Search code examples
c#asp.netasp.net-web-apiinversion-of-controlautofac

Autofac: Resolving dependencies for ApiControllers


I'm new to Inversion of Control & Autofac. Going through the documentation, there is a lot ASP.NET Web Api concepts I do not fully understand or have experience with, making it a bit difficult to determine what is missing from my implementation.

I want to apply Autofac to an existing ASP.NET Web Api project that has several ApiControllers. These controllers all share a parent abstract class. This abstract class has a method that is responsible for returning an instance of a service. I hoped to replace this method with Autofac's dependency injection.

The parent abstract class from which every ApiController inherits, is very simple.

public abstract class BaseApiController
{
    public IMyService serviceClient { get; set; }

    public BaseApiController() {}

    public BaseApiController(IMyService serviceClient)
    {
        this.serviceClient = serviceClient;
    }
}

Every controller inherits from the above class, while some employs a default Get method, most have multiple routes. Not a single controller is specifying a constructor:

public class MyController : BaseApiController
{
    public MyController() : base() {}
    public MyController(IMyService serviceClient) : base(serviceClient) {}

    [HttpGet]
    [Route("api/foo/bar")]
    [ActionName("FooBar")]
    public string FooBar()
    {
        using (serviceClient)
        {
            return serviceClient.GetFooBar() as string;
        }
    }
}

Autofac is integrated into the Application_Start method of the applications Glabal.asax.cs, registering the ServerClientProvider which should be the provider that should be resolved to when a dependency to the IMyService is encountered:

public class Global : System.Web.HttpApplication, IContainerProviderAccessor
{
    #region AutoFac
    private static IContainerProvider _containerProvider;

    public IContainerProvider ContainerProvider => _containerProvider;
    #endregion AutoFac

    protected void Application_Start(object sender, EventArgs e)
    {

        var builder = new ContainerBuilder();

        builder.Register(x => ServiceClientProvider.GetServiceClient())
            .As<IMyService>()
            .InstancePerRequest();

        builder.RegisterApiControllers(Assembly.GetExecutingAssembly()).PropertiesAutowired();
        builder.RegisterHubs(Assembly.GetExecutingAssembly()).PropertiesAutowired();

        var container = builder.Build();

        GlobalConfiguration.Configuration.DependencyResolver = new AutofacWebApiDependencyResolver(container);
        GlobalHost.DependencyResolver = new AutofacDependencyResolver(container);

        _containerProvider = new ContainerProvider(container);

    }
}

I have configured the ASP.NET application, in the web.config:

<configuration>
  <system.webServer>
    <modules runAllManagedModulesForAllRequests="true">
      <add name="ContainerDisposal" type="Autofac.Integration.Web.ContainerDisposalModule, Autofac.Integration.Web" preCondition="managedHandler" />
      <add name="PropertyInjection" type="Autofac.Integration.Web.Forms.PropertyInjectionModule, Autofac.Integration.Web" preCondition="managedHandler" />
    </modules>
  </system.webServer>
<configuration>

As I understand it, Autofac should automatically resolve the provider when encountering a controller with a public property that matches the registered type (Property Injection), or if a constructor exists with a parameter that matches any registered dependency.

However, I'm not getting any errors relating to my Autofac configuration. I'm getting a NullReferenceException when the MyController attempt to call the IMyService.FooBar method.

What am I missing?

Any help would be greatly appreciated.


Solution

  • After several attempts to debug the code, I realized that there existed another start up implementation in the project. OWIN is used and the start-up implementation I was trying to integrate Autofac with is instantiated but never used. So following the instructions on https://autofac.readthedocs.io/en/latest/integration/owin.html, yielded the results I was looking for.

    Here is how the start-up implemetation should look at:

    [assembly: OwinStartup(typeof(MyWebApp.Api.StartUp))]
    
    namespace MyWebApp.Api
    {
        public class StartUp
        {
    
            public void Configuration(IAppBuilder app)
            {
                // In OWIN you create your own HttpConfiguration rather than
                // re-using the GlobalConfiguration.
                HttpConfiguration httpconfig = new HttpConfiguration();
    
                httpconfig.Routes.MapHttpRoute(
                    name: "ApiRouteWithAction",
                    routeTemplate: "api/{controller}/{action}");
    
                httpconfig.Routes.MapHttpRoute(
                    name: "DefaultApi",
                    routeTemplate: "api/{controller}/{id}",
                    defaults: new { id = RouteParameter.Optional }
                );
    
                // Autofac SignalR integration
                var builder = new ContainerBuilder();
    
                // Register Web API controller in executing assembly.
                builder.RegisterApiControllers(Assembly.GetExecutingAssembly());
    
                // Register SignalR hubs.
                builder.RegisterHubs(Assembly.GetExecutingAssembly());
    
                // Registering Deletegates
                builder.Register(x => ServiceClientProvider.GetServiceClient())
                    .As<IMyService>()
                    .InstancePerRequest();
    
                // Set the dependency resolver to be Autofac.
                var container = builder.Build();
                httpconfig.DependencyResolver = new AutofacWebApiDependencyResolver(container);
    
                app.UseWebApi(httpconfig);
    
                // Register the Autofac middleware FIRST, then the custom middleware if any.
                app.UseAutofacMiddleware(container);
            }
        }
    }
    

    The controller & abstract class it inherited from, were tweaked, removing the parameterless constructors.

    public abstract class BaseApiController
    {
        public IMyService serviceClient { get; set; }
    
        public BaseApiController(IMyService serviceClient)
        {
            this.serviceClient = serviceClient;
        }
    }
    

    Every controller inherits from the above class, while some employs a default Get method, most have multiple routes. Not a single controller is specifying a constructor:

    public class MyController : BaseApiController
    {
        public MyController(IMyService serviceClient) : base(serviceClient) {}
    
        [HttpGet]
        [Route("api/foo/bar")]
        [ActionName("FooBar")]
        public string FooBar()
        {
            using (serviceClient)
            {
                return serviceClient.GetFooBar() as string;
            }
        }
    }
    
    

    Thanks for the interest, hopefully my rookie mistake will help another rookie.