Tuesday, November 18, 2008
#
In a recent post, Deepak describes how to generate enums using Linq to Sql and SqlMetal.
1. Generate dbml using SqlMetal.
2. Find reference columns in the dbml that will be used as enums in code. Change their type to the enum name.
3. Generate code using SqlMetal.
I find this pretty interesting, but there would need to be some kind of conventions or configuration to denote which tables will be used as enumerations in the code. I think the way to tackle this is to create a custom msbuild task that will replace the enums for you based on either an item group or an xml property. This whole thing could be wrapped up in msbuild and applied in a separate proj file or in the AfterBuild or BeforeBuild target of one of the projects.
Wednesday, November 05, 2008
#
Microsoft has released Enterprise Library 4.1. It is a service release and includes the following:
-
Unity interception mechanism and integration of the Policy Injection Application Block with the Unity Application Block
-
Added support for generics in the Unity Application Block
-
Added support for arrays in the Unity Application Block
-
Performance improvements
-
Usability improvements to the configuration tool
-
Visual Studio 2008 Service Pack 1 support
-
Bug fixes
Monday, October 27, 2008
#
I just learned that Windows Azure has been announced, presumably at PDC 2008. It's brand new, so visit the site to learn more and download the ctp.
Windows Azure is a cloud services operating system that serves as the development, service hosting, and service management environment for the Azure Services Platform. Windows Azure provides developers with on-demand compute and storage to host and manage web applications on the internet through Microsoft data centers.
Between this and Live Mesh, I feel as though we're in the middle of a huge paradigm shift.
Thursday, October 09, 2008
#
I've seen a few questions in the forums where the poster wants the build to fail for certain projects but not others. This can be accomplished through metadata and item batching.
Here is the item group that defines the projects.
<ItemGroup>
<Projects Include="$(MSBuildProjectDirectory)\DataAccess\DataAccess.csproj">
<Group>Build</Group>
<Title>Data Access</Title>
<Description>Data Access Layer</Description>
<ContinueOnError>False</ContinueOnError>
</Projects>
<Projects Include="$(MSBuildProjectDirectory)\Business\Business.csproj">
<Group>Build</Group>
<Title>Business</Title>
<Description>Business Layer</Description>
<ContinueOnError>False</ContinueOnError>
</Projects>
<Projects Include="$(MSBuildProjectDirectory)\NonCritical\NonCritical.csproj">
<Group>Build</Group>
<Title>NonCritical</Title>
<Description>A Non Critical Project</Description>
<ContinueOnError>True</ContinueOnError>
</Projects>
<Projects Include="$(MSBuildProjectDirectory)\Presentation\Presentation.csproj">
<Group>Build</Group>
<Title>Presentation</Title>
<Description>Presentation Layer</Description>
<ContinueOnError>False</ContinueOnError>
</Projects>
</ItemGroup>
Here is the call to the MSBuild task.
<MSBuild Projects="@(Projects)" ContinueOnError="%(ContinueOnError)" />
Since ContinueOnError is defined as metadata for the Projects items, you can access it in a batching scenario by using the % symbol. When assigned to the ContinueOnError attribute, it evaluates the text contained within the metadata, in this case True or False. One side effect of this is that all of the ContinueOnError=False projects will be executed before the True projects.
I don't like this approach, because I consider a compilation failure a failed build. However, this should help you out if you're faced with a scenario where this functionality is required.
Wednesday, October 08, 2008
#
Mike Fourie has begun a project to combine two of the larger MSBuild task libraries. FreeToDev and SDC tasks have a lot of overlap, so I believe the MSBuild Extension Pack is a great endeavor to simplify the life of many of us build architects. However, I do have a gripe after reading the description on the project page.
It implements a TaskAction based design which improves usability and maintenance whilst reducing the code base, e.g. to start or stop a website, typically two task files would be created to perform each task, whereas the pack accomplishes this in a single task files using TaskAction=”Stop” and TaskAction=”Start”.
I feel that a "TaskAction based design" decreases cohesion. Each task should be like a method: the name describes what it does and the attributes are the parameters to do it. If you start coding tasks that change behavior, then you've effectively given the class (remember, tasks are classes) too much responsibility. If multiple tasks have similar responsibilities, the correct approach is to abstract. Create a base class with the common elements, encapsulate what varies, then implement that variation in the child classes which are represented in MSBuild as tasks.
In the example given on the project page, I would prefer to have <Website.Start ... /> and <Website.Stop ... /> than <Website TaskAction="Start" ... /> and <Website TaskAction="Stop" ... />
Lou Vega will be presenting at the Columbia Enterprise Developers Guild tonight. The topic is "A Closer Look at Windows Mobile – Using SMS and State & Notifications Broker." Systemtec is sponsoring the event and will be providing food from Moe's.
Visit the website for more information.
Tuesday, October 07, 2008
#
This is one that belongs on failblog. I happen to be using Visual Studio 2005 at work, so the prop snippet generates a private member variable to encapsulate in a property. In this case, I needed the property "Value". Guess what happens?
private string value;
public string Value
{
get { return value; }
set { value = value; }
}
Fail. The only thing that needs to be done to correct this is to qualify value in the setter.
set { this.value = value; }
There's no reason to make a better prop snippet now that it generates automatic properties in Visual Studio 2008. This problem merely amused me.
Monday, October 06, 2008
#
MSBuild files are loaded and parsed in order. This means that properties and items are in scope if they have been previously defined anywhere within the load chain. Here's an example.
Test.proj
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<HelloWorld>Hello World!</HelloWorld>
</PropertyGroup>
<ItemGroup>
<Files Include="*.*"/>
</ItemGroup>
<Import Project="Test.properties" />
<Target Name="Build">
<Message Text="$(GotHere)" />
<Message Text="$(FileList)" />
</Target>
</Project>
Test.properties
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<GotHere>Got here, $(HelloWorld)</GotHere>
<FileList>@(Files)</FileList>
</PropertyGroup>
</Project>
When you run MSBuild test.proj, you will receive the following output.
Got here, Hello World!
Test.proj;Test.properties
If you were to move the Import task above the property and item definitions, your results will be different as the HelloWorld property and the Files item collection have not been defined.
This concept is important if you are attempting to break a large build file into smaller files. There may be dependencies between common properties & items and conditional properties & items. Conditional properties and items can be refactored out of the primary script (encapsulate what varies) and still use the common properties and items as long as they are defined before the conditional file is imported.
Wednesday, October 01, 2008
#
What do you do when you are loading hundreds of objects and it's taking too long? When you instantiate the object in a vacuum, it runs very fast. However, you run a few tests and determine a collection on the object causes a bottleneck if a call to load the collection occurs many times in succession.
public class Customer
{
private List<Account> accounts = SlowLoadMethod();
public IList<Account> Accounts
{
get{ return accounts; }
}
...
}
If the property doesn't need to be accessed immediately upon instantiation, we can use a technique called lazy loading. This means the data isn't loaded into the member variable and the call to the slow method will not occur until the first time the property is accessed. This is easy to accomplish via a conditional check inside the property's get accessor.
public class Customer
{
private List<Account> accounts;
public IList<Account> Accounts
{
get
{
if (accounts == null)
{
accounts = SlowLoadMethod();
}
return accounts;
}
}
...
}
In this example, the accounts private member is null until the first time someone accesses the Accounts property. At that point, the accounts private member is assigned a value from the SlowLoadMethod. Subsequent accesses to the Accounts property skip this step and returns the field as usual.
Tuesday, September 30, 2008
#
You're writing a Customer class, and the Customer class contains a collection of Account objects. Because you want to add and remove accounts with ease, you implement this collection as a List<T>.
public class Customer
{
private List<Account> accounts = new List<Account>();
public List<Account> Accounts
{
get { return accounts; }
}
}
Life is good. Your tests iterate through the accounts, add new accounts, and remove accounts. However, when you run FxCop, it complains that you shouldn't expose generic lists.
Do not expose List<T> in object models. Use Collection<T>, ReadOnlyCollection<T> or KeyedCollection<K,V> instead. List<T> is meant to be used from implementation, not in object model API. List<T> is optimized for performance at the cost of long term versioning. For example, if you return List<T> to the client code, you will not ever be able to receive notifications when client code modifies the collection.
FxCop is correct in its assessment as it becomes more difficult to later add underlying functionality. But I feel that it leaves out an important point. You shouldn't expose too much about your implementation, and this relays to the world that Employee uses a List<T>. Consumers of the Customer class don't care that you've implemented List<T>, they only care about the interface. Expose the public property as the interface the consumer should be using. In this example, our consumers want to utilize the interface IList<T>. Refactoring this is pretty easy: modify the property to be IList<Account>.
public class Customer
{
private List<Account> accounts = new List<Account>();
public IList<Account> Accounts
{
get { return accounts; }
}
}
In other cases, the consumers may only want to iterate the collection without making modifications. In that situation, expose the list as IEnumerable<T>. The point is to take into account the interface that consumers want to utilize, then hide your implementation.
You shouldn't do it this way if the collection needs to be serialized. In that case, stick with one of the concrete classes such as Collection<T> like FxCop suggested.
Friday, September 26, 2008
#
The Expression Blend team announced the released of of Service Pack 1 for Expression Blend 2 today. Here are the details for this release.
This Service Pack provides you with all of the functionality you had with our earlier Expression Blend 2.5 June 2008 Preview. Besides allowing you to create new projects for WPF, Silverlight 1, and Silverlight 2 RC, we are also exposing new platform functionality like Font Embedding / Subsetting for Silverlight 2 projects.
You can download the service pack here.
Wednesday, September 24, 2008
#
There are scenarios where the situation calls for performing set operations on item collections. You may want to join them together, subtract one from another, or perform an inner join. I originally came up with the idea to demonstrate these from this forum question. These examples work in both MSBuild 2.0 and MSBuild 3.5. A 3.5 only version is included with the attachment to this article.
Set Up
Create an empty msbuild file. Add a default target that you will use to perform the set operations and display messages to show your results.
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<SetA Include="alpha;beta;gamma;delta"/>
<SetB Include="alpha;gamma;epsilon"/>
</ItemGroup>
<Target Name="Build">
</Target>
</Project>
Union All
Perhaps the easiest set operation is the Union All. This operation combines one collection with another, including duplicates. We only have to use the CreateItem including both sets. Add the following code inside your target to see this in action.
<CreateItem Include="@(SetA);@(SetB)" >
<Output TaskParameter="Include" ItemName="UnionAllSet"/>
</CreateItem>
<Message Text="Union All: @(UnionAllSet)"/>
Minus
The Minus operation works similar to the Union All operation. However, instead of including both sets, you include one set and exclude the other.
<CreateItem Include="@(SetA)" Exclude="@(SetB)" >
<Output TaskParameter="Include" ItemName="MinusSet"/>
</CreateItem>
<Message Text="Minus: @(MinusSet)"/>
Intersect
Intersect only takes items that are in both collections. It starts to get tricky with this operation and in fact was the catalyst for this article. I attempted to perform this one using conditions, but nothing seemed to work. I finally realized I would have to perform multiple operations to get the desired intersection: take the first set and exclude the minus set.
<CreateItem Include="@(SetA)" Exclude="@(MinusSet)" >
<Output TaskParameter="Include" ItemName="IntersectSet"/>
</CreateItem>
<Message Text="Intersect: @(IntersectSet)"/>
Union
The Union operation pulls elements from both item collections. This is very similar to Union All except that it does not include duplicates. To accomplish this, take the UnionAllSet and exclude IntersectSet. Since this removes the original and duplicate items, add IntersectSet back to the results.
<CreateItem Include="@(UnionAllSet)" Exclude="@(IntersectSet)" >
<Output TaskParameter="Include" ItemName="UnionSet"/>
</CreateItem>
<CreateItem Include="@(IntersectSet)" >
<Output TaskParameter="Include" ItemName="UnionSet"/>
</CreateItem>
<Message Text="Union: @(UnionSet)"/>
Conclusion
These are basic examples of doing set operations in MSBuild. Combined with batching and transforms, there isn't much standing in the way of defining your item collections how you wish.
Be sure to download the samples below. It includes an MSBuild 3.5 version using the new, cleaner ItemGroup syntax.
MSBuildSetOperations.zip (1.12 kb)
Tuesday, September 23, 2008
#
Gael Fraiteur reported differing behavior with the Exists condition in MSBuild 3.5, which has been verified to be a bug by Microsoft.
Here is the setup. Have one file import a file from a different folder. Have that imported file import another relative to that file's path. Add a condition to check if the file exists to the Import task.
File 1 (foo.proj):
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="..\Bar\bar.targets" />
<Target Name="Build">
<Message Text="$(FooBar)"/>
</Target>
</Project>
File 2 (bar.targets):
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="message.targets" Condition="Exists('message.targets')"/>
</Project>
File 3 (message.targets):
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<FooBar>Hello World!</FooBar>
</PropertyGroup>
</Project>
If you run C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\msbuild.exe foo.proj, "Hello World" will be displayed. If you run C:\WINDOWS\Microsoft.NET\Framework\v3.5\msbuild.exe foo.proj, the text will be empty and nothing will display.
You can use absolute paths to get around this relative pathing issue in Exists. However, in the case of imports, I recommend removing the condition. In most cases your build should fail if the script failed to import a file.
Saturday, September 20, 2008
#
Everything worked fine the last time I gave my MSBuild presentation. There were no changes to my files, so imagine my surprise when I load things up to practice today only to be met by failures.
"C:\Demos\Introducing MSBuild\AccountManager\example01.proj" (default target) (1) -> "C:\Demos\Introducing MSBuild\AccountManager\AccountManager.sln" (default target) (2) -> (ValidateSolutionConfiguration target) -> C:\Demos\Introducing MSBuild\AccountManager\AccountManager.sln.cache(81,5): error MSB4126: The specified solution configuration "Debug|MCD" is invalid. Please specify a valid solution configuration using the Configuration and Platform properties (e.g. MSBuild.exe Solution.sln /p:Configuration=Debug /p:Platform="Any CPU") or leave those properties blank to use the default solution configuration.
The problem indicated by this error message is that the solution configuration is Debug|MCD. More specifically, this means that the platform equals MCD. I looked through all the solution files to find this mysterious MCD platform. I found nothing anywhere. Then I set the property through the msbuild commandline, and everything worked perfectly. The perplexing thing was that I set it to default in the project file if it was empty.
That was the key. It wasn't empty by the time the project file got ahold of it.
Environment variables are passed into MSBuild as properties. Keep this in mind if you're trying to figure out while your builds fail from certain machines due to errors being thrown from invalid property values. In fact, my problem came about because I purchased a new laptop from Gateway. I'm not sure what software they installed that set the environment variable, but it has the potential to wreak havoc on your build process if transitioning to a new build server.
Tuesday, September 16, 2008
#
I will be presenting at New England Code Camp 10: Dev InTENsity! this weekend. Chris Bowen has posted the schedule on his blog.
Here are my presentations:
Sunday, September 21st 9:00am, Room MPR B, New Features in C# 3.0
Sunday, September 21st 12:30PM, Room MPR B, Introducing MSBuild