Thinktecture IdentityModel with ASP.NET Web Api

I’m writing this post as a reminder to myself on how to fix the following error message …

Attempted to access an element as a type incompatible with the array

… when firing up a Web Api project which is using Thinktecture IdentityModel.

My initialisation code looks like this …

                    var authenticationConfig = CreateAuthenticationConfiguration();
                    var handler = new AuthenticationHandler(authenticationConfig);
                    configuration.MessageHandlers.Add(handler);

The problem is caused by the wrong version of the System.Net.Http being used. The solution is to remove the bindingRedirect you see below.

<?xml version="1.0" encoding="utf-8"?>
<configuration>
  <runtime>
    <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
      <dependentAssembly>
        <assemblyIdentity name="System.Net.Http" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
        <bindingRedirect oldVersion="0.0.0.0-2.0.0.0" newVersion="2.0.0.0" />
      </dependentAssembly>
    </assemblyBinding>
  </runtime>
</configuration>

Note to future me: You will eventually remember this without having to come and look at this blog post!

I’m all Moq’d out!

I’m currently working on creating a Hypermedia API, or at least getting as close as I can to one!

In order to avoid the client hitting a dead end when an error occurs, either internally within my code or as a result of a bad request from the client, I wanted to provide links that the client can follow. So, I created an ApiError model class to send in my response in such a case.

    [Hypermedia]
    public class ApiError : Resource
    {
        public string ParentId { get; set; }
        public string ErrorMessage { get; set; }
    }

The [Hypermedia] attribute is just a place holder I use within my Delegating Handler which “enriches” the resources with links. The ParentId is the id used in order to construct links to the home resource and it’s also used for constructing self links and so on.

