Wednesday 26 November 2008

Microsoft® Visual Studio Team System 2008 Database Edition now supports SQL Server 2008

Microsoft has posted the RTM of the update to Microsoft® Visual Studio Team System 2008 Database Edition to enable support for SQL Server 2008. One of the main features is a SQL Server 2008 Projects type in Visual Studio:

http://www.microsoft.com/downloads/details.aspx?familyid=bb3ad767-5f69-4db9-b1c9-8f55759846ed&displaylang=en

Remember, "Datadude" is free for people with a license for Microsoft® Visual Studio Team System 2008 Developer Edition:

http://callumhibbert.blogspot.com/2008/10/visual-studio-team-system-developer.html

Tuesday 25 November 2008

Windows Server 2008 Core will support managed code

I posted a while ago the surprisong news that Windows Server 2008 Core would not support managed code: http://callumhibbert.blogspot.com/2008/04/windows-2008-server-core-does-not.html

Seems like Microsoft have changed their mind and the Core install will support ASP.NET and a "subset" of .NET 2.0, 30 and 3.5 when SP2 arrives.

Thursday 6 November 2008

DebugView and Windows Server 2008

DebugView is a great tool for development. It will provide a live feed of messages output to the Debug listener. If you make a call to System.Diagnostics.Debug.WriteLine() then that message will appear in the DebugView console. Very useful for development, even more so when working with server products like BizTalk or SharePoint. You can insert Debug.WriteLine() statements into your code and monitor the behaviour of your application in real time.

One added bonus is that calls to System.Diagnostics.Debug.WriteLine() are not included in the Release build of your assemblies so you're not peppering your code with statements you don't want running in production.

I've used this tool for a long time but I've discovered on Windows Server 2008 you need to run it with Elevated Privileges to be able to capture events from the Kernel and Win32. You need these enabled (under the "Capture" menu) so catch messages from applications hosted in IIS etc.

Tuesday 28 October 2008

Using a custom dictionary for FxCop in Visual Studio 2008

A colleague of mine has spotted an excellent post on how to use Custom Dictionaries with FxCop in Visual Studio 2008.

The post is here: http://duncanjasmith.blogspot.com/2008/07/creating-custom-dictionary-for-code.html

The short story is that in VS2008 there is a "BuildAction" of "CodeAnalysisDictionary" that you can apply to Project Items. Copy and edit the built-in Custom Dictionary from "%systemdrive%\Program Files\Microsoft Visual Studio 9.0\Team Tools\Static Analysis Tools\FxCop\CustomDictionary.xml" and away you go. Read his post for details on how to have an FxCop Custom Dictionary applied Solution wide.

Professional Developer Conference 2008 - Day One Summary

Key Note - Azure Services Platform

During the key note, Ray Ozzie announced Microsoft's Azure Services Platform (code name "Red Dog"). This is a "services platform" for the cloud. This platform has been used to build Live Services and will be the building blocks for .NET Services, SQL Services, SharePoint Services and Dynamics CRM Services.Service Level Agreements (with financial guarantees) are scheduled for 2009. It should be noted that it's unlikely there will be an explicit Version 1 - these services will constantly evolve.

Details and analysis here:

Visual Studio 2010 and .NET Framework 4.0 CTP

The PDC kicked off with Microsoft releasing a CTP of Visual Studio 2010 and .NET Framework 4.0. Please note this does not include any Oslo features, Oslo integration with Visual Studio will come in a later CTP.

Details here:

Silverlight 2.0

Microsoft released Silverlight 2.0 for Windows and Mac. This is an important release as it includes a cross platform implementation of the .NET Framework. The original moniker for this project was WPF/E "Windows Presentation Foundation Everywhere" and was originally announced by Jim Allchin at the last PDC in 2005.

Details here:

http://www.theregister.co.uk/2008/10/27/silverlight_two_review/

Microsoft Federation Gateway

The Microsoft Federation Gateway is an identity hub that brokers identities across disparate applications and services. For seamless integration with Active Directory, Microsoft has released a server component called the Microsoft Services Connector. It should be noted that this is implemented using open standards. This appears to be an implementation of Microsoft Active Directory Federation Services (ADFS).

Details here:

http://dev.live.com/blogs/devlive/archive/2008/10/27/420.aspx

