avr. 26
The Belgian Agile & .NET usergroup DotNetHub (http://www.dotnethub.be) is planning soon a free conference about NodeJS and Windows Azure.
This conference will be given by Rob Ashton (one of the contributor to RavenDB) on June 05th and will be held in the Microsoft premises in Zaventem, Belgium.
Here is the conference abstract :
NodeJS is a pretty cool and fun technology to build server-side applications in; so cool in fact that Microsoft are now supporting it in their latest incarnation of Azure.
Let us first look at what NodeJS actually is and what it allows us to do, before building our first application and deploying it to Azure using the new tooling provided by Microsoft.
The conference is free. You want more information ? You want to register ? Just have a look on http://www.dotnethub.be/events/29/nodejs-and-azure-what-you-need-to-know.aspx
Tags:
avr. 18

The problem

Usually, you will use your app.config / web.config file to store some configuration. And so you will have some code depending on it. Let's take for instance :

public class MyService
{
   public void DoSomething()
   {
      string setting = ConfigurationManager.AppSettings["SomeSetting"];
      if ( setting == null )
         throw new ConfigurationErrorsException("Your settings shall be present");
      Console.WriteLine(setting);
   }
}

and of course, you will test your code. So you will have a test DLL, that will hold both a config file, and a test.

<configuration>
   <appSettings>
      <add key="SomeSetting" value="My Setting Value" />
   </appSettings>
</configuration>
[TestClass]
public class UnitTest1
{
   [TestMethod]
   public void TestMethod1()
   {
      var service = new MyService();
      service.DoSomething();
   }
}

When you will write a more complete test, you will probably start using a mock framework. Personnaly my favorite ones are Rhino Mock from Ayende, and Moles & Stubs that is developped by Microsoft Research. (Note that Moles & Stubs is getting replaced by Fakes under Visual Studio 2001).

Both framework has its own benefits and disadvantage, but this is not the place for a debate. Personally, in the late years, my preference has gone to Moles & Stubs, for its power and simplicity. So let's say you are using Moles for your test : 

(Note that the goal here is not to show the use of Moles. So we just assumere you are using some moles in your test, and so applying the HostType attribute).

[TestMethod]
[HostType("Moles")]
public void TestMethod1()
{
   var service = new MyService();
   service.DoSomething();
}

Run your test again and that time it crashes : your configuration file is not found anymore.

What happens ?

If you have already executed code from an external exe via .NET code, you may have already coped with the problem : your code is becoming the main AppDomain, and thus the searched config file correspond to your own exe and no longer to the one of the external exe. I can imagine the problem is similar here.

Note that this bug exist only when you use the HostType("Moles") and not when you only use stubs.

What do we want ?

Let's find a workaround to that bug. Moles & Stubs allows you to mock any method of the .NET framework. So we can mock also the ConfigurationManager ?

Here is the idea, using moles to "mole" the ConfigurationManager in order to let him "eat" the correct configuration file.

Of course, we need to do that in each test that is running with the HostType("Moles"). So the best would be to have that code in a global location that could be applied to every single corresponding method. This is typically where we need some AOP (Aspect Oriented Programming).

The solution - Step 1

There is many AOP framework available for .NET. As far as I am concerned, I think the best one (simpler to use and more powerful) is PostSharp.

So we want to have an attribute that can be applied to every method having the HostType attribute.

So we start by referencing PostSharp using NuGet, and we declare an attribute that will target the corresponding Test methods.

[Serializable]
[MulticastAttributeUsage(MulticastTargets.Method, AllowMultiple = false)]
public class ReconcileConfigurationManagerAttribute : OnMethodBoundaryAspect
{
   /// <summary>
   /// Returns whether the currently under investigation method shall we woven or not.
   /// We are searching any method that has the attributes [TestMethod] and [HostType("Moles")]
   /// </summary>
   /// <param name="method">The method being investigated</param>
   /// <returns>True if the method shall be woven, otherwise false</returns>
   public override bool CompileTimeValidate(MethodBase method)
   {
      if ( method.GetCustomAttributes(typeof(TestMethodAttribute), false).Length == 0 )
         return false;
      var hostType = method.GetCustomAttributes(typeof(HostTypeAttribute), false)
                           .Cast<HostTypeAttribute>()
                           .FirstOrDefault();
      if ( hostType == null || hostType.HostType != "Moles" )
         return false;
      return true;
   }
}

Step 2 : let's reconcile the ConfigurationManager

Now we need to update the attribute so we can use Moles to let the ConfigurationManager work again. To do that, we need to override the OnEntry method of our attribute.

/// <summary>
/// When entrying the method, let's mole the ConfigurationManager, so he uses the correct config file.
/// </summary>
/// <param name="args">The execution argument</param>
public sealed override void OnEntry(MethodExecutionArgs args)
{
   ExeConfigurationFileMap fileMap = new ExeConfigurationFileMap();
   fileMap.ExeConfigFilename = args.Method.DeclaringType.Assembly.GetName().Name + ".dll.config";
   var config = ConfigurationManager.OpenMappedExeConfiguration(fileMap, ConfigurationUserLevel.None);
   MConfigurationManager.GetSectionString = (sectionName) =>
      {
         //Note that when your code is using AppSettings, you do not work with the AppSettingsSection
         //but with a NameValueCollection.
         //So we need to handle that differently
         var section = config.GetSection(sectionName);
         if ( section is AppSettingsSection )
         {
            var collection = new NameValueCollection();
            foreach ( KeyValueConfigurationElement item in ( (AppSettingsSection)section ).Settings )
               collection.Add(item.Key, item.Value);
            return collection;
         }
         return section;
      };


   base.OnEntry(args);
}

What we do here is quite simple : the application should have used the app.config file that you have defined in your test assembly. So we are just taking the name of the test assembly, and concatening ".dll.config" : this correspond to the name of the config file that should have been used. And so, when our production code is calling the method ConfigurationManager.GetSection, we are just "redirecting" to the correct file.

Note that calling the GetSection method returns you a class inheriting from ConfigurationSection. However, we need to do a special treatment for the section appSettings. Indeed when you call ConfigurationManager.AppSettings, you receive a NameValueCollection and not the AppSettingsSection.

Step 3 : let's use our attribute

So now that our attribute is ready for use, we just need to use it in our test library. That's so simple : let's edit our AssemblyInfo.cs to apply our attribute to the whole assembly.

[assembly: ReconcileConfigurationManager]
//This line may be needed
//[assembly: MoledType(typeof(ConfigurationManager))]

PostSharp will do it's job and apply our code to any TestMethod that is using Moles. And, you have simply worked around the bug !

Note that for performance reasons, Moles & Stubs does not allow to mole some methods from the code of the .NET framework. To do this, you need to explicitely allow him to mole those types. That's the goal of the MoledTypeAttribute. In some of my tests, this attribute was not needed.

Limitations

Does this solution is a complete workaround for that bug ? I need to add some more stuff.

PostSharp is partly commercial

We are relying here on PostSharp which is a commercial product (even though it has a free licence that allows you to do a lot of great stuffs). The ability of declaring the attribute on the assembly and letting him to "propagate" to any method of that assembly is called multicast. This capability is available only with the commercial version.

If you do not want to invest (personal advice, I do think that this product worth 10x its price, and I recommend you to buy it. You won't be able to let it aside !), the described solution can still be used. But you will need to set this attribute individually on each TestMethod for which you need to "correct" the Moles bug.

Moles & Stubs cannot moles static constructor

There is another limitation to Moles & Stubs. You can mole what is called "predictibly". Unfortunately, this is not the case of a static constructor that will get called once you first call a member of a class. So any code that is inside of a static constructor cannot be replaced / detoured. So even if you are using this solution, if one of your static constructor is calling ConfigurationManager, you are stuck.

There is one possibility offered by Moles & Stubs : there is one attribute that is MolesEraseStaticConstructor. This will simply erase the cctor for the type given in the attribute constructor. This may not be sufficient in some of your cases anyway.

Conclusion

You were in love with Moles & Stubs, but quite bothered by this annoying bug ? Don't be anymore ! It can worked around, simply, and quite transparently.

juil. 11

So you have setup your continuous integration and every time you are doing a checkin, a new automated build is launched on your build server. Nice !

You have also launched the Team Foundation Build Notification tool to have a small popup alert every time a build finishes and starts. Nice !

But you would like to go a bit further and receive a mail with the build result every time a build fails (or let's say do not succeed).

Use the TFS' alerts

The Team Foundation Server includes a powerful alert system, but by default, you cannot do so many things.

Use the Team Foundation Server Power Tools

If the Project Alerts does not allow so many things, the underlying alert system is very powerful. And you can use the Team Foundation Server Power Tools (http://visualstudiogallery.msdn.microsoft.com/c255a1e4-04ba-4f68-8f4e-cd473d6b971f) that allow a very fine control of the alerts.

You can then create a new rule like the following one : 

Note that for the Send To field, you can either indicate a account name, or an email address. In the case of an account name, this correspond to an AD account, and you must have configured the email address of that person in the Active Directory.

How to customize the received email ?

All the alert process is based on XML and XSL and so you can customize the email you will received.

In the above windo, you have the Event field, corresponding to the alert type that will be raised. In our case, this correspond to the type BuildCompletionEvent2.

You can find in the folder C:\Program Files\Microsoft Team Foundation Server 2010\Application Tier\TFSJobAgent\Transforms all the XSL that are used to transform the XML into a nice HTML or plain text email. The XSL are named with the event type. So in our case, we are interesed in the two following files : 

  • BuildCompletionEvent2.xsl for HTML emails
  • BuildCompletionEvent2.plaintextXsl for plain text emails
Now it's up to you to customize the XSL content to include for example your company logo.

Which fields are available to include in the XSL ?

It's nice to be able to customize the XSL to change its look, but it could be interesting also to include some more information.

So which are the information available ?
You can have access to the XSD in the TFS database.

Just run the following query in your TFS database :
select * from tbl_EventType
and you will see for each event type the available fields.

If you want to really see the XML and not the XSD, you can simply

  • specify that your alert launch an plain text email
  • replace the XSL by one that does give the XML like the following one
    
<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
   xmlns:msxsl="urn:schemas-microsoft-com:xslt"
   exclude-result-prefixes="msxsl" >
   <xsl:output method="xml" indent="yes"/>

   <xsl:template match="@* | node()">
      <xsl:copy>
         <xsl:apply-templates select="@* | node()"/>
      </xsl:copy>
   </xsl:template>
</xsl:stylesheet>
Tags: |
juin 01

In some cases, when you are writing a unit test, you might need to have a valid HttpContext. Fortunately, you have the ability to do that with the Visual Studio's unit tests.

Let's use a static web site

So to do that, you can simply use a local existing web site. And can define your unit test as following :

[TestMethod]
[HostType("ASP.NET")]
[UrlToTest("http://localhost:7778/Default.aspx")]
[AspNetDevelopmentServerHost(@"c:\temp\WebSite\", "/")]
public void MyTestAccessingHttpContext()
{
   Assert.IsNotNull(HttpContext.Current);
}

So what does that mean ?

  • HostType specifies that you are writing an ASP.NET Unit test
  • UrlToTest defined the URL of your web site
  • AspNetDevelopmentServerHost is optional. It's required only if the website you want to use is not hosted in IIS. In that case, you will just specify a folder that is located on your computer and that will be mounted as a WebSite using the Visual Studio Web Server (Cassini). The port specified in the UrlToTest will be used to mount your web site.

How to use a "dynamic" web site ?

That's pretty cool, but the main drawback is that your website must exist on your disk. So when you have this kind of test in your team, all the team members' computer must be setup the same way to be sure to find the local website. And of course, this is the same thing for you conitnuous integration server.

To avoid this, you could have a website located in your solution (and so with a path that will change from environment to environment) and refer to this website. You could also have a folder defined in your test project and use it as a local web site. That's this second solution I will explain here (the first one is just similar, but even simpler).

First step : create your website

Here the usual way I create my minimal test web site.

My website just contain a empty Default.aspx page. The readme file is just some documentation to explain why I use this website.

I use two parent folders : 

  • The WebSite folder is the one that I will be using as a reference in my test. In my scenario, this must be unique (meaning that if you have several test projects, and some of them are using the same technique, just choose a unique name for each web site folder).
  • The __Deployment__ folder is the folder where I include all my deployable artifacts that I need for my tests. This will be more explained in the Second Step.

Second step : deploy your website

For now my website just exist in my solution, but I want it to be deployed for each test run. To do that, I need to update the testsettings of my solution.

In a basic scenario, we can just update the Local.testsettings file that is available under Solution Items. Of course if you have multiple "testsettings files", you may need to update all of them.

So what are we doing here ? We are asking MsTest to deploy, each time we are doing a test run, to deploy our "__Deployment__" folder. As a consequence, this folder will be copied to our 

Last step : use it in your test

So now when we run our test, we can have access to this website as it will be available in our current folder. So how can we transform our test code ?

/// <summary>
/// Initialization of the test class
/// </summary>
/// <param name="testContext">The test execution context</param>
[ClassInitialize]
public static void ClassInitialize(TestContext testContext)
{
   //Set an env. variable that can be used with AspNetDevelopmentServerHostAttribute
   Environment.SetEnvironmentVariable("DeployDirectory", testContext.DeploymentDirectory);
}

[TestMethod]
[HostType("ASP.NET")]
[UrlToTest("http://localhost:7778/Default.aspx")]
[AspNetDevelopmentServerHost(@"%DeployDirectory%\WebSite\", "/")]
public void MyTestAccessingHttpContext()
{
   Assert.IsNotNull(HttpContext.Current);
}

So in the initialization of our test (here I have chosen the ClassInitialize to run it only once before the first test of the class), we can create an environment variable that can be used in our aspNetDevelopmentServerHost.

With such a configuration, our test will work perfecly no matter which client computer or build server.

Tags: | |
mai 27

The scenario

CSS3 is released and implemented in all major browser latest version.

Time to use it ! So you have defined a "nice" CSS3 page like

<!DOCTYPE HTML>
<html>
<head>
   <title></title>
   <style type="text/css">
      div
      {
         padding: 10px;
         background-color: Blue;
         border: 1px solid black;
         border-radius: 30px;
         width: 800px;
         box-shadow: 10px 10px 50px red;
      }
   </style>
</head>
<body>
   <p>
      Before</p>
   <div>
      <p>
         Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vestibulum et ipsum eget nibh gravida porta. Morbi vitae felis risus, sagittis egestas ligula. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Morbi
         pretium eleifend ultricies. Nulla ut tellus vel dui ultricies scelerisque ut at odio. Morbi sem magna, facilisis non facilisis vel, molestie non diam. Aliquam ultrices velit nec lorem venenatis sit amet ultrices justo facilisis. Vivamus posuere ultricies
         mauris, accumsan tempus nibh scelerisque eget. Curabitur sed tortor feugiat diam tincidunt ultrices. Aenean fringilla dictum risus, imperdiet rutrum nibh adipiscing non. Praesent porta massa ut risus consequat ut aliquam sapien venenatis. Phasellus
         bibendum facilisis lacus, nec suscipit ante faucibus eget. Donec dolor sem, congue vestibulum malesuada et, condimentum at ante. 
      </p>
   </div>
   <p>After</p>
</body>
</html>

and you have checked in your favorite browser that the display is correct.

And now you want to use this page in a Windows Form / WPF application, hosting the page in a WebBrowser control.

The problem

One you have created a basic form and that you have rendered this HTML page in the WebBrowser, here is how it is rendered :

Well... seem that all the CSS3 functionalities have been skipped.

How the WebBrowser control works

When you use a WebBrowser control, there are several things to know:

  • The WebBrowser control use the rendering engine of Internet Explorer that is installed in you computer
  • More precisely it uses the ieframe.dll that is located in c:\Windows\System32

So if you have checked that you have correctly installed IE9 and that the ieframe.dll is at the correct version (meaning at least 9.0.8112.16421 for the first RTM version of IE9), the WebBrowser control will use the rendering engine of IE9.

But you must know that by default, the WebBrowser control is run in "IE7 compatibility mode", and so, quite logically, CSS3 is not supported.

How to correct it ?

Another important thing to know is that the WebBrowser control can be intensively configured thru the registry. That's what we call the Internet Feature Controls. More info about all those features can be found on http://msdn.microsoft.com/en-us/library/ee330720(v=VS.85).aspx

And one of these features is called Browser Emulation. It is the feature that controls the compatibility mode used by the WebBrowser control when rendering a page. The possible values are : 

  • 7000 : IE7 Standard mode (default)
  • 8000 : IE8 mode if containing standards-based DOCTYPE
  • 8888 : IE8 mode, whatever the DOCTYPE
  • 9000 : IE9 mode if containing standards-based DOCTYPE
  • 9999 : IE9, whatever the DOCTYPE

All info can be found on http://msdn.microsoft.com/en-us/library/ee330730%28v=vs.85%29.aspx#browser_emulation

So what do you need to do ? Just add a new DWORD value in the following registrey key:

  • HKEY_LOCAL_MACHINE
    • SOFTWARE
      • Microsoft
        • Internet Explorer
          • MAIN
            • FeatureControl
              • FEATURE_BROWSER_EMULATION

The key you need to add is the name of your executable, meaning, if your application is named "WindowsFormsApplication1"

  • WindowsFormsApplication1.exe when you will run directly the executable of your application
  • WindowsFormsApplication1.vshost.exe when you will run your application in debug in Visual Studio

And so let's run once more our application : 

Now everything is ok !

Thanks to Mike Dos Zhang for helping me to point out this solution !