blog.vi-kan.net One thought after another

Self host WebAPI controllers for testing

TLDR; With the help of Owin, TestServer and HttpClient, you can do a full integration test of your WebApi in memory without deployment to test host.

I had heard people talking about 'self-hosting' controllers for tests, and last night I manged to get a test rig up and running that I kind of liked.

So normaly, you can unittest your controllers fairly well by just instantiating it and call the methods on it directly. Some times, though, you want to test everything between the client request and the actual action invokation, like authorization attributes and routing etc.

So here's a basic xUnit test showing how I can have a controller defined inside my test, host it, and make a request to it:

    public class WebApiPingTest : IDisposable
    {
        public class WebApiUnderTestController : ApiController
        {
            [HttpGet, Route("api/ping")]
            public async Task<string> Ping()
            {
                return await Task.FromResult("pong");
            }
        }

        private readonly TestServer _server;
        private readonly HttpClient _client;

        public WebApiPingTest()
        {
            _server = TestServer.Create(app =>
                {
                    var config = new HttpConfiguration();
                    config.MapHttpAttributeRoutes();
                    app.UseWebApi(config);
                });
            _client = new HttpClient(_server.Handler) { BaseAddress = new Uri("http://testserver/") };
        }

        [Fact]
        public async Task WebApiOnOwinUpAndRuning()
        {
            var response = await _client.GetAsync("api/ping");
            var result = await response.Content.ReadAsStringAsync();

            Assert.Equal("\"pong\"", result);
        }

        public void Dispose()
        {
            _client.Dispose();
            _server.Dispose();
        }
    }

By separating the constructor and disposer in to a base class, you can get away with very few lines of code.

There are two nuget packages that you need for this to work. First you will need the microsoft.aspnet.webapi.owinselfhost v5.1.2 package for the selfhosted WebApi, and then you'll need microsoft.owin.testing v2.1 for the TestServer.

LightInject constructor injection corner case

TLDR; LightInject will always use the constructor with the most resolvable parameters. If there's only one named service of a given type, LightInject will be able to resolve this as the default service.

I'm using LightInject for dependency injection, and so far it has worked great. It's a small, fast and easy to use library with good documentation too.

I hit one bump in the road earlier this week, though. I have a dependency to a service with multiple constructors, but so far I have only needed the default constructor. Now I wanted to use one of the other two, but LightInject did not choose the one that I expected.

Let's say this is my service:

public interface IMyService
{
    string CalledConstructor { get; }         
}

public class MyService : IMyService
{
    public MyService()
    {
        CalledConstructor = "MyService()";                
    }

    public MyService(string parameterOne)
    {
        CalledConstructor = string.Format("MyService(parameterOne: {0}", parameterOne);                
    }

    public MyService(string parameterOne, string parameterTwo)
    {
        CalledConstructor = string.Format("MyService(parameterOne: {0}, parameterTwo: {1}", parameterOne, parameterTwo);
    }

    public string CalledConstructor { get; private set; }            
}

In the simplest case, we would register the service, and it would resolve using the default constructor:

[TestMethod]
public void Resolve_should_use_default_constructor()
{
    var container = new ServiceContainer();
    container.Register<IMyService, MyService>();

    var service = container.GetInstance<IMyService>();

    Assert.AreEqual("MyService()", service.CalledConstructor);
}

If we need to provide a value for parameterOne, we would register that as well:

[TestMethod]
public void FAILS_Resolve_should_use_constructor_with_one_parameter_but_chooses_the_one_with_two()
{
    var container = new ServiceContainer();
    container.RegisterInstance("FirstValue", "parameterOne");
    container.Register<IMyService, MyService>();

    var service = container.GetInstance<IMyService>();

    Assert.AreEqual(
        string.Format("MyService(parameterOne: {0}", "FirstValue"), 
        service.CalledConstructor);
}

And here's where things went wrong for me.

Test Name: FAILS_Resolve_should_use_constructor_with_one_parameter_but_chooses_the_one_with_two