Windows Live & OpenID

Windows Live publicly committed support for the OpenID platform enabling users to use their Windows Live ID to sign into any OpenID site.

Details here:

http://dev.live.com/blogs/devlive/archive/2008/10/27/421.aspx

More information on OpenID here:

http://openid.net/

Oslo Developer Centre

Microsoft announced the Oslo Developer Centre. You can download an Oslo CTP now from this site. This CTP includes documents and tools for working with the “M” language.

Main site:

http://msdn.microsoft.com/en-gb/oslo/default.aspx

Oslo SDK direct link:

http://download.microsoft.com/download/4/2/3/423FFDF3-B0B9-4EF0-990F-82DDE530B672/RepositoryOct2008CTP.msi

WCF REST Starter Kit

This is a preview of the REST features for WCF 4.0. Find it at the WCF Developer Centre.

Main site:

http://msdn.microsoft.com/wcf/rest

WCF REST Starter Kit direct link:

http://www.codeplex.com/aspnet/Wiki/View.aspx?title=WCF%20REST

Day One Summaries and Digests

S. Somasegar, Senior Vice Preseident of the Developer Division sums things up here:

http://blogs.msdn.com/somasegar/archive/2008/10/27/announcements-from-pdc-2008.aspx

Steve Martin, Director of Product Management for Microsoft's Connected Systems Division talks about where the Azure Services Platform is going and what is available now:

http://blogs.msdn.com/stevemar/archive/2008/10/27/pdc-day-1-azure-services-platform-ctp-availability-and-much-more.aspx

Matt Milner from Pluralsight talks about the Azure Services Platform in more depth:

http://www.pluralsight.com/community/blogs/matt/archive/2008/10/27/pdc-keynote-day-1.aspx


Friday 17 October 2008

Windows Server 2008 as a workstation (Part 3)

