Monthly Archives: March 2008

Easily switching between configuration files with MSBuild

A couple of days ago i wrote about Easily switching between App.Config files with MSBuild. Christophe Gijbels, a fellow compuwarrior, pointed out that developers usually need to copy more than a single App.Config file… I would propose to add a Folder for each Customer that contains all the specific configuration files. Eg:

screenshot of solution explorer with proposed folder structures

Now i have to configure MSBuild so that the right files are copied into the OutDir:

<!-- Define the CustomerPath depending on the choosen Configuration -->
<propertyGroup  Condition=" $(Configuration) == 'Customer1 Debug' ">
 <customerPath>Customer1</customerPath>
</propertyGroup>
<propertyGroup  Condition=" $(Configuration) == 'Customer2 Debug' ">
 <customerPath>Customer2</customerPath>
</propertyGroup>

<!-- Define AppConfig in the CustomerPath  -->
<propertyGroup>
 <appConfig>$(CustomerPath)\App.config</appConfig>
</propertyGroup>

<!-- Find all files in CustomerPath, excluding AppConfig -->
<itemGroup>
<customerFiles Include="$(CustomerPath)\*.*" Exclude="$(CustomerPath)\App.config" />
</itemGroup>

<target Name="AfterBuild">
<copy SourceFiles="@(CustomerFiles)" DestinationFolder="$(OutDir)" SkipUnchangedFiles="true"/>
</target>

Why doesn't Visual Studio display my MSBuild message texts?

In order to debug an MSBuild script i added a couple of <Message> tasks, but when i asked Visual Studio to Build i didn’t get to see the output… By default Visual Studio will use “Minimal” as verbosity level. You can change this via Tools -> Options -> Projects and Solutions -> Build and Run.

screenshot of configuration dialog in visual studio that allows the user to set the verbosity of msbuild

Easily switching between App.Config files with MSBuild

Imagine the following situation: One codebase, two customers with different Application Configuration files. How can we easily switch between the different configurations? By taking advantage of the Build Configurations functionality in Visual Studio we can easily switch between different configurations:

screenshot of the configuration manager in visual studio

A brute-force solution would be to add a Post-build Event that copies the desired App.Config file to the destination directory. In the Microsoft.Common.targets file (usually at C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727) around line 725 you can read how MSBuild chooses the App.Config that is copied to the destination folder:

Choose exactly one app.config to be the main app.config that is copied to the destination folder.

The search order is:

  1. Choose the value $(AppConfig) set in the main project.
  2. Choose @(None) App.Config in the same folder as the project.
  3. Choose @(Content) App.Config in the same folder as the project.
  4. Choose @(None) App.Config in any subfolder in the project.
  5. Choose @(Content) App.Config in any subfolder in the project.

Thus, simply setting $(AppConfig) should be enough to make sure that MSBuild chooses the appropriate App.Config file. Here is an example of a csproj section that defines $(AppConfig) as App.Customer1.Config or App.Customer2.Config depending on the choosen Build configuration:

<propertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug Customer1|AnyCPU' ">
 <debugSymbols>true</debugSymbols>
 <debugType>full</debugType>
 <optimize>false</optimize>
 <outputPath>bin\Debug\</outputPath>
 <defineConstants>DEBUG;TRACE</defineConstants>
 <errorReport>prompt</errorReport>
 <warningLevel>4</warningLevel>
 <appConfig>App.Customer1.Config</appConfig>
</propertyGroup>
<propertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug Customer2|AnyCPU' ">
 <debugSymbols>true</debugSymbols>
 <outputPath>bin\Debug Customer2\</outputPath>
 <defineConstants>DEBUG;TRACE</defineConstants>
 <debugType>full</debugType>
 <platformTarget>AnyCPU</platformTarget>
 <codeAnalysisUseTypeNameInSuppression>true</codeAnalysisUseTypeNameInSuppression>
 <codeAnalysisModuleSuppressionsFile>GlobalSuppressions.cs</codeAnalysisModuleSuppressionsFile>
 <errorReport>prompt</errorReport>
 <appConfig>App.Customer2.Config</appConfig>
  </propertyGroup>

Using Linq for statically-typed reflection

I discovered the TypedReflector
on Daniel Cazzulino’s Blog. In essence, a simplified version of the code looks like:

public static class Reflector
{
 public static PropertyInfo GetProperty<t, TRet>(Expression<func<t, TRet>> expression)
 {
  return GetMemberInfo(expression) as PropertyInfo;
 }

 public static FieldInfo GetField<t, TRet>(Expression<func<t, TRet>> expression)
 {
  return GetMemberInfo(expression) as FieldInfo;
 }

 public static MethodInfo GetMethod<t, TRet>(Expression<func<t, TRet>> expression)
 {
  return GetMemberInfo(expression) as MethodInfo;
 }

 public static MemberInfo GetMemberInfo(Expression memberInfoExpression)
 {
  Expression lambdaBodyExpression = ((LambdaExpression)memberInfoExpression).Body;
  switch (lambdaBodyExpression.NodeType)
  {
   case ExpressionType.MemberAccess:
    return ((MemberExpression)lambdaBodyExpression).Member;
   case ExpressionType.Call:
    return ((MethodCallExpression)lambdaBodyExpression).Method;
   default:
    throw new ArgumentException("Unsupported NodeType");
  }
 }
}

This class allows me to write the following:

PropertyInfo namePropertyInfo = Reflector.GetProperty<person, string>(p => p.Surname);

Not only can i be sure that the lambda (and thus the namePropertyInfo.Invoke) will always return a string, i can also use it to avoid ‘hardcoded’ propertynames:

//const string SurnameProperty = "Surname";
//comboBox1.DisplayMember = SurnameProperty;
comboBox1.DisplayMember = Reflector.GetProperty<person, string>(p => p.Surname).Name;

Heroes happened {Here}

I’m back from Heroes Happen Here. Even with a fullhouse this convention was well organized and evertyhing went pretty smooth (In my experience that is true for all events organised by Microsoft). One suggestion though: Reduce the sugar buffet (although the cake and muffins are very tasty) and add some healthy fruit ;)

I’m glad to notice, despite the fact that the main reason seems to be SEO, web developers are encouraged to develop websites that work without JavaScript and that they add it afterwards as a real usability enhancement.

Using System.DirectoryServices.AccountManagement to find the members of an AD group

A while ago i posted some code that demonstrated how to find the members of an AD group. If you’re using the brandnew .Net 3.5 framework you can take advantage of the System.DirectoryServices.AccountManagement library which is an abstraction for AD (DS, LDS) and SAM accounts. Using this new library my method can be simplified:

private static IEnumerable<string> FindUsernames(string groupname)
{
 PrincipalContext principalContext = new PrincipalContext(ContextType.Domain, "mydomain");
 GroupPrincipal groupPrincipal = GroupPrincipal.FindByIdentity(principalContext, groupname);

 foreach (Principal principal in groupPrincipal.Members)
 {
  yield return principal.DistinguishedName;
 }
}

If you’re looking for more information i would recommend that you read Managing Directory Security Principals in the .NET Framework 3.5.

Exploring alternative input: ActiveHome

A while ago i bought Media Centerkit for an euro or two. I wouldn’t recommend the product because it comes with crappy software. Anyway, i was only interested in playing with the hardware (RF Remote and USB Receiver) so i downloaded the ActiveHome Professional SDK. Once you install this you can add a reference to “ActiveHomeScript 1.0 Type Library” under the COM tab in Visual Studio. I wrote a little library so that i can consume the ActiveHomeClass.RecvAction in a Type-safe way:

class diagram of activehome library

Here is some sample code that demonstrates how you can use the Notifier to receive Notifications:

// register our eventhandler and tell the notifier to start raising events
Notifier.Instance.NotificationReceived += this.Instance_NotificationReceived;
Notifier.Instance.Enable();

private void Instance_NotificationReceived(object sender, NotificationReceivedEventArgs e)
{
 // for more complex logic i would recommend that you apply a Filter pattern...
 RadioFrequencyNotification rfNotification = e.Notification as RadioFrequencyNotification;
 if (rfNotification.IsKeyPressed)
 {
  if (rfNotification.Command == RadioFrequencyCommand.Menu)
  {
   this.RaiseToolStripMenuItemClicked(this.MenuClicked, EventArgs.Empty);
  }
 }
}

As always feel free to download the library and sample application: ActiveHome.zip

Find the members of an AD group

Because i always seem to forget about the syntax of LDAP Search Filters (RFC 2254: The String Representation of LDAP Search Filters and Creating a Query Filter) i’m going to post a basic demo of DirectorySearcher that returns the members that are part of a given AD group:

private static void Main(string[] args)
{
 foreach (string member in FindUsernames("?CWBE-PS-.NetDev"))
 {
  Console.WriteLine(member);
 }

 Console.Write("{0}Press any key to continue...", Environment.NewLine);
 Console.ReadKey();
}

private static IEnumerable<string> FindUsernames(string groupname)
{
 string filter = "(&(&(objectCategory=Group)(objectClass=Group))(name={0}))";
 filter = string.Format(filter, groupname);

 DirectoryEntry directoryEntry = new DirectoryEntry();
 DirectorySearcher searcher = new DirectorySearcher(directoryEntry);
 searcher.SearchScope = SearchScope.Subtree;
 searcher.Filter = filter;

 DirectoryEntry groupEntry = searcher.FindOne().GetDirectoryEntry();
 PropertyValueCollection members = (PropertyValueCollection)groupEntry.Properties["member"];
 return ConvertAll<object, string>((object[])members.Value);
}

private static IEnumerable<to> ConvertAll<from, To>(IEnumerable<from> elements)
{
 Type toType = typeof(To);

 foreach (From element in elements)
 {
  yield return (To)Convert.ChangeType(element, toType);
 }
}