Announcing release of ChameleonForms 2.0.0 and new documentation site

I’m somewhat more subdued¬†with my excitement for announcing this than I was for 1.0. In fact I just had a chuckle to myself in re-reading that post ūüôā (oh and if you were wondering – did Matt and I enjoy Borderlands 2? Yes we very much did, it’s a great game).

Nonetheless, there is some really cool stuff in ChameleonForms 2.0 and I’m particularly excited about the new PartialFor functionality, which I will describe below. My peak excitement about PartialFor was months ago when the code was actually written, but Matt and I have had a particularly busy¬†second half of the year with our work roles expanding in scope and a healthy prioritisation of our personal lives so it took a while to get our act together and get the code merged and released.

There have been a range of point releases that added a bunch of functionality to ChameleonForms since the 1.0 release and before this 2.0 release. You can peruse the releases list to see the features.

New docs site

I’ve taken¬†the lead (as well as a bunch of advice – thanks mate) from Jake Ginnivan¬†and moved the documentation for¬†ChameleonForms to Read the Docs. The new documentation site is now generated from files in the source repository’s docs folder. This is awesome because it means that the documentation can be tied to current state of the¬†software – no more documentation that is ahead or behind and pull requests can now contain documentation changes corresponding to the code changes.

For those who are curious the process I followed to migrate from GitHub wiki to Read the Docs was:

  1. Clone the wiki
  2. Move all the files into the docs folder of the repository
  3. Add a mkdocs.yml file to the root of the repository with all of the files¬†(this means I need to keep a list of the files in there, but I don’t mind since it gives me control of the menu, you can omit the mkdocs.yml file if you want and it¬†alphabetically places all of the files in the menu)
  4. Sign up for Read the Docs and create a new project linked to the GitHub repository
  5. Enable the fenced code markdown extension
  6. Change all internal documentation links to reference the .md file (in my case I had to search for all links to wiki/* and remove the wiki/ and add in the .md)
  7. Change any occurrences of ```c# with ```csharp (GitHub supports using c# for the fenced code snippet, but mkdocs doesn’t)
  8. Check all of the pages since some of them might render weirdly – I had to add some extra spaces between paragraphs and code blocks / bullet lists for instance since the markdown parser is slightly different

There are a bunch of different formats that give more flexibility that Read the Docs supports (e.g. restructured text), but I’m very happy with the markdown support.

2.0 minor features and bug fixes

Check out the release notes for the 2.0 release to see a bunch of minor new features and bug fixes that have been contributed by a bunch of different people Рthanks to everyone that contributed! It always give Matt and I a rush when we receive a pull request from someone :).

PartialFor feature

This is the big feature. A few breaking changes went into the 2.0 release in order to make this possible. This is the first of the extensibility features we have added to ChameleonForms.

Essentially, it allows us to contain a part of a form in a partial view, with full type-safety and intellisense. The form can be included directly against a form or inside a form section. This makes things like common parts of forms for create vs edit screens possible. This allows you to remove even more repetition in your forms, while keeping a clean separation between forms that are actually separate.

The best way to see the power of the feature in it’s glory is by glancing over the acceptance test for it.¬†The output should be fairly self explanatory.

There is also a documentation page on the feature,

Is ChameleonForms still relevant?

We were very lucky to be included in Scott Hanselman’s NuGet package of the week¬†earlier this year. The comments of Scott’s post are very interesting because it seems our library is somewhat¬†controversial. A lot of people are saying that single page applications and the increasing prevalence of JavaScript make creating forms in ASP.NET MVC redundant.

Matt and I have spent a lot more time in JavaScript land than MVC of late and we concede that there is certainly a lot more scenarios now that don’t make sense to break out MVC. That means ChameleonForms isn’t as relevant as when we first started developing it.

In saying that, we still firmly believe that there are a range of scenarios that MVC is very much appropriate for. Where you don’t need the flexibility of an API and/or you need pure speed of development (in particular developing prototypes) and/or you’re building CRUD applications or heavily forms-based applications (especially where you need consistency of your forms) we believe MVC + ChameleonForms is very much a good¬†choice and often is the best¬†choice.

Add role-based authorisation based on Azure AD group membership

This post describes how to use Azure AD groups for role-based authorisation in your ASP.NET web application.

Practical Microsoft Azure Active Directory Blog Series

This post is part of the Practical Microsoft Azure Active Directory Blog Series.

Add role-based authorisation based on Azure AD group membership

These instructions will help you easily add role-based authorisation based on Azure AD group membership to your existing ASP.NET application with Azure AD authentication.  The links show either a commit from the example project or to relevant documentation.

Note: Ignore the ...‚Äės and replace the {SPECIFIED_VALUES} with the correct values.

  1. Create groups in your Azure AD tenant
  2. Assign your users to relevant groups
  3. Configure your Azure AD application to have application permissions to read directory data from Azure Active Directory
    • If¬†you get a “Insufficient privileges to complete the operation.” exception then you might need to wait for a few minutes or an hour since it seems to cache the old permissions, or¬†it may be the problem mentioned by Jeff Dunlop in the comments
  4. In the Configure tab of your Azure AD application create a key in the keys section and copy it
  5. Configure the client id of your Azure AD application and the key you created in the last step in your web.config file
      <appSettings>
        ...
        <add key="ida:ClientId" value="{AZURE_AD_APP_CLIENT_ID}" />
        <add key="ida:Password" value="{AZURE_AD_APP_KEY}" />
      </appSettings>
    
  6. Install-Package Microsoft.Azure.ActiveDirectory.GraphClient -Version 1.0.3 (alternatively, you can use the latest version if you follow the steps mentioned by Jeff Dunlop in the comments)
  7. Install-Package Microsoft.IdentityModel.Clients.ActiveDirectory
  8. Create an AzureADGraphConnection class:
    Infrastructure\Auth\AzureADGraphConnection.cs
    
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Security.Claims;
    using Microsoft.Azure.ActiveDirectory.GraphClient;
    using Microsoft.IdentityModel.Clients.ActiveDirectory;
    
    namespace {YOUR_NAMESPACE}.Infrastructure.Auth
    {
        public interface IAzureADGraphConnection
        {
            IList<string> GetRolesForUser(ClaimsPrincipal userPrincipal);
        }
    
        public class AzureADGraphConnection : IAzureADGraphConnection
        {
            const string Resource = "https://graph.windows.net";
            public readonly Guid ClientRequestId = Guid.NewGuid();
            private readonly GraphConnection _graphConnection;
    
            public AzureADGraphConnection(string tenantName, string clientId, string clientSecret)
            {
                var authenticationContext = new AuthenticationContext("https://login.windows.net/" + tenantName, false);
                var clientCred = new ClientCredential(clientId, clientSecret);
                var token = authenticationContext.AcquireToken(Resource, clientCred).AccessToken;
    
                _graphConnection = new GraphConnection(token, ClientRequestId);
            }
    
            public IList<string> GetRolesForUser(ClaimsPrincipal userPrincipal)
            {
                return _graphConnection.GetMemberGroups(new User(userPrincipal.Identity.Name), true)
                    .Select(groupId => _graphConnection.Get<Group>(groupId))
                    .Where(g => g != null)
                    .Select(g => g.DisplayName)
                    .ToList();
            }
        }
    }
    
  9. Create an AzureADGraphClaimsAuthenticationManager class:
    Infrastructure\Auth\AzureADGraphClaimsAuthenticationManager.cs
    
    using System.Configuration;
    using System.Security.Claims;
    
    namespace AzureAdMvcExample.Infrastructure.Auth
    {
        public class AzureADGraphClaimsAuthenticationManager : ClaimsAuthenticationManager
        {
            public override ClaimsPrincipal Authenticate(string resourceName, ClaimsPrincipal incomingPrincipal)
            {
                if (incomingPrincipal == null || !incomingPrincipal.Identity.IsAuthenticated)
                    return incomingPrincipal;
    
                // Ideally this should be the code below so the connection is resolved from a DI container, but for simplicity of the demo I'll leave it as a new statement
                //var graphConnection = DependencyResolver.Current.GetService<IAzureADGraphConnection>();
                var graphConnection = new AzureADGraphConnection(
                    ConfigurationManager.AppSettings["AzureADTenant"],
                    ConfigurationManager.AppSettings["ida:ClientId"],
                    ConfigurationManager.AppSettings["ida:Password"]);
    
                var roles = graphConnection.GetRolesForUser(incomingPrincipal);
                foreach (var r in roles)
                    ((ClaimsIdentity)incomingPrincipal.Identity).AddClaim(
                        new Claim(ClaimTypes.Role, r, ClaimValueTypes.String, "GRAPH"));
                return incomingPrincipal;
            }
        }
    }
    
  10. Configure your application to use the AzureADGraphClaimsAuthenticationManager class for processing claims-based authentication in your web.config file:
      <system.identityModel>
        <identityConfiguration>
          <claimsAuthenticationManager type="{YOUR_NAMESPACE}.Infrastructure.Auth.AzureADGraphClaimsAuthenticationManager, {YOUR_ASSEMBLY_NAME}" />
          ...
        </identityConfiguration>
      </system.identityModel>
    
  11. Add [Authorize(Roles = "{AZURE_AD_GROUP_NAME}")] to any controller or action you want to restrict by role and call User.IsInRole("{AZURE_AD_GROUP_NAME}") to check if a user is a member of a particular group

Explaining the code

Microsoft.Azure.ActiveDirectory.GraphClient and AzureADGraphConnection

The ActiveDirectory.GraphClient provides a wrapper over the Azure AD Graph API, which allows you to query the users, groups, etc.

The AzureADGraphConnection class constructs a graph client connection and a method to take a user and return a list of the groups that user is a member of.

This is needed because the claims that the Azure AD token comes with by default do not include any roles.

AzureADGraphClaimsAuthenticationManager

This class provides a claims authentication manager that hooks into the point that authentication occurs and augments the Claims Principal that is generated by default by getting the Azure AD Groups that the user is a member of (via AzureADGraphConnection) and turning them into a ClaimTypes.Role claim. ClaimTypes.Role is the claim type that automatically hooks into ASP.NETs roles processing.

The web.config change is how you override the Claims Authentication Manager.

Using an enum for roles

To avoid the use of magic strings in your application and assuming the group names in AD are relatively stable you can encapsulate them in an enum. There is a corresponding commit in the example project that demonstrates how to do it.

This involves three main steps:

  1. Define an enum with your roles and using the [Description] attribute to tag each role with the Display Name of the equivalent Azure AD group
  2. Parse the group name into the corresponding enum value by using Humanizer.Dehumanize in AzureADGraphConnection
  3. Create an AuthorizeRolesAttribute that extends AuthorizeAttribute and an extension on IClaimsPrincipal that provides an IsInRole method that both take the enum you defined rather than magic strings to define the roles

Explaining the code behind authenticating MVC5 app with Azure AD

This post explains the code outlined in the last post on installing Azure AD authentication to an existing (or new) ASP.NET MVC 5 (or 3 or 4) application.

Practical Microsoft Azure Active Directory Blog Series

This post is part of the Practical Microsoft Azure Active Directory Blog Series.

Microsoft.Owin.Security.ActiveDirectory

The Microsoft.Owin.Security.ActiveDirectory package is part of the Katana project, which produces a bunch of libraries that build on top of Owin.

It allows your application to accept a Bearer Authorization header in the HTTP request that contains a JSON Web Token (JWT) token issued from Azure AD and will create a ClaimsPrincipal in the thread from that token. This is mainly useful for creating Web APIs and thus is optional if you just need web authentication.

Note: if you use bearer tokens make sure you request resources with HTTPS.

This package is enabled up by the app.UseWindowsAzureActiveDirectoryBearerAuthentication(...) call in Startup.cs.

There are two configurations in the Startup.cs code to configure the package:

  • TokenValidationParameters¬†– this controls how tokens that are presented by a user are checked for validity
    • In the code example in the previous blog post we set ValidAudience, which ensures that any tokens presented are valid for the given audience (alternatively, you can use ValidAudiences if you want to accept tokens from multiple audiences)
    • There is more information later in this post about audiences
  • Tenant – This sets which Azure AD tenant you are accepting tokens from

WSFederationAuthenticationModule (WS-FAM) and SessionAuthenticationModule (SAM)

These modules are part of WIF¬†via¬†System.IdentityModel.Services and are the mechanism by which the authentication hooks into ASP.NET and works. For this to work you need to enter a bunch of code in web.config, but Microsoft is currently working on OWIN-only components that hide all of that away and provide for a much simpler configuration so in the future you won’t need to do any of this. At the time of writing the samples don’t quite seem to work (for me at least) yet, so for now it makes sense to keep using the WIF modules, but it’s worth keeping out an eye on what happens with the samples Microsoft are working on, in particular the OpenIdConnect one.

So what do these WIF modules do? From the WSFederationAuthenticationModule documentation:

When an unauthenticated user tries to access a protected resource, the [Relying Party (RP)] returns a ‚Äú401 authorization denied‚ÄĚ HTTP response. The WS-FAM intercepts this response instead of allowing the client to receive it, then it redirects the user to the specified [Security Token Service (STS)]. The STS issues a security token, which the WS-FAM again intercepts. The WS-FAM uses the token to create an instance of¬†ClaimsPrincipal for the authenticated user, which enables regular .NET Framework authorization mechanisms to function.

Because HTTP is stateless, we need a way to avoid repeating this whole process every time that the user tries to access another protected resource. This is where the SessionAuthenticationModule comes in. When the STS issues a security token for the user, SessionAuthenticationModule also creates a session security token for the user and puts it in a cookie. On subsequent requests, the SessionAuthenticationModule intercepts this cookie and uses it to reconstruct the user’s ClaimsPrincipal.

From the SessionAuthenticationModule documentation:

The SAM adds its OnAuthenticateRequest event handler to the HttpApplication.AuthenticateRequest event in the ASP.NET pipeline. This handler intercepts sign-in requests, and, if there is a session cookie, deserializes it into a session token, and sets the Thread.CurrentPrincipal and HttpContext.User properties to the claims principal contained in the session token.

These modules are then configured by the system.identityModel and system.identityModel.services sections in web.config.

issuerNameRegistry and signing key refresh

This configures which tenants and issuers of authentication your application trusts as well as the thumbprint of their public signing key certificates.

The certificate thumbprints will¬†change over time¬†for security reasons so hardcoding the keys in web.config is not a good option hence you need to make sure to implement code that changes the keys for you. The simplest, built-in way to do that is using¬†ValidatingIssuerNameRegistry.WriteToConfig, which updates web.config for you automatically when it changes. That’s the instruction that was given in the last blog post.

Another option is to¬†store¬†the keys in a database, which is what the default code that Visual Studio’s Identity and Access Tools add (using EntityFramework). Yet another option is to store them in-memory and there is a class floating about that you can use to do that. Storing it in-memory is probably the nicest option.

Audiences and realm

The audienceUris configuration in web.config allows your application to control a list of identifiers that will be accepted for the scope of a presented authentication token (in Azure AD this maps to the App ID URI of your Azure AD application).

The realm attribute in the wsFederation element of the federationConfiguration in web.config tells the WSFederationAuthenticationModule to specify the WS Federation wtrealm to use for the request, which identifies the security realm that will be used for the request. For Azure AD this provides the App ID URI of the Azure AD application that should be used to service the authentication request. Thus, this value will generally be the same as the audience you configured unless you are doing multi-tenancy.

The difference between realm and audience is explained in this StackOverflow post.

securityTokenHandlers

A security token handler¬†provides a way for interpreting a security token of some sort into a Claims Principal for a given request. The code in the previous post gets you to remove the default handler¬†that takes care of looking at cookies in the request,¬†SessionSecurityTokenHandler, because it uses DPAPI to encrypt and decrypt the cookies and that doesn’t work in an environment with multiple web servers. Instead you are guided to add a¬†MachineKeySessionSecurityTokenHandler, which uses the machine key to encrypt and decrypt the cookie.

The configured securityTokenHandler will be what the SessionAuthenticationModule will make use of to store and retrieve the token from and to the cookie.

certificateValidation

On first thought, it might be confusing to see that certificate validation is turned off, but this is by design. The validating issuer name registry as explained above is a replacement for standard certificate validation. The only information that I’ve been able to find that explains this further is a post on the MSDN forums.

To illustrate what happens when you try using certificate validation, you can change certificateValidationMode to, say, ChainTrust and then you will get the following error:

The X.509 certificate CN=accounts.accesscontrol.windows.net chain building failed. The certificate that was used has a trust chain that cannot be verified. Replace the certificate or change the certificateValidationMode. A certificate chain processed, but terminated in a root certificate which is not trusted by the trust provider.

HTTPS

You can ensure that the security cookie is set to require SSL with the requireSSL attribute of the cookieHandler element in web.config and ensure that the authentication requests require a HTTPS connection with the requireHttps attribute of the wsFederation element in web.config.

In production environments it’s absolutely essential that you set both to true otherwise you are vulnerable to MITM attacks. You can set them to true locally if you use https with IIS Express or via a self-signed cert with IIS.

issuer

Setting this attribute on the wsFederation element in web.config determines where sign-in and sign-out requests are redirected.

passiveRedirectEnabled

Setting this attribute on the wsFederation element in web.config to true allows the WSFederationAuthenticationModule to automatically redirect the user to the authentication server in the event of a 401. Without this set to true you would need to explicitly call SignIn to log the user in.

reply

Setting this attribute on the wsFederation element in web.config¬†allows the application to control where the user is taken after they authenticate. The last post didn’t tell you to set it because by default it’s not required. When using Azure AD, in the instance that it’s not specified, the user will be redirected to the first Reply URL specified in the Azure AD application.

This requires that you can only have a one-to-one relationship between an Azure AD application and a web application requiring authentication. You can actually add multiple reply URLs to your Azure AD application though. This fact in combination with the reply attribute means that you can support multiple web applications (e.g. local, dev, staging, prod or even just different applications altogether) with the same Azure AD application. You just need to config transform your web.config file for each different environment as explained in this post.

If you are in a situation where you want to only change an app setting to control the reply URL (e.g. you are using VSO to deploy different branches to separate Azure Web Sites) then you can change the reply URL in code like so:

    public static class IdentityConfig
    {
        public static void ConfigureIdentity()
        {
            ...
            FederatedAuthentication.FederationConfigurationCreated += FederatedAuthentication_FederationConfigurationCreated;
        }

        ...

        private static void FederatedAuthentication_FederationConfigurationCreated(object sender, FederationConfigurationCreatedEventArgs e)
        {
            var federationConfiguration = new FederationConfiguration();
            federationConfiguration.WsFederationConfiguration.Reply =
                ConfigurationManager.AppSettings["AuthenticationReplyUrl"];
            e.FederationConfiguration = federationConfiguration;
        }
    }

Anti-forgery config

AntiForgeryConfig.UniqueClaimTypeIdentifier allows you to set which claim from the claims-based authentication token can be used to uniquely identify a user for the purposes of creating an appropriate anti-forgery token. Side note: this post about anti-forgery token is great. The claim that was shown in the last post is the correct one to use for Azure AD.

Logout

There are two parts to the logout code in the last post. Firstly, there is a call to the SessionAuthenticationModule, which will cause the cookie you have on the current site to be dropped by your browser. Secondly, there is a¬†redirect to a URL that the WS Federation code generates that will log you out of the source system (in this case your Azure AD session) and then redirect you back to a callback page with [AllowAnonymous] so they don’t get redirected back to login again straight away.

Announcing AspNet.Mvc.Grid

Whenever I need to display tables of data in an ASP.NET MVC application I end up pulling in the MVCContrib library to use its Grid Helper.

The Grid helper is really cool, it allows you to take a class like:

public class Person
{
    public int Id { get; set; }
    public string Name { get; set; }
    public string Email { get; set; }
    public DateTime DateOfBirth { get; set; }
}

And create a Razor view like the following (including appending some Bootstrap classes):

@model IEnumerable<Person>

<h1>Person List</h1>

@Html.Grid(Model).Columns(cb =>
{
    cb.For(p => Html.ActionLink(p.Name, "Detail", "People", new {p.Id}, null)).Named("Name");
    cb.For(p => p.Email);
    cb.For(p => p.DateOfBirth);

}).Attributes(@class => "table table-striped table-hover table-condensed").HeaderRowAttributes(new Dictionary<string, object> { { "class", "active" } })

This will then output HTML like the following:

<h1>Person List</h1>
<table class="table table-striped table-hover table-condensed">
   <thead>
      <tr class="active">
         <th>Name</th>
         <th>Email</th>
         <th>Date Of Birth</th>
      </tr>
   </thead>
   <tbody>
      <tr class="gridrow">
         <td><a href="/People/Detail/1">Name1</a></td>
         <td>Email1</td>
         <td>19/08/2014 12:00:00 AM</td>
      </tr>
      <tr class="gridrow_alternate">
         <td><a href="/People/Detail/2">Name2</a></td>
         <td>Email2</td>
         <td>20/08/2014 12:00:00 AM</td>
      </tr>
      <tr class="gridrow">
         <td><a href="/People/Detail/3">Name3</a></td>
         <td>Email3</td>
         <td>21/08/2014 12:00:00 AM</td>
      </tr>
   </tbody>
</table>

This means you don’t have to render out the nasty, tedious table HTML, it takes care of creating the thead and tbody for you, it’s type safe (thanks Razor!) and there are some sensible defaults that save you time (like inferring the th title from the property name).

The problem with MvcContrib

There is however a few big problems with MvcContrib – it’s not really kept very maintained¬†and it contains A LOT of bloat in there for stuff you will never need (and¬†frankly shouldn’t use).

To be honest, out of everything in there the Grid is the only thing I would touch.

It does actually have an MVC5 package, but it contains a reference to Mvc4Futures and this can actually have a really bad impact if you are using MVC5 due to one of the breaking changes in MVC5. If you have code that is assembly scanning the current AppDomain for instance then you will soon come across this error:

Inheritance security rules violated while overriding member: ‘Microsoft.Web.Mvc.CreditCardAttribute.GetClientValidationRules(System.Web.Mvc.ModelMetadata, System.Web.Mvc.ControllerContext)’. Security accessibility of the overriding method must match the security accessibility of the method being overriden.

Creating AspNet.Mvc.Grid

Given that roadblock on a current¬†project, and given I don’t really want to pull in all the bloat of MvcContrib I decided to¬†pull out the Grid code from MvcContrib and put it into it’s own library that targets .NET 4.5 and MVC 5. This is allowed under the Apache 2.0 license the MvcContrib code is licensed for.

Hence, I’d like to announce the AspNet.Mvc.Grid library! It has been published to NuGet as per usual.

The only difference you will notice between it and MvcContrib is that the namespaces are different. This was a conscious decision to make the library less confusing for completely new users.

Enjoy!

Authenticating an ASP.NET MVC 5 application with Microsoft Azure Active Directory

This post outlines how to easily add Azure AD authentication to an existing (or new) ASP.NET MVC 5 (or 3 or 4) application.

Practical Microsoft Azure Active Directory Blog Series

This post is part of the Practical Microsoft Azure Active Directory Blog Series.

Add Azure AD Authentication

These instructions will help you¬†easily add authentication to your new or existing ASP.NET application, based on what the Visual Studio Identity and Access tools do. It’s a basic setup for a single tenant. Read the next post in the series to understand what’s going on and ways that it can be extended. The links show either a commit from the example project or to relevant documentation.

Note: Ignore the ...‘s and replace the {SPECIFIED_VALUES} with the correct values.

  1. Create an Azure Active Directory tenant; note: AD tenants are not associated with your Azure Subscription, they are “floating” so add any live ids for people you want to administer it as Global Administrators
  2. Create an Application in your AD tenant with audience URL and realm being your website homepage (minus the slash at the end)
    • Record the name of your AD tenant e.g. {name}.onmicrosoft.com
    • Record the GUID of your AD tenant by¬†looking at the¬†FEDERATION METADATA DOCUMENT URL under View Endpoints
    • The image upload and Sign On URL are used for the Azure AD Applications Portal
  3. Create a user account in your tenant that you can use to log in with
  4. Install-Package Microsoft.Owin.Security.ActiveDirectory
  5. Install-Package System.IdentityModel.Tokens.ValidatingIssuerNameRegistry
  6. Add a reference to System.IdentityModel
  7. Add a reference to System.IdentityModel.Services
  8. Add a Startup.cs file (if it doesn’t already exist) and configure OWIN to use Azure Active Directory¬†(edit for new version)
    using System.Configuration;
    using Microsoft.Owin.Security.ActiveDirectory;
    using Owin;
    
    namespace {YOUR_NAMESPACE}
    {
        public class Startup
        {
            public void Configuration(IAppBuilder app)
            {
                app.UseWindowsAzureActiveDirectoryBearerAuthentication(
                    new WindowsAzureActiveDirectoryBearerAuthenticationOptions
                    {
                        TokenValidationParameters = new TokenValidationParameters
                        {
                            ValidAudience = ConfigurationManager.AppSettings["ida:AudienceUri"]
                        },
                        Tenant = ConfigurationManager.AppSettings["AzureADTenant"]
                    });
            }
        }
    }
    
  9. Add the correct configuration to your web.config file; change requireSsl and requireHttps to true if using a https:// site (absolutely required for production scenarios)
    <?xml version="1.0" encoding="utf-8"?>
    <configuration>
      <configSections>
        <section name="system.identityModel" type="System.IdentityModel.Configuration.SystemIdentityModelSection, System.IdentityModel, Version=4.0.0.0, Culture=neutral, PublicKeyToken=B77A5C561934E089" />
        <section name="system.identityModel.services" type="System.IdentityModel.Services.Configuration.SystemIdentityModelServicesSection, System.IdentityModel.Services, Version=4.0.0.0, Culture=neutral, PublicKeyToken=B77A5C561934E089" />
      </configSections>
    ...
      <appSettings>
        ...
        <add key="ida:AudienceUri" value="{YOUR_WEBSITE_HOMEPAGE_WITHOUT_TRAILING_SLASH}" />
        <add key="ida:FederationMetadataLocation" value="https://login.windows.net/{YOUR_AD_TENANT_NAME}.onmicrosoft.com/FederationMetadata/2007-06/FederationMetadata.xml" />
        <add key="AzureADTenant" value="{YOUR_AD_TENANT_NAME}.onmicrosoft.com" />
      </appSettings>
    ...
      <system.webServer>
        ...
        <modules>
          <add name="WSFederationAuthenticationModule" type="System.IdentityModel.Services.WSFederationAuthenticationModule, System.IdentityModel.Services, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" preCondition="managedHandler" />
          <add name="SessionAuthenticationModule" type="System.IdentityModel.Services.SessionAuthenticationModule, System.IdentityModel.Services, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" preCondition="managedHandler" />
        </modules>
      </system.webServer>
    ...
      <system.identityModel>
        <identityConfiguration>
          <issuerNameRegistry type="System.IdentityModel.Tokens.ValidatingIssuerNameRegistry, System.IdentityModel.Tokens.ValidatingIssuerNameRegistry">
            <authority name="https://sts.windows.net/{YOUR_AD_TENANT_GUID}/">
              <keys>
                <add thumbprint="0000000000000000000000000000000000000000" />
              </keys>
              <validIssuers>
                <add name="https://sts.windows.net/{YOUR_AD_TENANT_GUID}/" />
              </validIssuers>
            </authority>
          </issuerNameRegistry>
          <audienceUris>
            <add value="{YOUR_WEBSITE_HOMEPAGE_WITHOUT_TRAILING_SLASH}" />
          </audienceUris>
          <securityTokenHandlers>
            <add type="System.IdentityModel.Services.Tokens.MachineKeySessionSecurityTokenHandler, System.IdentityModel.Services, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
            <remove type="System.IdentityModel.Tokens.SessionSecurityTokenHandler, System.IdentityModel, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
          </securityTokenHandlers>
          <certificateValidation certificateValidationMode="None" />
        </identityConfiguration>
      </system.identityModel>
      <system.identityModel.services>
        <federationConfiguration>
          <cookieHandler requireSsl="false" />
          <wsFederation passiveRedirectEnabled="true" issuer="https://login.windows.net/{YOUR_AD_TENANT_NAME}.onmicrosoft.com/wsfed" realm="{YOUR_WEBSITE_HOMEPAGE_WITHOUT_TRAILING_SLASH}" requireHttps="false" />
        </federationConfiguration>
      </system.identityModel.services>
    </configuration>
    
  10. Configure AntiForgery to use the correct claim type to uniquely identify users
    Global.asax.cs
    
              protected void Application_Start()
              {
                  ...
                  IdentityConfig.ConfigureIdentity();
              }
    
    App_Start\IdentityConfig.cs
    
    using System.IdentityModel.Claims;
    using System.Web.Helpers;
    
    namespace {YOUR_NAMESPACE}
    {
        public static class IdentityConfig
        {
            public static void ConfigureIdentity()
            {
                AntiForgeryConfig.UniqueClaimTypeIdentifier = ClaimTypes.Name;
            }
        }
    }
    
  11. Configure the application to refresh issuer keys when they change
            public static void ConfigureIdentity()
            {
                ...
                RefreshIssuerKeys();
            }
    
            private static void RefreshIssuerKeys()
            {
                // http://msdn.microsoft.com/en-us/library/azure/dn641920.aspx
                var configPath = AppDomain.CurrentDomain.BaseDirectory + "\\" + "Web.config";
                var metadataAddress = ConfigurationManager.AppSettings["ida:FederationMetadataLocation"];
                ValidatingIssuerNameRegistry.WriteToConfig(metadataAddress, configPath);
            }
    
  12. Add LogoutController
    Controllers\LogoutController.cs
    
    using System;
    using System.IdentityModel.Services;
    using System.Web.Mvc;
    
    namespace {YOUR_NAMESPACE}.Controllers
    {
        public class LogoutController : Controller
        {
            public ActionResult Index()
            {
                var config = FederatedAuthentication.FederationConfiguration.WsFederationConfiguration;
    
                var callbackUrl = Url.Action("Callback", "Logout", null, Request.Url.Scheme);
                var signoutMessage = new SignOutRequestMessage(new Uri(config.Issuer), callbackUrl);
                signoutMessage.SetParameter("wtrealm", config.Realm);
                FederatedAuthentication.SessionAuthenticationModule.SignOut();
    
                return new RedirectResult(signoutMessage.WriteQueryString());
            }
    
            [AllowAnonymous]
            public ActionResult Callback()
            {
                if (Request.IsAuthenticated)
                    return RedirectToAction("Index", "Home");
    
                return View();
            }
        }
    }
    
    Views\Logout\Callback.cshtml
    
    @{
        ViewBag.Title = "Logged out";
    }
    
    <h1>Logged out</h1>
    
    <p>You have successfully logged out of this site. @Html.ActionLink("Log back in", "Index", "Home").</p>
    
  13. Add logout link somewhere@Html.ActionLink("Logout", "Index", "Logout")
  14. Add authentication to the app; do this as you normally would with [Authorize] to specific controller(s) or action(s) or globally by adding to GlobalFilters.Filters.Add(new AuthorizeAttribute());
  15. Load the site and navigate to one of the authenticated pages – it should redirect you to your Azure AD tenant login page whereupon you need to log in as one of the users you created and it should take you back to that page, logged in
  16. The usual User.Identity.Name and User.Identity.IsAuthenticated objects should be populated and if you want access to the claims to get the user’s name etc. then use something like ClaimsPrincipal.Current.FindFirst(ClaimTypes.GivenName).Value

Practical Microsoft Azure Active Directory Blog Series

I finally had a chance to play with Microsoft Azure Active Directory in a recent project. I found the experience to be very interesting – Azure AD itself is an amazing, powerful product with a lot of potential. It certainly has a few rough edges here and there, but it’s pretty clear Microsoft are putting a lot of effort into it as it’s forming the cornerstone of how it authenticates all of it’s services including Office 365.

Azure AD gives you the ability to securely manage a set of users and also gives the added benefit of allowing two-factor authentication (2FA), single-sign-on across applications, multi-tenancy support and ability to allow external organisations to authenticate against your application.

This blog series will outline the minimum set of steps that you need to perform to quickly and easily add Azure AD authentication to an existing ASP.NET MVC 5 (or 3 or 4) site (or a new one if you select the No Authentication option when creating it) as well as configure things like API authentication, role authorisation, programmatic logins and deployments to different environments.

There are already tools and libraries out there for this – why are you writing this series?

Microsoft have made it fairly easy to integrate Azure AD authentication with your applications by providing NuGet packages with most of the code you need and also tooling support to configure your project in Visual Studio. This is combined with a slew of MSDN and technet posts covering most of it.

When it comes to trying to understand the code that is added to your solution however, things become a bit tricky as the documentation is hard to navigate through unless you want to spend a lot of time. Also, if you have Visual Studio 2013 rather than Visual Studio 2012 you can only add authentication to a new app as part of the File -> New Project workflow by choosing the Organizational Authentication option:

ASP.NET Organizational Authentication option
Visual Studio: File > New Project > ASP.NET > Change Authentication > Organizational Authentication

If you have an existing ASP.NET web application and you are using Visual Studio 2013 then you are out of luck.

Furthermore, the default code you get requires you to have Entity Framework and a database set up, despite the fact this is only really required if you are using multiple Azure AD tenants (unlikely unless you are creating a fairly hardcore multi-tenant application).

If you then want to add role-based authentication based on membership in Azure AD groups then there is no direction for this either.

For these reasons I’m developing a reference application that contains the simplest possible implementation of adding these¬†features in an easy to follow commit-by-commit manner as a quick reference. I will also provide explanations of what all the code means in this blog series so you can understand how it all works if you want to.

You can see the source code of this application here and an example deployment here. The GitHub page outlines information such as example user logins and what infrastructure I set up in Azure.

What are you planning on covering?

This will be the rough structure of the posts I am planning in no particular order (I’ll update this list with links to the posts over time):

I’m notoriously bad at finishing blog series‘ that I start, so no promises on when I will complete this, but I have all of the code¬†figured out in one way or another and the GitHub should at least contain commits with all of the above before I finish the accompanying posts so *fingers crossed*! Feel free to comment below if you want me to expedite a particular post.

More resources

I came across some great posts that have helped me so far so I thought I’d link to them here to provide further reading if you are interested in digging deeper:

ChameleonForms 1.0 Released

I’m incredibly excited and proud to finally announce the release of 1.0 of the ChameleonForms library I’ve been working on with Matt Davies. My blog has been fairly quiet the last couple of months while I’ve poured time and energy in finally getting ChameleonForms to 1.0.

WOOOOOOOOOOOOOOOO

(Apologies; I’m releasing months of built-up anticipation and excitement here).

I’m biased of course, but I think this library is amazing to use and results in immensely more maintainable form generation code when using ASP.NET MVC. It extends on the knowledge that MVC developers would have in generating forms using the (already pretty awesome) built-in stuff, but adds the things I think are missing. For me, this library epitomises over 7 years of exploration in the best way to do web-based forms and I’m excited to be able to share the beginnings of my current vision via this library.

What is ChameleonForms?

In short, ChameleonForms takes away the pain and repetition of building forms with ASP.NET MVC by following a philosophy of:

  • Model-driven¬†defaults (e.g. enum is drop-down,¬†[DataType(DataType.Password)]¬†is password textbox)
  • DRY¬†up your forms – your forms will be quicker to write and easier to maintain and you won’t get stuck writing the same form boilerplate markup form after form after form
  • Consistent¬†– consistency of the API and form structure within your forms and consistency across all forms in your site via templating
  • Declarative¬†syntax – specify how the form is structured rather than worrying about the boilerplate HTML markup of the form; this has the same beneficial effect as separating HTML markup and CSS
  • Beautiful, terse, fluent APIs¬†– it’s a pleasure to read and write the code
  • Extensible and flexible¬†core – you can extend or completely change anything you want at any layer of ChameleonForms and you can drop out to plain HTML at any point in your form for those moments where pre-prepared field types and templates just don’t cut it

More info.

What are the big improvements in 1.0?

We’ve been releasing pretty often so that depends on what version you are currently using, but these are the most important things:

  • Extensive usage across a number of production websites – we are happy that this library is mature, stable and ready for prime-time
  • Twitter Bootstrap 3 Template out-of-the-box supported by a NuGet package to get you up and running faster – this is HUGE for a number of reasons:
    • Bootstrap is pretty darn popular right now so this is immediately useful to a lot of people
    • In creating this template we had to do some pretty sophisticated changes to allow the template to drive a lot of changes unobtrusively to the form structure you are adding in your views – this is great because it means it’s really easy for you to create your own form templates and accomplish similarly complex transformations of your form markup
    • The ASP.NET MVC templates that come with Visual Studio 2013 come with Bootstrap by default now – and boy do they have gross repetitive boilerplate in them, which you can clean right up using this library
    • The vision that we have for this library is coming to fruition, which is personally gratifying – this is a beautiful demonstration of being able to declaratively specify the structure of your form and then completely change the markup/template of your form across a whole application with a single line of code when it changes
  • Really comprehensive documentation of everything in the library – we’ve spent many hours writing up the documentation – the idea was to make it comprehensive, but accessible/terse; hopefully we’ve met that goal!
  • Really solid code coverage to help prevent regressions or breaking changes as well as some refactorings that give us a solid codebase to continue with the other features we want to add – hopefully this can support us into the future with minimal breaking changes

How can I get it?

Checkout the GitHub release or go to NuGet.

Versioning

From this point on we are following semver thanks to the GitHubFlowVersion project. The fourth number in the NuGet version number is actually build metadata.

Borderlands 2 here I come!

Over a year ago now (yes it’s been a long journey – our first NuGet package was published on November 1, 2012) Matt Davies and I made an agreement to each other that neither of us would play the recently released Borderlands 2 game (we were both huge fans of Borderlands so this was a big deal) until we released 1.0 of ChameleonForms so that we would remain focussed on it and not get distracted. Now, while we both didn’t realise that it would take this long and while the last couple of months have seemed like forever (I’m pretty sure we had a phone conversation at least once a week where one of us would say “dude, we are sooooo close to 1.0 and BORDERLANDS 2!”) we are both incredibly proud of the library and are happy with what we’ve managed to get into 1.0.

Needless to say, we will probably be taking a break from open source for a few weekends to play Borderlands 2 ūüôā

We hope you enjoy using the library!

As usual hit us up with issues and pull requests on GitHub – they make our day ūüôā

Resolving request-scoped objects into a singleton with Autofac

This week I had an issue raised on my Github site for examples of unobtrusive validation with ASP.NET MVC. The person that raised the issue was having a problem where they wanted their fluent validation modules to be singleton, but they wanted to inject a factory that can be invoked to return a request-scoped object (in this case some sort of database store). Inevitably they came across the “No scope with a Tag matching ‘AutofacWebRequest’ is visible from the scope in which the instance was requested” error.

I’ve blogged previously about a technique for using DependencyResolver.Current and being able to unit test it for similar situations. It’s not a great solution, but it does work and at least it can be unit tested.

Low and behold though, thanks to the power of the Internet, the person that raised the issue asked a question on StackOverflow and got a really elegant solution for how to inject factories in a singleton that will correctly resolve request-scoped objects. I’m pretty excited about it so I thought I’d give it more exposure by doing this blog post.

This is the technique in all it’s glory (I’ve renamed the method name slightly to make it more readable):

public Func<T> HttpRequestScopedFactoryFor<T>()
{
    return () => DependencyResolver.Current.GetService<T>();
}

...

builder.RegisterType<SomeRequestScopedComponent>().As<ISomeRequestScopedComponent>().InstancePerHttpRequest();
builder.RegisterInstance(HttpRequestScopedFactoryFor<ISomeRequestScopedComponent>()); // this is the magic bit

This will then allow you to do something like this:

builder.RegisterType<SomeSingletonType>().As<ISomeSingletonType>().SingleInstance();

...

public class SomeSingletonType
{
    private readonly Func<ISomeRequestScopedComponent> _someRequestScopedComponentFactory;

    public SomeSingletonType(Func<ISomeRequestScopedComponent> someRequestScopedComponentFactory())
    {
        _someRequestScopedComponentFactory = someRequestScopedComponentFactory;
    }

    public void SomeMethod() {
        var requestScopedComponent = _requestScopedComponentFactory();
        ...
    }
}

Nice and even easier to unit test than using DependencyResolver.Current directly!

Big thanks to @thardy and @felix.

Automated Testing of ASP.NET Web API and MVC applications

Yesterday I started working on my first professional usage of ASP.NET Web API and as part of that created a handy base class to perform full-stack unit and/or integration testing of controller actions in-process. It was based on some stuff I found online, but put my own flair on so I thought I would share it here in case anyone else found it useful. While I’m at it I thought I’d briefly outline my testing strategy for most MVC applications I write.

ASP.NET MVC Testing

When I’m testing an ASP.NET MVC application I have had good mileage with covering the following (this is a combination of what you might consider to be integration and unit tests):

  • Routes: Typically you aren’t going to change the URLs in your application (because then you would be dealing with potential search engine optimisation and bookmarking issues) so if they do change it’s a good indication that (in an MVC application) you’ve added a new route definition that has broken some existing definitions. I will typically test the URLs for all controller actions (including mapping route values to action input parameters) and test that calling Url.Route with the same parameters results in the same route being generated. This kind of testing has saved my bacon many times in the past and it is quick and effective to write the tests whenever adding a new controller action using the code I use (a version of MVCContrib.TestHelper that I modified to use NSubstitute). It’s particularly handy when you have areas in your application because they have a nasty tendency of breaking your routes.
  • Controllers: If any particular controller action is more than a few lines of code (and thus it isn’t¬†bleedingly¬†obviously that it’s either correct or not correct just by looking at it), then like all complex business logic I try and unit test the controllers. I do this using the Fluent MVC Testing library that I created because it’s terse and easy to write these tests.
  • Controller Instantiation: As previously blogged.
  • Filters, Filter Providers and Model Binders: I will typically unit test these, for an example see my previous post about unit testing filter providers.
  • UI Testing: If the circumstances of the project allow for it then well-placed full-stack tests provide a lot of extra confidence. My fellow TestStacker Mehdi Khalili has a brilliant slide deck on this.
  • Database Layer: I perform tests against individual queries / commands / repository methods by doing a full integration test against a real database and wrapping the whole thing in a Transaction Scope so I can roll-back any changes in the test teardown. This ensures the test database always remains clean (read: empty) and each test can work in isolation.
  • Database migrations: I like to include one test that brings the test database to version 0 and then back up to the latest version so that if you ever need to use your down migrations then you have confidence they work (as well as continuing confidence that all of your up migrations work).
  • Business logic / services / domain logic: I will always unit test this
  • Infrastructure code: Where practical I try and unit test this. Sometimes this code is tested as a result of other tests e.g. the database tests and controller instantiation tests

If there are any particular types of testing that you would like me to do a more detailed blog post feel free to add a comment below.

ASP.NET Web API

The tests above have a nice mixture of unit and integrations tests and I find that they combine to provide a good level of confidence and coverage as the codebase evolves. I have only really played around with Web API in my spare time so far so the following recommendations are likely to evolve over time, but this is my current gut feel about this kind of testing.

Firstly, there are a few good posts I came across that give a broad idea of the different ways in which you can test Web API:

And then my initial approach / thoughts:

  • Routes:The other day I stumbled across a library someone had created to do route testing for ASP.NET Web API and while I’m not a fan of the syntax they created (vs MVCContrib.TestHelper style syntax) it’s a good start in this direction. For the moment I’m thinking (as you will see) that I can take care of route testing implicitly. Furthermore, at least for my current project, the number of routes I’m dealing with doesn’t necessitate route testing. If the routes that you deal with are complex enough and or large enough in number then unit testing routes will likely provide a lot of value.
    Controllers:¬†There is less need for a library like Fluent MVC Testing with Web API since most of your controllers will simply return the data that they queried directly and rely on formatters to give the correct response. This makes unit testing the controllers really simple. As for route testing the initial approach I’ve settled on will cover this testing anyway.
  • Controller Instantiation: For the same reason this is valuable for ASP.NET MVC projects I think this is valuable (and just as easy to test). In my current project I haven’t bothered creating this yet since I’m only dealing with one controller with a couple of dependencies so I don’t have any code for this.
  • Filters, etc.: I think there is value in unit testing these things in the same way as there is for MVC applications. In this instance the approach I’ve settled on tests these as well because it’s a full stack test. This is fine for simple filters / formatters etc., but if you have complex ones then I highly recommend unit testing them as well.
  • UI Testing: This one is interesting, because at first thought there is no UI to test so this isn’t applicable. However, the way I see it, the equivalent in API tests are testing from the viewpoint of the client/consumer e.g. if I make a get request to this URL then I expect that object in JSON format. If you are producing an API according to a specification then this is the viewpoint the specification is written in and depending on how you do things, the acceptance criteria for the work you are doing will also be in terms of this. For these reasons, I think in some ways, while it is integration testing, testing the full stack from the viewpoint of a client provides a lot of bang for buck. As I will explain further below, this is the approach I have decided to initially take. I should note that the traditional pain points of UI testing for MVC applications (cross-browser differences, really slow, out of process so you can’t easily mock things, etc.) can easily be mitigated when doing this testing, which is why I find it a suitable approach in lieu of some of the other testing I might normally do.
  • Database / business logic / infrastructure: None of this changes.

The approach I’ve taken for Web API testing

This is heavily based on the ASP.Net Web Api Integration Tests With Self Hosting post I linked to above. The problems I had with the code shown in that post was:

  • The route was defined in the test rather than re-using the routes you define in your application
  • The test itself is defined within a lamdba
  • There was no abstraction of the code to set up the server
  • The base URL was specified multiple times
  • The test was really verbose (apart from not abstracting out the server it had a stream reader and WebRequest.Create etc.)

In the end I created a base class (using NUnit, but the same applies to any unit testing framework) that abstracted away the creation of the server as well as the HTTP call. This resulted in tests that were dead simple and very terse (for the moment there is only a get request, but you can easily add other methods and headers etc.). I also exposed the dependency injection so that I could insert mocks to control whether I want to unit test the controller action or integration test it with real dependencies. In this case it uses Autofac, but again the same applies for any DI framework.

Another thing to note is that I’ve baked in support for detecting if Fiddler is currently running and proxying requests through Fiddler in that instance. That way you can seemlessly move your test between your local computer (with or without Fiddler running) and your CI server without changing any code. The fact it proxies through Fiddler makes it really easy to debug exactly what is going on too.

Two other things to note are that you need to change PingController to a controller (or any class really) in the assembly that contains your API controllers and that this assumes you have created a static method inside the RouteConfig class called RegisterApiRoutes that defines the routes for your API.

using System;
using System.Net.Http;
using System.Web.Http.SelfHost;
using Autofac;
using Autofac.Integration.WebApi;
using NUnit.Framework;
using WebApiTesting.App_Start;
using WebApiTesting.Controllers;

namespace WebApiTesting.Tests.TestHelpers
{
    class WebApiTestBase
    {
        private HttpSelfHostServer _webServer;
        protected IContainer Container { get; private set; }
        protected ContainerBuilder ContainerBuilder { get; set; }
        protected Uri BaseUri { get; private set; }

        private bool _fiddlerActive = true;

        [TestFixtureSetUp]
        public void TestFixtureSetup()
        {
            var client = new HttpClient();
            try
            {
                client.GetAsync("http://ipv4.fiddler/").Wait();
            }
            catch (Exception)
            {
                _fiddlerActive = false;
            }
        }

        [SetUp]
        public virtual void Setup()
        {
            BaseUri = new Uri("http://localhost:3000");
            var config = new HttpSelfHostConfiguration(BaseUri);

            ContainerBuilder = ContainerBuilder ?? new ContainerBuilder();
            ContainerBuilder.RegisterApiControllers(typeof(PingController).Assembly);
            Container = ContainerBuilder.Build();

            RouteConfig.RegisterApiRoutes(config);
            config.DependencyResolver = new AutofacWebApiDependencyResolver(Container);

            _webServer = new HttpSelfHostServer(config);
            _webServer.OpenAsync().Wait();
        }

        protected HttpResponse PerformGetTo(string url)
        {
            var client = new HttpClient();
            var response = client.GetAsync((_fiddlerActive ? "http://ipv4.fiddler:3000/" : BaseUri.ToString()) + url).Result;
            var content = response.Content.ReadAsStringAsync().Result;

            return new HttpResponse { Content = content, Response = response };
        }

        [TearDown]
        public void Teardown()
        {
            _webServer.CloseAsync().Wait();
            _webServer.Dispose();
            Container.Dispose();
            ContainerBuilder = null;
            Container = null;
        }
    }

    class HttpResponse
    {
        public string Content { get; set; }
        public HttpResponseMessage Response { get; set; }
    }
}

So, how exactly do you use this class? Great question, but first a bit of context. My example will be for a endpoint at /api/ping that takes a GET request and returns the UTC system time in ISO format within an object with a property “Timestamp” along with a 200 OK if the database is up and running or a blank response with a 500 error if the database is not up and running.

Here is my test class:

using System;
using System.Net;
using Autofac;
using NSubstitute;
using NUnit.Framework;
using WebApiTesting.Infrastructure;
using WebApiTesting.Tests.TestHelpers;

namespace WebApiTesting.Tests.Controllers
{
    internal class PingControllerTests : WebApiTestBase
    {
        private IDateTimeProvider _dateTimeProvider;
        private IPingRepository _pingRepository;

        [SetUp]
        public override void Setup()
        {
            ContainerBuilder = new ContainerBuilder();
            _dateTimeProvider = Substitute.For<IDateTimeProvider>();
            _pingRepository = Substitute.For<IPingRepository>();
            ContainerBuilder.Register(c => _dateTimeProvider);
            ContainerBuilder.Register(c => _pingRepository);
            base.Setup();
        }

        [Test]
        public void GivenTheDatabaseIsUpAndRunning_WhenGetToPing_ReturnCurrentTimestampAnd200Ok()
        {
            _dateTimeProvider.Now().Returns(new DateTimeOffset(new DateTime(2012, 11, 4, 12, 20, 6), TimeSpan.Zero));

            var response = PerformGetTo("api/ping");

            Assert.That(response.Response.StatusCode, Is.EqualTo(HttpStatusCode.OK));
            Assert.That(response.Content, Is.EqualTo(@"{""Timestamp"":""2012-11-04 12:20:06""}"));
        }

        [Test]
        public void GivenTheDatabaseIsNotRunning_WhenGetToPing_Return500ErrorWithNoContent()
        {
            _pingRepository.When(r => r.CheckDatabase()).Do(a => { throw new Exception(); });

            var response = PerformGetTo("api/ping");

            Assert.That(response.Response.StatusCode, Is.EqualTo(HttpStatusCode.InternalServerError));
            Assert.That(response.Content, Is.EqualTo(string.Empty));
        }
    }
}

There are a few things to note:

  • To register the listener to the port you need to run Visual Studio (and your CI test runner) as admin otherwise you will get a could not register port error.
  • I used port 3000, but if you are running as admin and get an error saying that port can’t be registered it then you might have something else on that port so feel free to change.
  • Unfortunately I couldn’t make use of AutoSubstitute, but unfortunately that broke the HTTP server (I imagine because it was giving mocks for things that the server needed real stuff for). The downside of this is that I have to keep track of the dependencies of the controller within the test making the test more verbose.
  • Because I need the container builder before starting up the web server I have to create the container builder in the setup method and register everything that I need to mock for any of the tests there, rather than setting up what needs to be mocked in each individual test.
  • I am setting up and shutting down the web server for each test to isolate them, but if there are a lot of tests this might be too slow and attaching start up to fixture setup or even test assembly set up might be a better option.
  • As mentioned above for now there is only a PerformGetTo method, but it would be easy to support the other things needed.

I’ve uploaded the example source code to Github. Feel free to fork it and play around. If you have any suggestions or improvements feel free to add a comment ūüôā

Enjoy!