Most people will want to use Windows Live Messenger, unfortunately the installer from the "Get Live" site (http://get.live.com/) does not work with Windows Server 2008.

One way around this is to download Windows Live Messenger Version 8.1 from Microsoft.com. You can find it here: http://www.microsoft.com/downloads/details.aspx?familyid=d78f2ff1-79ea-4066-8ba0-ddbed94864fc&displaylang=en

This works fine for Windows Server 2008.

Windows Server 2008 as a workstation (Part 2)

Continuing from my last post about using Windows Server 2008 as a workstation there are some changes to make to Internet Explorer to make it more usable.

As per Windows 2003 Server, the operating system employs the "Internet Explorer Enhanced Security Configuration" component to lock down IE. This makes total sense when Windows Server 2008 is being used as a server but when using it for general use its not user friendly.

In Windows 2003 Server you were able to completely un-install the "Internet Explorer Enhanced Security Configuration" component from Add/Remove Programs in Control Panel. That is not possible in Windows Server 2008 as the component is baked into the OS. You can't remove it but you can disable it.

To do this open Server Manager (Start --> Administrative Tools --> Server Manager). On the right hand side under the "Security" section, click on "Configure IE ESC". This opens a new dialog box where you can disable Internet Explorer Enhanced Security Configuration for Admins and/or Users.

Thursday 16 October 2008

Windows Server 2008 as a workstation

I have been using Windows Server 2008 as a my main workstation lately and my experiences have been wholly positive but there are two niggling issues. Fortunately both are easily resolvable.

The first is that by default, the use of MSIs is prohibited (okay, this is more than a niggle). To be able to install additional programs you need to change the Local Group Policy. To do this run "gpedit.msc" and navigate to "Computer Configuration\Administrative Temaplates\Windows Components\Windows Installer". Change the "Disable Windows Installer" state to "Enabled".

The second issue is the annoying "Shut Down Windows" dialog that appears everytime you want to shutdown your box. This dialog box requires that you enter a reason everytime you shutdown or restart your box. I have found multiple articles and blogs that suggest you need to change the Local Group Policy. Done by running "gpedit.msc" again, navigating to "Computer Configuration\Administrative Temaplates\System" and changing the "Display Shutdown Event Tracker" state to "Disabled". But this does not appear to work, at least it didn't for me. What did work was editing a registry value. Open regedit.exe and go to "HKLM\SOFTWARE\Policies\Microsoft\WindowsNT". Create a new Key called "Reliability" and add a DWORD value at that location. The name should be "ShutdownReasonOn" and the value should be "0".

Repairing the .NET Framework 2.0 and 3.0 on Windows Vista and Windows Server 2008

I had a problem recently with some files from the .NET Framework 2.0 being corrupt. I think the root cause of the problem was use of Virtual Machines. Anyway, I needed to repair the .NET Framework 2.0, specifically aspnet_regiis.exe.

The problem is that under Windows Vista and Windows Server 2008 these components are part of the operating system so you can't do a repair with the MSI like you normally can with installed programs. After doing some digging I found the answer here:

http://blogs.msdn.com/astebner/archive/2007/03/26/how-to-repair-the-net-framework-2-0-and-3-0-on-windows-vista.aspx

The short story is to run "sfc /scannow" with elevated privileges.

Sunday 5 October 2008

Visual Studio Team System Developer & Database Editions are merged

Microsoft has recently announced that the Visual Studio Team System Developer & Database Editions are to be merged, details are here: http://msdn.microsoft.com/en-us/vsts2008/products/cc990295.aspx

Essentially MSDN Subscribers with a "Visual Studio Team System Developer" or "Visual Studio Team System Database" (or relevant Partner Programs) will be given access to the alternative SKU. Please note that these products are not a single installation, you need to install both products. This results in you having both SKUs installed which means you will get additional features/menus in Visual Studio. This affects the current toolset in addition to Rosario (VS2010).

This is a great move by Microsoft, the features of the Database Edition are incredibly useful to a
developer. There is a new Database Project type that supports MSBuild, this means you can build/rebuild you database schema from the IDE or from the command line. The schema compare facilities give you functionality broadly equivalent to RedGate's fantastic SQL Compare product (http://www.red-gate.com/products/SQL_Compare/index.htm).

Monday 30 June 2008

XBAP applications and Strong Naming.

One of the first things that is hammered into you when start reading up on XBAP applications is that they run with Partial Trust. There are ways to get your XBAP application running with full trust but this is not the typical scenario (and that topic is worth a whole series of blog posts).

When you Strong Name an assembly, by default the assembly will not allow Partially Trusted callers. As the sandbox in which your XBAP applications run is running with Partial Trust, this means that you will get the following error in the browser when you try to run your application

Startup URI: C:\dir\MyApplication.xbapApplication Identity: file:///C:/dir/MyApplication.xbap#MyApplication.xbap, Version=x.x.x.x, Culture=neutral, PublicKeyToken=0000000000000000, processorArchitecture=msil/MyApplication.exe, Version=x.x.x.x, Culture=neutral, PublicKeyToken=0000000000000000, processorArchitecture=msil, type=win32
System.Security.SecurityException: That assembly does not allow partially trusted callers. at System.Security.CodeAccessSecurityEngine.ThrowSecurityException(Assembly asm, PermissionSet granted, PermissionSet refused, RuntimeMethodHandle rmh, SecurityAction action, Object demand, IPermission permThatFailed) at System.AppDomain._nExecuteAssembly(Assembly assembly, String[] args) at System.AppDomain.nExecuteAssembly(Assembly assembly, String[] args) at System.Runtime.Hosting.ManifestRunner.Run(Boolean checkAptModel) at System.Runtime.Hosting.ManifestRunner.ExecuteAsAssembly() at System.Runtime.Hosting.ApplicationActivator.CreateInstance(ActivationContext activationContext, String[] activationCustomData) at System.Runtime.Hosting.ApplicationActivator.CreateInstance(ActivationContext activationContext) at System.Windows.Interop.PresentationApplicationActivator.CreateInstance(ActivationContext actCtx) at System.Activator.CreateInstance(ActivationContext activationContext) at System.AppDomain.InternalRemotelySetupRemoteDomainHelper(Object[] args) at System.Threading.Thread.CompleteCrossContextCallback(InternalCrossContextDelegate ftnToCall, Object[] args) at System.AppDomain.nCreateInstance(String friendlyName, AppDomainSetup setup, Evidence providedSecurityInfo, Evidence creatorsSecurityInfo, IntPtr parentSecurityDescriptor) at System.Runtime.Hosting.ApplicationActivator.CreateInstanceHelper(AppDomainSetup adSetup) at System.Runtime.Hosting.ApplicationActivator.CreateInstance(ActivationContext activationContext, String[] activationCustomData) at System.Windows.Interop.PresentationApplicationActivator.CreateInstance(ActivationContext actCtx) at System.Windows.Interop.ApplicationLauncherXappDebug.Initialize() at System.Windows.Interop.DocObjHost.MS.Internal.AppModel.IBrowserHostServices.Run(String path, String debugSecurityZoneURL, String viewerUri, String fragment, String applicationId, MimeType mime, Object streamContainer, Object ucomLoadIStream, String userAgentString, Boolean isDebugMode, String progressAssemblyName, String progressClassName, String errorAssemblyName, String errorClassName)The action that failed was:LinkDemandThe method that caused the failure was:Void Main()


To prevent this problem, you need to mark your XBAP assembly with the AllowPartiallyTrustedCallersAttribute, for example:

[assembly: AllowPartiallyTrustedCallers]


With this Attribute your XBAP application will now run.

Wednesday 25 June 2008

Microsoft Dynamics CRM 4.0 install error "The instance name must be the same as computer name."

If you are installing Microsoft Dynamics CRM 4.0 to a computer that you have renamed, this can cause problems depending on when you installed SQL Server 2005. If you installed SQL Server before you renamed the box, you will receive the following error regarding SQL Server 2005 when the installer does a system check:

"The instance name must be the same as computer name."

To fix this problem you need to update the name of the machine in SQL Server by executing the following:

sp_dropserver 'OldMachineName'
GO
sp_addserver 'NewMachineName', local
GO

You will also need to restart the SQL Server service. Please note you can't use this command to change the instance suffixes. For example you can NOT change "serverA\SomeInstance" to "serverA\AnotherInstance", you may only change "serverA\SomeInstance" to "serverB\SomeInstance".

For more information see the following MSDN article: http://msdn.microsoft.com/en-us/library/ms143799.aspx

You may also need to update Reporting Services: http://msdn.microsoft.com/en-us/library/ms345235.aspx

This situation can easily arise if you have a virtual envrionment and are cloning machines.

Monday 7 April 2008

Windows 2008 Server Core does not support managed code

Yes, you read the title correctly.

The Windows 2008 Server Core SKU does not support any managed code, that means no .NET applications at all. Period.

More info in the "Server Core Installation Option of Windows Server 2008 Step-By-Step Guide" here: http://technet2.microsoft.com/windowsserver2008/en/library/47a23a74-e13c-46de-8d30-ad0afb1eaffc1033.mspx?mfr=true

Apple Safari for Windows

Apple has recently release its Safari browser for Windows: http://www.apple.com/safari/

While I hate the fonts (no where near as good as Internet Explorers Clear Type goodness) the browser itself is blisteringly fast. I use Newsgator On-line as my RSS aggregator and under IE it runs fairly slow (there is alot of JavaScript). Under Safari it is incredibly fast.

The browser wars are here again.

Sunday 6 April 2008

MSBuild, VS2008 and "Invalid search path"

Since installing VS2008 I have been getting the following error when using the VS2008 Command Prompt and trying to build Visual Studio solutions or trying to run "local" Team Builds:

CSC : error CS1668: Warning as Error: Invalid search path 'C:\Program Files\\Microsoft SDKs\Windows\v6.0A\lib' specified in 'LIB environment variable' -- 'The system cannot find the path specified. '

The reason for this is that the environment variables configured for this command console assume you have installed the C++ components with Visual Studio (which I did not install for the sakes of disk space).

The easiest way to solve this problem is to create the path. The "'C:\Program Files\\Microsoft SDKs\Windows\v6.0A\" path should already exist, so just create a "Lib" folder at that location.

Its a simple fix but working out why this was a problem was tricky, it niggled me why a fairly straight forward install of VS2008 would have a not insignificant problem.

Thursday 13 March 2008

Generating a Schema for the BizTalk SQL Adapter

To call a Stored Procedure from BizTalk you need to use the SQL Adapter. This requires you add a special Schema to your BizTalk application, this Schema is generated by a wizard in Visual Studio (the wizard is installed as part of the BizTalk SDK).

This process isn't as straight forward as it should be an its easy to end up with a Schema where the value returned from the Stored Procedure is represented by a "Success" Element of "anyType which is useless.

Firstly, you must have a Stored Procedure that that returns a result set using "FOR XML AUTO". Secondly, when you run through the wizard you must add "XMLDATA" to the end of the Stored Procedure (and remove it after you have generated the Schema). The XMLDATA clause causes SQL Server to return the Schema for the result set (as well as the result). So, when you go through the wizard you must have a stored procedure looking something like this:

SELECT ColumnA, ColumnB FROM MyTable FOR XML AUTO, XMLDATA

After you have generated your schema, remove the "XMLDATA" clause to leave:

SELECT ColumnA, ColumnB FROM MyTable FOR XML AUTO

When you run through the wizard, most of the values you need to enter are obvious but when you get to the "Schema Information" screen, you need to change the "Port Type" to "Send".

When you get to the "Statement Information" screen, you need to enter valid values into the "Value" column (click the Value cell twice to enter data). Then hit "Generate", then hit "Next".

The SQL Adapter Wizard does not seem to support "FOR XML EXPLICIT", you get an error that says "the required attribute 'name' is missing". However, I would guess that if you can generate the boiler plate Schema using "FOR XML AUTO," you should be able to change your Stored Procedure and then manually edit the Schema generated by the Wizard to match what your XML EXPLICIT format.

Wednesday 5 March 2008

Microsoft SharedView Version 1.0 available

Microsoft’s desktop sharing application, called SharedView, is out of beta. Think of the application as “Live Meeting”-lite, where up to 15 people can all share one desktop.

Download from here: http://www.connect.microsoft.com/content/content.aspx?ContentID=5306&SiteID=94

Monday 3 March 2008

Gated Check-ins and Team Foundation Server

There was a discussion lately on the ALT.NET mailing list about the merits of NAnt versus MSBuild. This discussion expanded to encompass the various build engines there are outt here such as CruiseControl.NET (open source from ThoughtWorks) and TeamCity (free for non-Enterprise use, by JetBrains).

Someone mentioned the "private build" feature of TeamCity where by you ask the build server to do a build of what you currently have but without actually checking in your code to the source tree.

I pointed out that this feautre is also supported by Team Foundation Server through an open source framework exisits called Gauntlet (http://www.opengauntlet.org/). The elevator pitch from the Gauntlet web site is as follows:

"OpenGauntlet...mimics a fundamental feature of Microsoft's internal development system (codenamed Gauntlet), also known as "Gated Checkins". It avoids the problems associated with large development teams whereby a single developer will check in non-compiling code, which subsequently causes delays in the development life cycle as the team waits for the issues to be resolved. It can also be configured to disallow check ins if the proposed code changes break the unit tests. The central principle is that users are not allowed to check code directly into source control. Instead, they shelve their changes with a specific naming prefix when they are ready to check some changes in, and OpenGauntlet unshelves their changes into a temporary workspace, checks the changes compile and pass unit tests, and then checks the changes into source control under the requesting developer's username."

I've not taken the plunge with setting this up yet, I have an upgrade to TFS2008 to do first, but it looks like a must have. Here's to less "red" builds!

Monday 25 February 2008

NServiceBus

I subscribed to Udi Dahan's blog recently (http://udidahan.weblogs.us/). I saw him present a session called "Designing High Performance, Persistent Domain Models" at Tech-Ed 2007 in Barcelona. It was one of the best sessions I saw during the week. How he got a talk with NHibernate demo material into Tech-Ed I'll never know.

I read through some of the old blog posts to catch up on what he'd been doing since Tech-Ed and I noticed he'd been working on a open source messaging framework called "NServiceBus" (http://www.nservicebus.com/).

This is interesting because I frequently encounter projects that require some kind of message bus with pub/sub features but don't want to take the plunge with BizTalk as its either too heavy weight or the license cost is prohibitive.

The project seems to be progressing, version 1.7 has been released at the time of writing and there is an active news group (http://tech.groups.yahoo.com/group/nservicebus/).

I will evaluate the framework at some point and report back.


Saturday 23 February 2008

WCF Services and Dependency Injection with Castle

You might encounter a situation where you are leveraging the dependency injection design pattern in your application. At first this might seem problematic to implement if you are using WCF Services.

For example, you may have the following classes:

public interface ICustomerRepository

{

    // Code

}

 

public class CustomerRepository : ICustomerRepository

{

    // Code

}

 

[ServiceContract]

public interface ICustomerService

{

    [OperationContract]

    void AddCustomer(AddCustomerRequest addCustomerRequest);

}

 

public class CustomerService : ICustomerService

{

    private readonly ICustomerRepository _customerRepository;

 

    public CustomerService(ICustomerRepository customerRepository)

    {

        _customerRepository = customerRepository;

    }

 

    /// <remarks />

    public void AddCustomer(AddCustomerRequest addCustomerRequest)

    {

        // Do stuff

        // _customerRepository.SomeMethod(someParameter);

    }

}

The problem is that as your WCF Service is instantiated by the WCF plumbing, you don't have any control over the creation of this class. How do you "inject the dependency"? How do you supply the "ICustomerRepository" to the "CustomerService"? If you are using the Windsor Container part of the Castle framework (http://www.castleproject.org/) as your Component Container, it has a Facility that enables us to do this.

Using the "CustomerService" example above, you need to do three things in your Web Services project.

1. Modify the .svc file

Create your "CustomerService.svc" file as follows:

<%@ ServiceHost Service="CustomerService" Factory="Castle.Facilities.WcfIntegration.WindsorServiceHostFactory, Castle.Facilities.WcfIntegration" %>

Note the differences between a standard svc file.

2. Modify your Global.asax

Next you need to instantiate a Windsor Container, do this in a Global.asax file as follows (you might have to add one to your project):

public class Global : HttpApplication

{

    private readonly IWindsorContainer _container =

        new WindsorContainer(new XmlInterpreter());

 

    protected void Application_End(object sender, EventArgs e)

    {

        if (_container != null)

            _container.Dispose();

    }

 

    protected void Application_Start(object sender, EventArgs e)

    {

        WindsorServiceHostFactory.RegisterContainer(_container.Kernel);

    }

}

3. Configure Castle

Configure Castle in the usual way, you need to include your "CustomerService" and "CustomerRepository" classes in the configuration. An example is as follows:

<configSections>

  <section

    name="castle"

    type="Castle.Windsor.Configuration.AppDomain.CastleSectionHandler, Castle.Windsor" />

</configSections>

 

<castle>

  <components>

    <component

      id="CustomerRepository"

      service="Acme.PetSop.ICustomerRepository, myAssembly"

      type="Acme.PetSop.CustomerRepository, myAssembly" />

    <component

      id="CustomerService"

      service="Acme.PetSop.ICustomerService, myAssembly"

      type="Acme.PetSop.CustomerService, myAssembly" />

  </components>

</castle>

Please note that your "Service" value in the .svc file must match the "id" value in the Castle configuration.

You need to have the "Castle.Facilities.WcfIntegration.dll" assembly referenced by your Web Application project. At the time of writing this assembly is not in the latest Castle release and can only be found in the nightly builds.

The Castle documentation for the WCF Facility can be found here: http://www.castleproject.org/container/facilities/trunk/wcf/index.html


Saturday 16 February 2008

Using the MSTest AspNetDevelopmentServer Attribute

If you want to have Integration-type tests and run automated tests against a web service (or web site), with MSTest you can use the "AspNetDevelopmentServer" Attribute on your Test Method. There is a gotcha with the use of this attribute. See the following example:

[TestClass]

public class MyTestClass

{

    [TestMethod]

    [AspNetDevelopmentServer("name", "path")]

    public void MyTestMethod()

    {

        // Do stuff

    }

}



You might be tempted to put the "name" and "path" properties in constants somewhere. Unfortunately if you do this, the "AspNetDevelopmentServer" Attribute will cease to function and the ASP.NET Development Server will not be activated when your tests run. Why is a mystery. So, keep the property values as hard-coded strings in-line.

Friday 15 February 2008

Installing Visual Studio 2005 Extensions for .NET Framework 3.0 after Visual Studio 2008

This took me a while to resolve.

If you come to install the Visual Studio 2005 Extensions for .NET Framework 3.0 after you have installed .NET Framework 3.0 SP1 or Visual Studio 2008 (which installs .NET 3.0 SP1) then you will receive get a message saying you need to have .NET Framework 3.0 installed (as in, no Service Pack). Obviously you can't because you'll have to un-install/re-install a whole chain of stuff.

A small registry hack will let you re-try the installation, add the following to your registry:

[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\{15095BF3-A3D7-4DDF-B193-3A496881E003}]
"DisplayName"="Microsoft .NET Framework 3.0"

This will fool the installer. I'd recommend removing the registry entry afterwards (that's what I did).

More details here: http://forums.microsoft.com/MSDN/ShowPost.aspx?PostID=2550726&SiteID=1

Sunday 27 January 2008

Extending MSTest

One criticism that is levelled against MSTest, especially when comparing it against the xUnit testing frameworks, is its lack of extensibility. While MSTest is missing any explicit extension points, it is possible to extend its functionality and add additional Test Attributes. In this post I will describe how to do this.

I have created a project on CodePlex hosting the solution which supports VS2005 and VS2008 (link at the end). The CodePlex release contains MSIs plus the full source code.

The MSTest extensions Attributes are as follows:
  • TestTransaction – this provides equivalent functionality to MbUnit’s much lauded “RollBack” attribute.
  • ExpectedExceptionMessage – this is an alternative to MSTest’s built-in “ExpectedException” Attribute. The built in “ExpectedException” Attribute is broken, it allows you to provide a message which you would expect is the exception message that is thrown by the expected type. But it isn’t. It’s actually a message that is displayed to the user in the test results log which is very confusing. This alternative allows you to supply the exception message. If the exception message thrown by the Test Method does not match the message in the ExpectedExceptionMessage Attribute, then the test fails.
  • TestTimer – this allows us to put a timer on the unit tests so if a unit test takes longer than the time specified in the Attribute then the test fails.

An example usage of the custom Attributes for MSTest are as follows:

[TestClass]

public class TestTransactionAttributeTest : MSTestExtensionsTestFixture

{

    [TestMethod]

    [TestTransaction]

    public void SomeTest1()

    {

        // Do database stuff, will be

        // rolled back  after test ends.

    }

 

    [TestMethod]

    [TestTimer(10)]

    public void SomeTest2()

    {

        // Do stuff, if it takes longer

        // than  10 milliseconds the test

        // will fail.

    }

 

    [TestMethod]

    [ExpectedExceptionMessage(typeof(MSTestExtensionsException), "Message.")]

    public void SomeTest3()

    {

        throw new MSTestExtensionsException("Message.");

        // This test passes

        // (see above comments).

    }

}

Please note there are no references to any xUnit frameworks! All that is required is to inherit from “MSTestExtensionsTestFixture” and to decorate the Test Methods with the relevant Attribute.

Here’s how we get there...

A comprehension of Aspect Oriented Programming (AOP) is needed to understand how this all fits together. I won’t go into AOP in detail as there are many on-line resources that do a much better job than I would. This is as good a place as any to start: http://en.wikipedia.org/wiki/Aspect-oriented_programming.

MSTest, like the xUnit testing frameworks, uses Attributes on Classes and Methods to specify tests and their behaviour. AOP uses the same style of Attributes on Types to extend their behaviour. If you were building your own application, you might use a framework such as Spring.NET which would provide you with a transparent AOP mechanism. Unfortunately, as MSTest is effectively “closed” (there are no extension points) we don’t have any such options. We have to wire up the AOP features ourselves.

The only way to implement AOP is to use the following objects from the .NET Framework:

  • System.ContextBoundObject – the object that you wish to decorate with Attributes as a means to change the behaviour must inherit from this class.
  • System.Runtime.Remoting.Contexts.ContextAttribute – Attributes inheriting from this Attribute will be called at run-time when the type that they are decorating is called.

The combination of these two objects will allow us to intercept method calls. If we can intercept calls to Methods, we can intercept the calls to Test Methods and modify their behaviour. Every one of our Test Classes (or Fixtures if you prefer) will need to inherit from “ContextBoundObject” and be decorated with our own specialised “ContextAttribute”. Instead of having to do this every time we write a Test Class, we’ll create a Class from which we can inherit when we want to write a Test Class. We’ll call this base class “MSTestExtensionsTestFixture” (as per the previous examples).This is as follows:

[MSTestExtensionsTest]

public class MSTestExtensionsTestFixture : ContextBoundObject

{

}

The “MSTestExtensionsTestFixture” class is as simple as that, it inherits from “ContextBoundObject”, so any classes that inherit from this will be ready for our AOP widgets. Any Test Classes that are to take advantage of our “extensions” will need to inherit from this class or else we won’t be able to intercept the Method calls.

The “MSTestExtensionsTest” Attribute that this base Test Class is decorated with needs explaining. The “MSTestExtensionsTest” Attribute inherits from the “ContextAttribute” mentioned above. The “ContextAttribute” class has a virtual method called “GetPropertiesForNewContext” which we override. This method allows us to add “Aspects” to the context (see above link for a detailed description of Aspects and other AOP concepts). These “Aspects” will intercept Method calls i.e. when the Test Methods are executed, allowing us to change their behaviour. The important “MSTestExtensionsTest” Attribute code is as follows:

[AttributeUsage(AttributeTargets.Class)]

public sealed class MSTestExtensionsTestAttribute : ContextAttribute

{

    ...

 

    public override void GetPropertiesForNewContext(IConstructionCallMessage msg)

    {

        if (msg == null)

            throw new ArgumentNullException("msg");

        msg.ContextProperties.Add(new TestProperty<TestTimerAspect>());

        msg.ContextProperties.Add(new TestProperty<TestTransactionAspect>());

        msg.ContextProperties.Add(new TestProperty<ExpectedExceptionMessageAspect>());

    }

 

    ...

}

The "TestProperty" is a generic Class to reduce the amount of boiler plate code in each Aspect Class. I will skip this for the sakes on brevity, please look at the attached source code for details.

Fast forwarding, this is what an Aspect looks like:

public class MyAspect : TestAspect<TestTimerAttribute>, IMessageSink, ITestAspect

{

    ...

 

    [SecurityPermission(SecurityAction.LinkDemand, Flags = SecurityPermissionFlag.Infrastructure)]

    public IMessage SyncProcessMessage(IMessage msg)

    {

        if (msg == null)

            throw new ArgumentNullException("msg");

        // The following line is the call

        // to the actual method we have

        // intercepted. We can do stuff

        // before we call this or after.

        // This lets us change behaviour.

        IMessage returnMessage = _nextSink.SyncProcessMessage(msg);

        return returnMessage;

    }

 

    ...

}

Please review the in-line comments above. If this code was used as-is, it would simply call the Method that had been intercepted and we would notice no change in behaviour. However, we can add code before and/or after the call to “SyncProcessMessage” to do whatever we wish. This is the point at which we add our custom code to change the behaviour of the calls to the Test Methods.

From the above code, the “TestAspect” Class is another Class containing boiler plate code which I will skip over and the “ITestAspect” Interface is an Interface that our Aspects must satisfy.

An Aspect must be accompanied by an Attribute, an Attribute is simple and is essentially a placeholder for properties and ensures an Aspect is called. An example Attribute is as follows:

public sealed class MyAttribute : Attribute

{

    private string _someProperty;

 

    public MyAttribute(string someProperty)

    {

        _testLength = someProperty;

    }

 

    public string SomeProperty

    {

        get { return _someProperty; }

    }

}

And bringing it all together, if we were to use our (rather useless) Attribute it would look like so:

[TestClass]

public class MyTest : MSTestExtensionsTestFixture

{

    [TestMethod]

    [MyAttribute("some value")]

    public void SomeTest()

    {

        // Unit test code.

    }

}

Summary

I have skipped over the details of AOP as I would only be repeating other resources you can find on-line. However, I hope I’ve given you a taste of how the solution was implemented. Full source code is available from the CodePlex project

I think this shows that MSTest can be extended and via this mechanism can match a lot of the features of the xUnit frameworks. If you want to make further extensions, all you need to do is implement you own "TestAttribute" and an accompanying "TestAspect". Inherit from the "MSTestExtensionsFixture" and apply your Attribute and you are good to go.

Note the CodePlex solution supports VS2005 and VS2008. With the extensions that are possible and the performance improvements in VS2008 (MSTest is noticeably faster), then MSTest is not such a poor cousin to the xUnit frameworks anymore.

MSTest...it’s not all that bad, honest!

The CodePlex project hosting the solution can be found here: http://www.codeplex.com/MSTestExtensions

Callum


Blog Archive

About Me