GAS05: Tuning the C# projects#

[This is episode 5 of the Guidance Automation Series]

Last time, we left off with two empty projects that had a project reference between them. If you're still not too thrilled by all that, let's take it one step further: we'll add binary references to Enterprise Library and make sure that the project output is always copied to the Enterprise Library Configuration Tool directory (otherwise, the application block won't show up in the configuration tool). The first one involves knowing where to find those references, the second one involves executing a post-build command that copies the project output to the proper location.

Adding Binary References

Adding a binary reference in itself is pretty straight-forward. The project references are stored in the C# project file (which is an MSBuild file) and can therefore easily be added in the project's template. The only minor difficulty is that we need to provide the hint-path, i.e. the physical location where the assemblies can be found.

In this case, we'll be adding references to Enterprise Library assemblies, so we need to know the directory where Enterprise Library was installed. By default, this is in C:\Program Files\Microsoft Enterprise Library January 2006\bin, but it could have been installed elsewhere so we better verify this with the user. The easiest way, of course, is to make this a recipe argument, just like with the application block's name and namespace:

<Argument Name="EnterpriseLibraryPath" Required="true">
  <ValueProvider Type="Evaluator" Expression="C:\Program Files\Microsoft Enterprise Library January 2006\bin" />
</Argument>

Notice that we're using the ExpressionEvaluatorValueProvider again, but this time without a complex expression. Used in this way, it just sets a default value for the argument that can be modified by the user later on. If we now want to add a binary reference to the Microsoft.Practices.EnterpriseLibrary.Common.dll assembly, for example, we can just add the following lines to the itemgroup containing the references:

<Reference Include="Microsoft.Practices.EnterpriseLibrary.Common, Version=2.0.0.0, Culture=neutral, PublicKeyToken=null, processorArchitecture=MSIL">
  <SpecificVersion>False</SpecificVersion>
  <HintPath>$EnterpriseLibraryPath$\Microsoft.Practices.EnterpriseLibrary.Common.dll</HintPath>
</Reference>

Notice that the $EnterpriseLibraryPath$ parameter will automatically be replaced by the directory that the user chose in the wizard. So finally, the wizard's page definition will also need to include the new field:

<Field ValueName="EnterpriseLibraryPath" Label="Enterprise Library Path">
  <Editor Type="System.Windows.Forms.Design.FolderNameEditor, System.Design, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"/>
</Field>

This time, we're also providing an editor that allows the user to select the directory more easily using a folder browser window.

Adding A Post-Build Command

Now that we've referenced Enterprise Library, it's also a good time to make sure that the project output is always copied to the Enterprise Library directory. Otherwise, the application block is quite unuseable. The easiest way to do this is to add a post-build command to both projects that simply copy the project's assemblies to the EnterpriseLibraryPath the user has already chosen. Just like with the binary references, this is just a matter of modifying the MSBuild project file to include a new property group as such:

<PropertyGroup>
  <PostBuildEvent>$PostBuildCommand$</PostBuildEvent>
</PropertyGroup>

Creating the post-build command itself is a little trickier: it depends on the EnterpriseLibraryPath argument, and needs to build a more complex string based on that argument's value. The post-build command itself (as defined in Visual Studio) is simply:

COPY /Y $(TargetPath) "<Enterprise Library Path>"

Where we need to replace <Enterprise Library Path> with the value of the EnterpriseLibraryPath argument. So, how can we provide this value to the $PostBuildCommand$ argument? By building our own Value Provider, of course.

We start off by defining the argument itself:

<Argument Name="PostBuildCommand">
  <ValueProvider Type="JelleDruyts.EnterpriseLibraryGuidance.ValueProviders.PostBuildCommandValueProvider, JelleDruyts.EnterpriseLibraryGuidance"
                 EnterpriseLibraryPathArgument="EnterpriseLibraryPath">
    <MonitorArgument Name="EnterpriseLibraryPath" />
  </ValueProvider>
</Argument>

Notice that the value provider is now of our own type, namely the PostBuildCommandValueProvider we'll be building, and that it monitors the EnterpriseLibraryPath argument (since it depends on it). Furthermore, since the value provider needs access to the value of the EnterpriseLibraryPath argument, we also need to specify that argument's name, which is done through a custom EnterpriseLibraryPathArgument attribute on the ValueProvider node.

The code for the Value Provider isn't all that difficult, either. It's a class that inherits from the ValueProvider base class and that also implements the IAttributesConfigurable interface to support that custom EnterpriseLibraryPathArgument attribute. It can then override the OnArgumentChanged method that gets called when a monitored argument has changed, and re-generate the post-build command as such:

public override bool OnArgumentChanged(string changedArgumentName, object changedArgumentValue, object currentValue, out object newValue)
{
    // Get the name of the argument that defines the EnterpriseLibraryPath.
    string enterpriseLibraryPathArgumentName = m_Attributes[EnterpriseLibraryPathArgumentAttribute];
    
    // Get the dictionary that contains the recipe arguments.
    IDictionaryService dictionary = this.GetService<IDictionaryService>(true);

    // Get the current value of the EnterpriseLibraryPath argument.
    string enterpriseLibraryPath = (string)dictionary.GetValue(enterpriseLibraryPathArgumentName);

    // Create the post-build command.
    newValue = string.Format("COPY /Y \"$(TargetPath)\" \"{0}\"", enterpriseLibraryPath);
    return true;
}

Now we have an argument containing the post-build command that automatically contains the proper directory based on the Enterprise Library directory the user has chosen in the wizard dialog:

Where Are We

We've seen how to add binary references to the C# projects by modifying the MSBuild files and gathering user input through the wizard. We've also built a custom Value Provider that depends on the value of another argument, and used that as a post-build command. Next time, we'll see how we can generate some classes so that the application block can already be added to the Enterprise Library Configuration Tool.

Download the source code for the current state of the Guidance Package.

Sunday, February 18, 2007 6:15:29 AM (Romance Standard Time, UTC+01:00)
bbpodvhg http://bheaztmv.com lbcpihhp zujhoiym [URL=http://mndbnojv.com]fiyzcacg[/URL] <a href="http://uiqpqmib.com">nxujlihu</a>
Comments are closed.
All content © 2008, Jelle Druyts
On this page

Recent Photos
www.flickr.com
This is a Flickr badge showing public photos from Jelle Druyts. Make your own badge here.
Advertising
Top Picks
Statistics
Total Posts: 345
This Year: 8
This Month: 0
This Week: 0
Comments: 523
Archives
Sitemap
Disclaimer
This is my personal website, not my boss', not my mother's, and certainly not the pope's. My personal opinions may be irrelevant, inaccurate, boring or even plain wrong, I'm sorry if that makes you feel uncomfortable. But then again, you don't have to read them, I just hope you'll find something interesting here now and then. I'll certainly do my best. But if you don't like it, go read the pope's blog. I'm sure it's fascinating.

Powered by:
newtelligence dasBlog 2.0.7226.0

Sign In