Configuration dependent references

When you are developing Windows Phone 7 applications, especially if you are using additional assemblies that you developed yourself, it might not be sufficient to just add a reference to those particular assemblies from inside Visual Studio 2010. For instance, take this scenario that is taken from a real Windows Phone application:

AddingReferences(1)

This application makes use of an assembly that contains lots of re-usable functionality around MVVM support, IsolatedStorage support for tombstoning purposes and a few goodies to test an application’s Trial mode support. The latter item is the one I want to talk about in more detail in this article.

On a side note: even though I partly re-invented the wheel, there is a very nice MVVM implementation available with great Windows Phone 7 support. Take a look at Galasoft’s MVVM Light, a great resource for developing ‘serious’ Windows Phone 7 applications.

If you are developing Windows Phone 7 applications, you are most likely aware of the fact that the IsTrial method of the LicenseInformation class always returns false when running your application locally from a development machine. In order to test your application’s behavior in trial mode, you probably end up with something like this:

  1. using Microsoft.Phone.Marketplace;
  2.  
  3. namespace DotNETForDevices.Tools.Controls
  4. {
  5.     public class RunningMode
  6.     {
  7.         public static bool CheckIsTrial()
  8.         {
  9. #if DEBUG_TRIAL
  10.             return true;
  11. #else
  12.             return new LicenseInformation().IsTrial();
  13. #endif
  14.         }
  15.     }
  16. }

By defining a conditional compilation symbol ‘DEBUG_TRIAL’, it is now possible to test the application as if it is running in trial mode. However, if you are lazy like me, you probably get tired of manually setting conditional compilation symbols. I am also afraid to forget undefining symbols like this one when I submit applications for verification, especially since the above code snippet lives in a separate  assembly. For me, it would be very helpful if I could create an additional configuration, that would allow me to build my entire solution for trial mode testing. Creating a new build configuration is very easy inside Visual Studio.

CreatingNewConfiguration

Inside this new configuration I can define my DEBUG_TRIAL conditional compilation symbol as well as additional symbols. Because I derived my new configuration from the existing Debug configuration, all other settings in my new configuration are copied from the existing Debug configuration. This is exactly what I want. Unfortunately though, even though I can define additional settings, at first sight it seems that Visual Studio 2010 does not help me to refer to other versions of assemblies that I add to my solution. In other words, I would really like to refer to a DebugTrial build of my additional DotNETForDevices.Tools.Controls assembly when I am building my application in the DebugTrial configuration. Of course I want Visual Studio to update to the Release configuration of all my own assemblies as well when I decide to build my solution in Release mode. If you take a look at the path to my referred assembly when I switch from Debug mode to DebugTrial or to Release mode, you will see that the referred assembly is still the original Debug assembly.

AddingReferences(2)

At first glance it seems that there is no way to be able to import my own assemblies with the same build configuration that I am using during the current build of my solution. There is a way to overcome this situation. As you might now, Visual Studio 2010 project files are XML based files, so it is possible to view them with a text editor and it is even possible to modify them. Of course you have to be very careful with modifying project files because it might lead to Visual Studio not being able to open your project any longer. If you want to modify your project files, make sure to always make a back-up of the original file.

  1. <ItemGroup>
  2.   <Reference Include="DotNETForDevices.Tools.Controls">
  3.     <HintPath>..\..\..\DotNETForDevices\Controls\Bin\Debug\DotNETForDevices.Tools.Controls.dll</HintPath>
  4.   </Reference>
  5.   <Reference Include="DotNETForDevices.Tools.Persistence">
  6.     <HintPath>..\..\..\DotNETForDevices\Persistence\Bin\Debug\DotNETForDevices.Tools.Persistence.dll</HintPath>
  7.   </Reference>
  8.   <Reference Include="Microsoft.Phone" />
  9.   <Reference Include="Microsoft.Phone.Interop" />
  10.   <Reference Include="System.Windows" />
  11.   <Reference Include="system" />
  12.   <Reference Include="System.Core" />
  13.   <Reference Include="System.Net" />
  14.   <Reference Include="System.Xml" />
  15. </ItemGroup>