Result Message: Assert.AreEqual failed.
Expected:<MyService(parameterOne: FirstValue>.
Actual:<MyService(parameterOne: FirstValue, parameterTwo: FirstValue>.

LightInject chose the third constructor, the one taking two parameters, and used the value given to parameterOne for both parameters. Why is that?

The documentation states that

Note: In the case where the implementing type(Foo) has more than one constructor, LightInject will choose the constructor with the most parameters.

It also states that

If only one named registration exists, LightInject is capable of resolving this as the default service.

So LightInject will first try to resolve the constructor with the most parameters, which in this case is the one taking two strings. It will then try to resolve each parameter; first by serviceName, then by using the default for the given type. In this case it will find a service called parameterOne that it uses for the first parameter, but for the second parameter it want find any service registered with the name parameterTwo, so it will try finding one without any name. Since there is only one string instance registered, it will use this as default, even though it was registered with a name.

So how can this be solved?

1. Hide unwanted constructors

If a constructor shouldn't be used, there's no need for it. If it's our service, we could delete the constructor, or change the access modifier. If it's part of an external library, we could inherit it and only expose the one that we need.

public class MyInheritedService : MyService 
{
    public MyInheritedService(string parameterOne) : base(parameterOne) { }
}

[TestMethod]
public void Solution_1_hide_constructor()
{
    var container = new ServiceContainer();
    container.RegisterInstance("FirstValue", "parameterOne");        
    container.Register<IMyService, MyInheritedService>();

    var service = container.GetInstance<IMyService>();

    Assert.AreEqual(
        string.Format("MyService(parameterOne: {0}", "FirstValue"), 
        service.CalledConstructor);
}

2. Register a dummy service

Since this is a problem only when we have just one string instance registered, we could register a second 'dummy' service to prevent the default resolving.

[TestMethod]
public void Solution_2_prevent_resolveing_of_default_service()
{
    var container = new ServiceContainer();
    container.RegisterInstance("FirstValue", "parameterOne");
    container.RegisterInstance("dummy", "dummy");
    container.Register<IMyService, MyService>();

    var service = container.GetInstance<IMyService>();

    Assert.AreEqual(
        string.Format("MyService(parameterOne: {0}", "FirstValue"), 
        service.CalledConstructor);
}

All test cases are available as a Gist

MongoDB and Guids

TLDR: use MongoClientSettings.GuidRepresentation to control how guids are encoded through the .net mongo driver.

When first starting with MongoDb, we generated our document Ids our self in code with Guid.NewGuid(). What we then experienced, was that the actually stored guid, the guid displayed to us by the mongo shell, was not the same as the guid that we saw in Visual Studio during debugging.

At first we where afraid that there was something completly wrong, but testing showed that everything worked as expected - except for the difference in the displayed values.

Today I had the oppertunity to ask Craig Wilson, the maintianer of the .net mongo driver, about this issue. What he told was that each mongo driver has its own way of encoding guids when sending it to mongodb. I'm not sure how big an issue this really is. As long as we stick to one language, it shouldn't be any problem at all, but could mixing two languages with different encoding schemas create trouble? I don't know.

What I do know, though, is that the the .net driver includes a setting to smooth this out. When crating the MongoClient-object, you pass a MongoClientSettings-object that again has a GuidRepresentation-property.

With that problem sorted out, there are something else that should be considered. Rob Conery have written a piece on id generation. Basically its much better to have sequential keys than random keys. There are ways of generating sequential guids, but this project shows that using the native ObjectId may be a better solution anyway.

Azure Mobile Services & Active Directory authentication

TLDR; When authenticating against Azure Active Directory through the Azure Mobile Services, use the magic string aad as he provider, not windowsazureactivedirectory as stated in the documentation.

I just tried out Azure Mobile Services. If you need a simple backend for your app, mobile services may be the way to go. It supports all mayor mobile plattforms (iOS, Android and WinPhone) as well as html5/js and windows store applications.

One of the things it gives you, is easy authentication through 3rd party providers like facebook and twitter. It also supports azure active directory, which is nice for internal applications.

There is one problem, though. The documentation seems to be a little off...

There are documentation for all platforms. Lets have a look at the iOS one:


  1. Open the project file QSTodoListViewController.m and in the viewDidLoad method, remove the following code that reloads the data into the table:
        [self refresh];
  1. Just after the viewDidLoad method, add the following code:
        - (void)viewDidAppear:(BOOL)animated
        {
            MSClient *client = self.todoService.client;            
            if (client.currentUser != nil) {
                return;
            }            
            [client loginWithProvider:@"facebook" controller:self animated:YES completion:^(MSUser *user, NSError *error) {
                [self refresh];
            }];
        }

Note If you are using an identity provider other than Facebook, change the value passed to loginWithProvider above to one of the following: microsoftaccount, facebook, twitter, google, or windowsazureactivedirectory.

  1. Press the Run button to build the project, start the app in the iPhone emulator, then log-on with your chosen identity provider.

    When you are successfully logged-in, the app should run without errors, and you should be able to query Mobile Services and make updates to data.


The code shows how to authenticate through facebook, and the note states that you can use active directory instead by changing @"facebook" to @"windowsazureactivedirectory".

When I tried this, I got a 401 error with the message

"Error: Authentication with 'windowsazureactivedirectory' is not supported."

For some reason I decided to try with @"aad" instead, and lo and behold - it worked!

Since the documentation is hosted on GitHub, I dropped a pull request to notify them of the issue.

Update: the pull request was excepted, and the documentation will soon be (more) accurate on this topic.

Dagens fotnoter… #8

Micro-ORM

Mye prat om micro-orms for tiden. Denne podcasten gir ett lite innblikk i hva det dreier seg om. http://www.hanselminutes.com/default.aspx?showID=282

DevDays 2011, Netherlands

Opptak fra DevDays 2011 er lagt ut på channel 9. http://channel9.msdn.com/Events/DevDays/DevDays-2011-Netherlands

Bart De Smet hadde en interessant session om 10 c# language features. http://channel9.msdn.com/Events/DevDays/DevDays-2011-Netherlands/Devdays041

Breakpoints on Xaml in Silverlight 5

Montro om dette også blir mulig i WPF? Ville vært høyst velkomment. http://jesseliberty.com/2011/04/26/breakpoints-on-xaml-in-silverlight–5/

MineCraft

Dette fenomenet må en visst bare vende seg til. http://www.minecraft.net/