The links are generated by way of Mark Seamann’s excellent HyprLinkr library, available via Nuget (http://nuget.org/packages/Hyprlinkr/).

My first attempt was to create an extension method to create the response, much like the built in HttpRequestMessage.CreateErrorResponse extension method. This worked great when I tested it using my current favourite chrome extension, POSTman. It returned the error, along with a “back” and “home” link so the client didn’t just hit a dead-end.

For example …

  "errorMessage" : "The was an error, run for the hills!",
  "_links" :
  [
    {
      "rel" : "home",
      "href" : "http://server/api/home/someone@example.com",
      "title" : "home",
      "verb" : "GET"
    }
  ]

So, all is well. I’m a happy bunny….

Until I run my unit tests.

What The Flip?

Why is there red everywhere?!

As it turns out I wrote some legacy (read: un-testable) code. Here’s what I’d come up with …

    public static class HttpRequestMessageExtensions
    {
        public static HttpResponseMessage CreateErrorResponse(
            this HttpRequestMessage request,
            HttpStatusCode statusCode,
            string parentId,
            string errorMessage,
            Action<IResourceLinker, ApiError> addLinks)
        {
            var apiError = new ApiError
            {
                ParentId = parentId,
                ErrorMessage = errorMessage
            };

            if (addLinks != null)
            {
                var routeLinker = _resourceLinkerFactory.GetResourceLinker(request);
                addLinks(routeLinker, apiError);
            }

            return request.CreateResponse(statusCode, apiError);
        }

After spending some time in the debugger trying to figure out why I was getting a null reference exception, I started looking at Mark’s code on github and eventually figured out that the GetRouteData() call was returning null. So, I spent more time trying to figure out a way of getting that to *not* be null. I ended up getting the source code for the aspnetwebstack from codeplex and looking at the code for GetRouteData().

Veering off-topic slightly, I didn’t have git installed on my pc, so I fired up powershell and …

  PS> cinst git

… I used chocolately to install it, restarted powershell and …

  PS> git clone https://git01.codeplex.com/aspnetwebstack

… I was rummaging around the asp.net web stack code 😀

Back on to topic …

After a few failed attempts at getting the null reference to go away it dawned on me that with another layer or two or abstraction I could Moq (on nuget too – https://www.nuget.org/packages/moq) my way out of trouble.

So, thinking about it for a little while I came up with a way of doing all this so I could moq it. Firstly I needed to change CreateApiErrorResponse from an extension method into a “service”, which I could then pass into the relevant controllers. Once I get past the unit test stage I could easily set it up using Castle Windsor. I would also need an IResourceLinker factory.

The Service

    public interface IHttpRequestMessageService
    {
        HttpResponseMessage CreateErrorResponse(
            HttpRequestMessage request,
            HttpStatusCode statusCode,
            string parentId,
            string errorMessage,
            Action<IResourceLinker, ApiError> addLinks);
    }

    public class HttpRequestMessageService : IHttpRequestMessageService
    {
        private readonly IResourceLinkerFactory _resourceLinkerFactory;

        public HttpRequestMessageService(IResourceLinkerFactory resourceLinkerFactory)
        {
            _resourceLinkerFactory = resourceLinkerFactory;
        }

        public HttpResponseMessage CreateErrorResponse(
            HttpRequestMessage request,
            HttpStatusCode statusCode,
            string parentId,
            string errorMessage,
            Action<IResourceLinker, ApiError> addLinks)
        {
            var apiError = new ApiError
            {
                ParentId = parentId,
                ErrorMessage = errorMessage
            };

            if (addLinks != null)
            {
                var routeLinker = _resourceLinkerFactory.GetResourceLinker(request);
                addLinks(routeLinker, apiError);
            }

            return request.CreateResponse(statusCode, apiError);
        }
    }

The Factory

    public interface IResourceLinkerFactory
    {
        IResourceLinker GetResourceLinker(HttpRequestMessage request);
    }

    public class ResourceLinkerFactory : IResourceLinkerFactory
    {
        public IResourceLinker GetResourceLinker(HttpRequestMessage request)
        {
            return new RouteLinker(request, new AttributeBasedRouteDispatcher());
        }
    }

Once I sorted out a few built errors it was time to do some Moqing…

    public class MyControllerTests
    {
        private Mock<IResourceLinkerFactory> _mockResourceLinkerFactory;
        private Mock<IResourceLinker> _mockResourceLinker;
        private IHttpRequestMessageService _httpRequestMessageService;
        private MyController _controller;

        [SetUp]
        public void SetUp()
        {
            const string id = "john.doe@example.com";

            var config = new HttpConfiguration();
            var request = new HttpRequestMessage(HttpMethod.Post, string.Format("http://localhost/api/user/{0}", id));

            _mockResourceLinkerFactory = new Mock<IResourceLinkerFactory>();
            _mockResourceLinker = new Mock<IResourceLinker>();
            _httpRequestMessageService = new HttpRequestMessageService(_mockResourceLinkerFactory.Object);

            _mockResourceLinkerFactory.Setup(x => x.GetResourceLinker(It.IsAny<HttpRequestMessage>()))
                                      .Returns(_mockResourceLinker.Object);

            _mockResourceLinker.Setup(x => x.GetUri(It.IsAny<Expression<Action<MyController>>>()))
                           .Returns(new Uri(string.Format("http://localhost/api/user/{0}", id)));

            _controller = new MyController(_httpRequestMessageService);
        }
    }

Hurrah! It all worked and I could get back to testing what I was actually trying to, which was unrelated to providing links when sending errors to the client. But, I needed this anyway 😀

Since the tests I was working on weren’t testing the presence of the links, I suppose I could have done something like this …

    var _mockHttpRequestMessageService = new Mock<IHttpRequestMessageService>();
    _mockHttpRequestMessageService
        .Setup(x => x.CreateErrorResponse(
            It.IsAny<HttpRequestMessage>(),
            It.IsAny<HttpStatusCode>(),
            It.IsAny<string>(),
            It.IsAny<string>(),
            It.IsAny<Action<IResourceLinker, ApiError>>())
        .Returns(new HttpResponseMessage(...));

Anyway, I hope that helps someone out. It’ll probably be me at some point in the future as my memory is not the best 😉

Hosting ASP.NET Web Api with IIS

I spent the whole of today trying to figure out why IIS on our servers behaved differently from my local IIS and IIS Express when hosting my ASP.NET Web Api.

I have a ValidationActionFilter class which uses Data Annotations. For some reason it wasn’t returning the validation error messages in the response body when hosted on our IIS servers. However, it worked perfectly on both IIS Express and IIS locally.

After a process of elimination we boiled it down to being an issue with the web server itself. A little googling later and we found this post.

So, it turns out that IIS needs a little configuration to allow your HTTP status codes through without it sanitising them!

<configuration>
    <system.webServer>
        <httpErrors existingResponse="PassThrough" />
    </system.webServer>
</configuration>

ASP.NET Web Api Validation with Data Annotations

I’ve recently moved a project over from WCF Web Api over to ASP.NET Web Api. In doing that I needed to re-implement my validation code. Thanks to the Api being a part of the MVC framework, things are much simpler now.

public class ValidationActionFilter : ActionFilterAttribute
{
    public override void OnActionExecuting(HttpActionContext context)
    {
        var modelState = context.ModelState;
        if (!modelState.IsValid)
        {
            dynamic errors = new JsonObject();
            foreach (var key in modelState.Keys)
            {
                var state = modelState[key];
                if (state.Errors.Any())
                {
                    errors[key] = state.Errors.First().ErrorMessage;
                }
            }

            context.Response = new HttpResponseMessage<JsonValue>(
                errors,
                HttpStatusCode.BadRequest);
        }
    }
}

All I need do now is decorate my models appropriately, for example …

public class TellAFriend
{
    [StringLength(100)]
    public string ToName { get; set; }

    [StringLength(100)]
    [Required]
    [RegularExpression(Regexes.EmailPattern, ErrorMessage = "Invalid email address")]
    public string ToEmailAddress { get; set; }
}

I will get a HTTP 400 response with a nice array of key/value pairs in the response body whenever a client sends me bad data.

{
    "ToEmailAddress": "Invalid email address"
}

ASP.NET Web Api Basic Authentication

I have recently moved a project over from WCF Web Api Preview 6 to ASP.NET Web Api (Beta). Part of that migration involved moving my message handler which dealt with authentication. In the old API I could only authenticate requests to the whole API or nothing at all. This is obviously not ideal, as we may want some parts of the API to be public, but other to only be available to authenticated users.

I have eventually come up with this for my message handler …

public class BasicAuthenticationMessageHandler : DelegatingHandler
{
    private readonly ILogger _logger;

    private class Credentials
    {
        public string Username { get; set; }
        public string Password { get; set; }
    }

    public BasicAuthenticationMessageHandler(ILogger logger)
    {
        _logger = logger;
    }

    protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, System.Threading.CancellationToken cancellationToken)
    {
        if (request.Headers.Authorization != null)
        {
            var credentials = ExtractCredentials(request.Headers.Authorization);
            if (credentials != null && ValidateUser(credentials))
            {
                var identity = new GenericIdentity(credentials.Username, "Basic");
                request.Properties.Add(HttpPropertyKeys.UserPrincipalKey, new GenericPrincipal(identity, new string[0]));
            }
        }
        return base.SendAsync(request, cancellationToken);
    }

    private bool ValidateUser(Credentials credentials)
    {
        if (!Membership.ValidateUser(credentials.Username, credentials.Password))
        {
            _logger.Debug("BasicAuthenticationMessageHandler.ExtractCredentials: Authentication failed for user '{0}'", credentials.Username);
            return false;
        }
        return true;
    }

    private Credentials ExtractCredentials(AuthenticationHeaderValue authHeader)
    {
        try
        {
            if (authHeader == null)
            {
                _logger.Debug("BasicAuthenticationMessageHandler.ExtractCredentials: auth header is null, returning null");
                return null;
            }

            if (authHeader.Scheme != "Basic")
            {
                _logger.Debug("BasicAuthenticationMessageHandler.ExtractCredentials: unsupported scheme {{0}), returning null", authHeader.Scheme);
                return null;
            }

            var encodedUserPass = authHeader.Parameter.Trim();
            var encoding = Encoding.GetEncoding("iso-8859-1");
            var userPass = encoding.GetString(Convert.FromBase64String(encodedUserPass));
            var parts = userPass.Split(":".ToCharArray());
            return new Credentials {Username = parts[0], Password = parts[1]};
        }
        catch (Exception ex)
        {
            _logger.Error(ex, "BasicAuthenticationMessageHandler.ExtractCredentials: Cannot extract credentials.");
            return null;
        }
    }
 }
 

To hook the handler into your API simply add the handler to the global configuration …

var logger = container.Resolve<ILogger>();
GlobalConfiguration.Configuration.MessageHandlers.Add(new BasicAuthenticationMessageHandler(logger));

The key thing to remember is to not try and take over the handling of returning the 401 (Unauthorised) response code to the client, let the framework do that for you via the [Authorize] attribute. Like so …

[Authorize]
public class MyController : ApiController
{
...
}

or, for individual actions …

public class MyController : ApiController
{
    [Authorize]
    public string Get(string id)
    {
    ...
    }
}