Oftentimes, when developing or integration-testing a piece of software that is web-based (for example a web site or a web service component such as an Azure Mobile Service), being able to start and stop a web server programmatically on an as-needed basis comes in very handy.
This is where IIS Express comes into play. IIS Express basically is a lightweight, self-contained version of his big sibling, the fully fledged Internet Information Server. Because it doesn’t run as a service and doesn’t require administrator rights, it is ideally suited for developing and testing web sites and services locally – just like Visual Studio starts an instance of IIS Express when you hit F5 on a web application/service.
This post presents a helper class to programmatically interact with the IIS Express web server.
The IisExpress
class essentially, is a wrapper around the IIS Express command line (you can read more about the command line interface here). It’s public interface looks like this:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 |
/// <summary> /// Helper class for running IIS Express. Basically a convenient wrapper around IIS Express' command line. /// </summary> public class IisExpress { /// <summary> /// The path to the <c>iisexpress.exe</c> executable. Defaults to the default installation path /// (e.g. <c>C:\Program Files (x86)\IIS Express\iisexpress.exe</c>), if not explicitely set. /// </summary> public string ExePath { get; set; } /// <summary> /// Path to the IIS Express configuration file. Defaults to <c>USER\DOCUMENTS\IISExpress\config\applicationhost.config</c>. /// </summary> public string ConfigPath { get; set; } /// <summary> /// The application pool that IIS Express should use. Defaults to <c>"Clr4IntegratedAppPool"</c>. /// </summary> public string AppPool { get; set; } /// <summary> /// Gets a value indicating whether the associated IIS Express instance is currently running. /// </summary> public bool IsRunning { get { return _process != null; } } /// <summary> /// Starts IIS Express with the specified website. /// </summary> /// <param name="site">The website that IIS Express should host.</param> /// <exception cref="ArgumentNullException"> /// Argument <paramref name="site"/> is null. /// </exception> /// <exception cref="InvalidOperationException"> /// There already is an associated IIS Express instance running (i.e. <see cref="IsRunning"/> is true). /// </exception> /// <exception cref="FileNotFoundException"> /// Either <see cref="ExePath"/> or <see cref="ConfigPath"/> could not be found. /// </exception> public void Start(string site) { ... } /// <summary> /// Stops the IIS Express instance that was formerly started via the <see cref="Start"/> method. /// </summary> public void Stop() { ... } } |
The configuration file
One really nice thing about IIS Express is that it enables you to work with the full web-server feature set – including SSL, URL Rewrite, Media Support, and the IIS extensibility model. (A configuration reference can be found here).
The default IIS/IIS Express configuration file is located in the %userprofile%\Documents\IISExpress\config
folder or %userprofile%\My Documents\IISExpress\config
folder, depending on your OS. – This is the configuration that the IisExpress
class uses as default when no other config file was explicitly specified. However, in most cases you will use an extra file for your purposes that you will commit to your source repository along with the rest of your project, containing the specific configuration settings for your scenario. (Tip: You can start with a copy of your original applicationhost.config
.).
Using the class with xUnit.Net
In this section, I will shortly demonstrate how the IisExpress
helper could be used for integration testing an ASP.NET MVC application. I will use xUnit.Net here, but the choice of the unit testing framework is largely a matter of personal taste. Essentially, the story remains the same for NUnit or Visual Studio Unit Testing Framework (MSTest) or whatever else…
First of all, we need a mechanism to start and stop IIS Express. This would be done with TestFixtureSetUp/TestFixtureTearDown
methods in test frameworks such as NUnit, and with ClassInitialize/ClassCleanup
methods in MSTest. When using xUnit.Net, you will have a separate wrapper class for the IisExpress
helper (called a ‘fixture’ in xUnit.Net-speak), and implement the IDisposable
interface to automatically have IIS Express shutting down when the fixture goes out of scope:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 |
/// <summary> /// XUnit.Net fixture class that exposes the <see cref="IisExpress"/> helper class /// to a test class that implements <see cref="IUseFixture{IisExpressFixture}"/>. /// Shuts down the IisExpress instance on disposal. /// </summary> /// <remarks> /// Instantiated just before the first test is run, and the same instance is shared by all tests in the class. /// Implements <see cref="IDisposable"/>, therefore it will be disposed of after the last test is run. /// <para>Equivalent to <c>TestFixtureSetUp/TearDown</c> methods in NUnit, or <c>ClassInitialize/Cleanup</c> /// in MSTest respectively. </para> /// </remarks> public class IisExpressFixture : IDisposable { private readonly IisExpress _iisExpress = new IisExpress(); public IisExpress IisExpress { get { return _iisExpress; } } public void Dispose() { _iisExpress.Stop(); } } |
You would then ‘inject’ that fixture in your test class via the IUseFixture<T>
interface and initialize the IisExpress
helper in your class that contains the actual tests:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
public class Tests : IUseFixture<IisExpressFixture> { public void SetFixture(IisExpressFixture fixture) { if (!fixture.IisExpress.IsRunning) { fixture.IisExpress.ConfigPath = "IisHelper.MvcApplication.Test.config"; fixture.IisExpress.Start("IisHelper.MvcApplication"); } } // test go here... } |
As you can see, the IsRunning
property is checked before initialization; this is because xUnit.Net creates a new test class instance for each single test method (which is the biggest conceptual difference to other test frameworks).
On initialization of the IisExpress
class then, the path to the config file is set and then the Start()
method is called with the name of the web application which should be hosted (this is the name of the web application from the config file).
Downloads
The stand-alone IisExpress
helper class is available as a Gist here, the entire sample project with xUnit.Net and ASP.NET MVC can be found here.