Read Config Value in MSBuild Task - configuration

Is there a way to read a System.Config connection string in an MSBuild task?
Basically I have my connection string setup in a config file
<add name="MyApp.MyConnectionString" connectionString="..." />
And I would like to reference it in an MSBuild task like so ...
<Target Name="Migrate" DependsOnTargets="Build">
...
<Migrate Connectionstring="$(MyApp.MyConnectionString)" ... />
</Target>

There's an XMLRead task in the MSBuild Community Tasks Project, that uses xpath to pull out a value.
<XmlRead
XPath="/add/#connectionString"
XmlFileName="app.config">
<Output TaskParameter="Value" PropertyName="MyConnectionString" />
</XmlRead>
<Message Text="MyConnectionString: $(MyConnectionString)"/>
(note: totally untested)

Related

ant task to run JUnit tests from a jar (but only files that have tests!)

We're using JUnit inside a custom framework to test an applications behaviour. We're not actually doing unit testing, just leveraging JUnit.
I've created an ant task to run all the tests in the jar file, but unfortunately it's trying to run everything as a JUnit test. Since the jar file contains things besides just the tests (it contains the supporting framework) this is a problem.
Is there a way to make the junit task only run things marked as tests (we use #Test)?
Currently my ant task looks like this:
<target name="test">
<junit printsummary="yes" haltonfailure="no">
<classpath refid="library.third-party.classpath" />
<classpath>
<pathelement location="${basedir}/build/jar/fidTester.jar" />
</classpath>
<formatter type="plain" />
<formatter type="xml" />
<batchtest fork="no" todir="${basedir}/reports">
<zipfileset src="${basedir}/build/jar/fidTester.jar" includes="**/tests/**/*.class" />
</batchtest>
</junit>
</target>
From the Ant JUnit Task documentation:
skipNonTests
Do not pass any classes that do not contain JUnit tests to the test
runner. This prevents non tests from appearing as test errors in test
results. Tests are identified by looking for the #Test annotation on
any methods in concrete classes that don't extend
junit.framework.TestCase, or for public/protected methods with names
starting with test in concrete classes that extend
junit.framework.TestCase. Classes marked with the JUnit 4
org.junit.runner.RunWith or org.junit.runner.Suite.SuiteClasses
annotations are also passed to JUnit for execution, as is any class
with a public/protected no-argument suite() method.

Propagate=False in BIML

I'm using BIML to create my package.
There is a sequence container where I want to set the system variable Propagate to False.
I cannot find the method in BIML to set the system variable for Propagate.
Propagate is a System scoped variable that only exists within Event Handlers.
The following Biml creates an SSIS Package with an OnError event handler that has an empty Sequence Container
The Event itself redefines the System::Propagate variable to have a value of false instead of the default value of true
<Biml xmlns="http://schemas.varigence.com/biml.xsd">
<Packages>
<Package Name="so_38121956">
<Events>
<Event EventType="OnError" Name="OnError">
<Variables>
<Variable DataType="Boolean" Name="Propagate" Namespace="System">false</Variable>
</Variables>
<Tasks>
<Container Name="SEQC Propagate no more">
</Container>
</Tasks>
</Event>
</Events>
</Package>
</Packages>
</Biml>
Try using BIML Online.
http://bimlonline.com/
Here you can upload an existing SSIS package with propagate set and the browser based application will reverse engineer it for you to give you the BIML.
Its handy if you know how to do something in SSIS, but not sure of the BIML equivalent.
Officially its still in Beta, but works well.

how to add configuration for log4net (or any other 3rd party library) in ASP.NET 5.0

I was reading Scott Gu's blog on ASP.NET 5.0 features and one of the new feature mentioned in the blog is to use json file as configuration and elimination of Web.config file.
I have few questions around that feature.
Assume I have following log4net configuration which was previously added to Web.Config in previous version of ASP.NET
Config file
<section name="log4net" type="log4net.Config.Log4NetConfigurationSectionHandler, log4net" />
<log4net debug="true">
<appender name="RollingLogFileAppender" type="log4net.Appender.RollingFileAppender">
<file value="C:\\TestProj\\TestLog.txt" />
<appendToFile value="true" />
<rollingStyle value="Size" />
<maxSizeRollBackups value="10" />
<maximumFileSize value="10MB" />
<staticLogFileName value="true" />
<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="%-5p %d %5rms %-22.22c{1} %-18.18M - %m%n" />
</layout>
</appender>
<root>
<level value="DEBUG" />
<appender-ref ref="RollingLogFileAppender" />
</root>
</log4net>
How would one add sections in config.json ?
How would one convert above xml and add it to config.json?
Does 3rd Party library ( In my example log4net ) or users of the library have to add some type of custom conversion api to support json based configuration, in order to take advantage of new configuration feature provided in ASP.NET 5.0?
Recently I had the same problem with log4net. I managed to do it working as following:
Create log4net.xml file containing the configuration section for log4net
<?xml version="1.0" encoding="utf-8" ?>
<log4net>
...
</log4net>
You can put the file in the project root folder.
And in the Startup.Startup() method you can configure the log4net providing the xml as a configuration:
public Startup(IApplicationEnvironment appEnv)
{
// ...
XmlConfigurator.Configure(new FileInfo(Path.Combine(appEnv.ApplicationBasePath, "log4net.xml")));
}
I hope this helps.
Current versions of log4net don't support Json projects, so the config needs to be in a separate xml file.

Azure role configuration management

I don't see how Windows Azure lets you vary the configuration of an application when you have no choice but to hold configuration settings in web.config (or app.config).
For example...
Quite often projects will make use of a 3rd party library that makes heavy use of web.config. The use of web.config may involve connection strings, app settings or custom configuration sections. A good example of this is ELMAH. A web.config file for ELMAH might look like the following:
<configuration>
<configSections>
<sectionGroup name="elmah">
<section name="security" requirePermission="false" type="Elmah.SecuritySectionHandler, Elmah" />
<section name="errorLog" requirePermission="false" type="Elmah.ErrorLogSectionHandler, Elmah" />
</sectionGroup>
</configSections>
<connectionStrings>
<add
name="MyElmahDatabase"
providerName="System.Data.SqlClient"
connectionString="Server=tcp:myServer.database.windows.net,1433;Database=myDB;User ID=user#myServer;Password=password;Trusted_Connection=False;Encrypt=True;Connection Timeout=30" />
</connectionStrings>
<elmah>
<security allowRemoteAccess="1" />
<errorLog type="Elmah.SqlErrorLog, Elmah" connectionStringName="MyElmahDatabase" />
</elmah>
</configuration>
There are a couple of problems here:
There is no way for me to update or vary whether remote access is enabled between Service Configurations.
There is no way for me to update or vary the ELMAH connection string between Service Configurations.
This is because the web.config is packaged as is into the .cspkg file and ELMAH will not look at the Service Configuration settings (which are the only way I can vary configuration settings between Service Configurations).
I can think of many other examples where this is a problem...
Any data access frameworks that look directly at the connection strings section.
Any custom configuration settings I need to create.
...to name just two.
Am I missing something or is this a significant gap in the configuration management offered by Windows Azure?
EDIT
From the answer and comments below, it looks like this is something that is not well supported. I think that managing multiple solution build configurations to support different configuration profiles is a very weak solution. I should not have to rebuild the solution for each configuration profile I need (there will likely be quite a few). Compilation is not equal to configuration.
I was wondering if there was a way to modify the .cspkg file as it is just a zip file. According to this documentation you can on Linux.
I've looked at the manifest in the .cspkg file and it looks like this:
<PackageManifest version="2">
<Encryption keytype="1" />
<Contents hashtype="1">
<Item name="MyApp.Web.UI_<GUID>.cssx" hash="AED69299C5F89E060876BC16BD3D6DE5130F6E62FFD2B752BAF293435339B7E2" uri="/MyApp.Web.UI_<GUID>.cssx" />
<Item name="MyApp.Web.Services_<GUID>.cssx" hash="7AC81AFF642E4345173C8470C32A41118A4E3CFD4185B82D0ADA44B71057192D" uri="/MyApp.Web.Services_<GUID>.cssx" />
<Item name="SMPackage_<GUID>.csmx" hash="B5E6B83B62AF64C7C11CAC1A394ABBF15D7DB7667A773C5284CE5BE95C5834E9" uri="/SMPackage_<GUID>.csmx" />
<Item name="SDPackage_<GUID>.csdx" hash="F34B7C02A551D82BAD96881E2DA9447D0014D49B47CCB3840475BDC575234A7D" uri="/SDPackage_<GUID>.csdx" />
<Item name="NamedStreamPackage_<GUID>.csnsx" hash="FA2B5829FF5D9B2D69DCDDB0E5BDEE6B8B0BC09FFBF37DAEEE41CF3F3F4D0132" uri="/NamedStreamPackage_<GUID>.csnsx" />
</Contents>
<NamedStreams>
<Stream name="RequiredFeatures/MyApp.Web.Services/1.0" />
<Stream name="RequiredFeatures/MyApp.Web.UI/1.0" />
<Stream name="SupportData/MyApp.Web.Services/1.0" />
<Stream name="SupportData/MyApp.Web.UI/1.0" />
</NamedStreams>
</PackageManifest>
Unfortunately, if I re-compute the hash of the unchanged "MyApp.Web.UI_.cssx" file, my hash is different from the one in the manifest.
Hash from manifest: AED69299C5F89E060876BC16BD3D6DE5130F6E62FFD2B752BAF293435339B7E2
My calculated hash: E3B0C44298FC1C149AFBF4C8996FB92427AE41E4649B934CA495991B7852B855
Note that I have not yet changed the file, so the hash should be the same.
This suggests I'm calculating it wrong. My method was as follows:
class Program
{
static void Main(string[] args)
{
using (FileStream fs = new FileStream(args[0], FileMode.Open))
{
ComputeHash(new SHA256Managed(), fs);
}
}
private static void ComputeHash(HashAlgorithm hashAlgorithm, Stream stream)
{
byte[] hash = hashAlgorithm.ComputeHash(stream);
string hashString = BitConverter.ToString(hash);
Console.WriteLine(hashString.Replace("-", string.Empty));
Console.WriteLine();
}
}
The documentation link above, suggests it is straightforward to re-calculate the hash (on Linux anyway).
Does anyone know how to re-compute the hashes?
Passing a Stream to ComputeHash() ends up with a different hash as compared to using the byte[] overload. I don't know why.
Try something like:
private static void ComputeHash(HashAlgorithm hashAlgorithm, Stream stream)
{
BinaryReader reader = new BinaryReader(stream)
byte[] hash = hashAlgorithm.ComputeHash( reader.ReadBytes( (int)stream.Length ) );
string hashString = BitConverter.ToString(hash);
Console.WriteLine(hashString.Replace("-", string.Empty));
Console.WriteLine();
}
This will give you the hash you're after.
As you've probably already discovered, on linux you can get the digest with
openssl dgst -sha256 /path/to/file
I you have items in your web.config that you want to change depending on how it's being built, there is a solution that is outside of Azure that you can use. You can use Web.config transforms. These transforms are tied to your build configuration not your service configuration, but your service configurations a likely closely tied to your build configurations anyway (...Local.csfg -> Debug, ...Cloud.csfg -> Release). If the default build configurations don't work for you, just create the ones you need.
If you want to use different service definitions per service configuration, then it's not supported by the UI, but you can mess around with the build process to make it work

Windows Azure: how do I expose a configuration setting as an environment variable?

I tried adding this to my ServiceDefinition.csdef file:
<WorkerRole ...><Runtime><Environment>
<Variable name="AZURE_STORAGE_ACCOUNT">
<RoleInstanceValue xpath="/RoleEnvironment/CurrentInstance/ConfigurationSettings/ConfigurationSetting[#name='AZURE_STORAGE_ACCOUNT']/#value" />
</Variable>
</Environment></Runtime></WorkerRole>
And I set the configuration setting in my ServiceConfiguration.Cloud.cscfg file:
<Role name="WorkerRole">
<ConfigurationSettings>
<Setting name="AZURE_STORAGE_ACCOUNT" value="<secret stuff>" />
</ConfigurationSettings>
</Role>
But I got the following error when I run cspack:
CloudServices091 : The '/RoleEnvironment/CurrentInstance/Configur
ationSettings/ConfigurationSetting[#name='AZURE_STORAGE_ACCOUNT']/#value' is an
invalid xpath expression.
Are you missing the declaration of that setting? I don't see the appropriate element in your .csdef, something like <ConfigurationSettings><Setting name="AZURE_STORAGE_ACCOUNT"/></ConfigurationSettings>. You need one of those in your .csdef, and then you still want the one in your .cscfg that includes the value.
If you're using Visual Studio, it should edit both files for you if you use its property view. (Just double click the role and then click around to get to config settings and add a new one.)
The configuration seems to be correct. It would be better if you can make sure you’re using the latest SDK. The xPath feature is available in Windows Azure SDK 1.5 and later.
Best Regards,
Ming Xu.
I have tried out different options mentioned at blogs, like including the setting in both .cscfg and .csdef. But, it doesn't seem to work.
Also, other Xpath queries like
<RoleInstanceValue xpath="/RoleEnvironment/CurrentInstance/#id"/>
work correctly.
Finally, I figured out that the variable name used was different:
In cscfg I had :
<Setting name="WFFEPeriodicRestartTime" value="168:00:00" />
in csdef I had :
<ConfigurationSettings>
<Setting name="PeriodicRestartTime" />
</ConfigurationSettings>
....
....
<Variable name="PeriodicRestartTime">
<RoleInstanceValue xpath="/RoleEnvironment/CurrentInstance/ConfigurationSettings/ConfigurationSetting[#name='WFFEPeriodicRestartTime']/#value" />
</Variable>
Changed csdef to :
<ConfigurationSettings>
<Setting name="WFFEPeriodicRestartTime" />
</ConfigurationSettings>
....
....
<Variable name="WFFEPeriodicRestartTime">
<RoleInstanceValue xpath="/RoleEnvironment/CurrentInstance/ConfigurationSettings/ConfigurationSetting[#name='WFFEPeriodicRestartTime']/#value" />
</Variable>
It seems to work correctly now
Ran into the same issue here as I was trying to read config values via the example provided here: https://learn.microsoft.com/en-us/azure/cloud-services/cloud-services-role-config-xpath#config-setting - lost quite a few brain cells in the process!
The trick is, this doesnt mean that you read config values from your web.config (which is how I mis read it), but from the Settings in the cscfg file.
With cloud services you have 1 csdef file that applies to all your cloud service convigurations, but then a cscfg for each environment. In my scenario I have cscfg's for DEV, QA, Prod, and I needed to set a different variable depending on the environment.
So for the OP's question, when you try to perform the "RoleEnvironment/CurrentInstance/ConfigurationSettings.." statement and get the invalid xpath value, its essentially saying "hey I cant find this value"
How to make the magic happen:
Your csdef file needs the following:
<ConfigurationSettings>
<Setting name="AZURE_STORAGE_ACCOUNT" />
</ConfigurationSettings>
Your cscfg then needs:
<ConfigurationSettings>
<Setting name="AZURE_STORAGE_ACCOUNT" value="Some Secret Value" />
</ConfigurationSettings>
For my purposes I was trying to use this value in a startup.cmd file, so I was able to add the following to my csdef startup task
<Startup>
<Task commandLine="Startup.cmd" executionContext="elevated" taskType="simple">
<Environment>
<Variable name="AZURE_STORAGE_ACCOUNT">
<RoleInstanceValue xpath="/RoleEnvironment/CurrentInstance/ConfigurationSettings/ConfigurationSetting[#name='AZURE_STORAGE_ACCOUNT']/#value" />
</Variable>
</Environment>
</Task>
</Startup>
Then in my startup.cmd you can just reference the value as %%AZURE_STORAGE_ACCOUNT%%