Looking inside my Clicker.csproj file, it becomes clear that the paths to referred assemblies are defined in a configuration independent way. This is fine for all system assemblies, but less ideal for my own assemblies, especially since they might still be under development as well. If you take a further look inside the *.csproj file, you will see that there are configuration dependent definitions.

  1. <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
  2.   <DebugSymbols>true</DebugSymbols>
  3.   <DebugType>full</DebugType>
  4.   <Optimize>false</Optimize>
  5.   <OutputPath>Bin\Debug</OutputPath>
  6.   <DefineConstants>DEBUG;TRACE;SILVERLIGHT;WINDOWS_PHONE</DefineConstants>
  7.   <NoStdLib>true</NoStdLib>
  8.   <NoConfig>true</NoConfig>
  9.   <ErrorReport>prompt</ErrorReport>
  10.   <WarningLevel>4</WarningLevel>
  11. </PropertyGroup>
  12. <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
  13.   <DebugType>pdbonly</DebugType>
  14.   <Optimize>true</Optimize>
  15.   <OutputPath>Bin\Release</OutputPath>
  16.   <DefineConstants>TRACE;SILVERLIGHT;WINDOWS_PHONE</DefineConstants>
  17.   <NoStdLib>true</NoStdLib>
  18.   <NoConfig>true</NoConfig>
  19.   <ErrorReport>prompt</ErrorReport>
  20.   <WarningLevel>4</WarningLevel>
  21. </PropertyGroup>

It seems that conditions can be defined very easy inside project files. If I could do something similar for paths to assemblies that I have added as references, I could add assemblies with the same build configuration as my current solution has. This guarantees me building against the right configuration of my own additional assemblies. So this is the final solution I came up with, indeed modifying the project file manually:

  1. <ItemGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
  2.   <Reference Include="DotNETForDevices.Tools.Persistence">
  3.     <HintPath>..\..\DotNETForDevices\Persistence\Bin\Debug\DotNETForDevices.Tools.Persistence.dll</HintPath>
  4.   </Reference>
  5.   <Reference Include="DotNETForDevices.Tools.Controls">
  6.     <HintPath>..\..\..\DotNETForDevices\Controls\Bin\Debug\DotNETForDevices.Tools.Controls.dll</HintPath>
  7.   </Reference>
  8. </ItemGroup>
  9. <ItemGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
  10.   <Reference Include="DotNETForDevices.Tools.Controls">
  11.     <HintPath>..\..\DotNETForDevices\Controls\Bin\Release\DotNETForDevices.Tools.Controls.dll</HintPath>
  12.   </Reference>
  13.   <Reference Include="DotNETForDevices.Tools.Persistence">
  14.     <HintPath>..\..\DotNETForDevices\Persistence\Bin\Release\DotNETForDevices.Tools.Persistence.dll</HintPath>
  15.   </Reference>
  16. </ItemGroup>
  17. <ItemGroup Condition="'$(Configuration)|$(Platform)' == 'DebugTrial|AnyCPU'">
  18.   <Reference Include="DotNETForDevices.Tools.Controls">
  19.     <HintPath>..\..\DotNETForDevices\Controls\Bin\DebugTrial\DotNETForDevices.Tools.Controls.dll</HintPath>
  20.   </Reference>
  21.   <Reference Include="DotNETForDevices.Tools.Persistence">
  22.     <HintPath>..\..\DotNETForDevices\Persistence\Bin\DebugTrial\DotNETForDevices.Tools.Persistence.dll</HintPath>
  23.   </Reference>
  24. </ItemGroup>

Changing to another build configuration now also results in referring to assemblies that correspond with that particular build configuration.

AddingReferences(3)

One very important thing to keep in mind though is that you need to manually modify the project file each time you add references to additional assemblies that you own and that you want to be build configuration aware. Other than that, I have not seen any issues by extending project files for this particular purpose. However, things might of course change with future versions of Visual Studio.

Advertisements
Both comments and trackbacks are currently closed.
%d bloggers like this: