Web API

LightInject.WebApi provides an integration that enables dependency injection in Web API applications.

Installing

LightInject.WebApi provides two distribution models via NuGet

Binary

PM> Install-Package LightInject.WebApi

This adds a reference to the LightInject.WebApi.dll in the target project.

Source

PM> Install-Package LightInject.WebApi.Source

This will install a single file, LightInject.WebApi.cs in the target project.

Initializing

protected void Application_Start()
{
    var container = new ServiceContainer();
    container.RegisterApiControllers();        
    //register other services
    container.EnablePerWebRequestScope();
    container.EnableWebApi(GlobalConfiguration.Configuration)              
}

Note: EnablePerWebRequestScope is only required for hosting within ASP.Net

FilterAttribute

Although filter attributes are instantiated by the MFC infrastructure, LightInject is still able to inject dependencies into properties.

public class FooFilterAttribute : ActionFilterAttribute
{
    public IFoo Foo { get; set; }
}

Owin Selfhosting

This example shows how to do Web API self hosting using OWIN.

Step 1

Create a standard console application and run the following command from the package manager console.

PM> Install-Package Microsoft.AspNet.WebApi.OwinSelfHost

Step 2

Add a OWIN startup class.

public class Startup
{
    public void Configuration(IAppBuilder app)
    {                        
        // Configure Web API for self-host. 
        var config = new HttpConfiguration();          
        config.Routes.MapHttpRoute(
            name: "DefaultApi",
            routeTemplate: "api/{controller}/{id}",
            defaults: new { id = RouteParameter.Optional });

        app.UseWebApi(config); 
    }
}

Step 3

Add a controller

public class ValuesController : ApiController
{        
    public IEnumerable<string> Get()
    {
        return new string[] { "value1", "value2" };
    }        
}

Step 4

Modify the Main method to start the OWIN host.

class Program
{
    static void Main(string[] args)
    {            
        // Start OWIN host 
        using (WebApp.Start<Startup>("http://localhost:9000/"))
        {
            Console.ReadLine(); 
        }

        Console.ReadLine(); 
    }
}

Press F5 to run the application and browse to http://localhost:9000/api/values.

Step 5

PM> Install-Package LightInject.WebApi

Modify the Startup class to enable LightInject to be used as the dependency resolver.

public class Startup
{
    public void Configuration(IAppBuilder app)
    {                        
        // Configure Web API for self-host. 
        var config = new HttpConfiguration();
        var container = new ServiceContainer();
        container.RegisterApiControllers();
        container.EnableWebApi(config);
        config.Routes.MapHttpRoute(
            name: "DefaultApi",
            routeTemplate: "api/{controller}/{id}",
            defaults: new { id = RouteParameter.Optional });

        app.UseWebApi(config); 
    }
}

Note: LightInject.Web can be uninstalled as it is not used in the self host scenario.

Scoping

Scopes are handled by Web API itself and services registered with the PerScopeLifetime or PerRequestLifetime are disposed when the web request ends.

HttpRequestMessage

The current HttpRequestMessage is available to us in the controllers as it is exposed through the Request property. To make the HttpRequestMessage available to other services we need to make some minor changes

The following code will be included as part of the next version of LightInject.WebApi.

The first thing we need is a handler that can keep track of the current HttpRequestMessage.

internal class HttpRequestMessageHandler : DelegatingHandler
{
    private LogicalThreadStorage<HttpRequestMessageStorage> messageStorage =
        new LogicalThreadStorage<HttpRequestMessageStorage>(() => new HttpRequestMessageStorage());

    protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
    {
        messageStorage.Value.Message = request;            
        return base.SendAsync(request, cancellationToken);
    }

    public HttpRequestMessage GetCurrentMessage()
    {
        return messageStorage.Value.Message;
    }
}

The HttpRequestMessageStorage class is simply a "holder" class for the actual HttpRequestMessage.

public class HttpRequestMessageStorage
{
    public HttpRequestMessage Message { get; set; }
}

Next we modify the Startup class to support injection of a Func<HttpRequestMessage>.

public class Startup
{
    public void Configuration(IAppBuilder app)
    {                                                
        // Configure Web API for self-host. 
        var config = new HttpConfiguration();
        var container = new ServiceContainer();
        container.RegisterApiControllers();
        container.EnableWebApi(config);
        container.ScopeManagerProvider = new PerLogicalCallContextScopeManagerProvider();
        var handler = new HttpRequestMessageHandler();
        config.MessageHandlers.Insert(0, handler);
        container.Register<Func<HttpRequestMessage>>(factory => () => handler.GetCurrentMessage());

        config.Routes.MapHttpRoute(
            name: "DefaultApi",
            routeTemplate: "api/{controller}/{id}",
            defaults: new { id = RouteParameter.Optional });

        app.UseWebApi(config); 
    }
}

Now, if we need access to the current HttpRequestMessage, we can just inject a function delegate.

public class Foo
{
    public Foo(Func<HttpRequestMessage> getCurrentRequestMessage)
    {
        var currentMessage = getCurrentRequestMessage();
    }

}