I'm finding my feet with Web Api 2, Owin and Autofac and need some guidance, please.
Overview
I have an Owin self-hosted Web Api that uses Autofac for IoC and dependency injection. The project is a console app acting like a service, meaning it can be stopped and started. I have an Authentication controller with two constructors: one parameter-less and the other injects a repository.
Problem
When I run the service and call the api, my parameter-less constructor is called and my repository never gets injected (_repository = null).
Research
I've done a fair bit of research and found some helpful projects on Github, which I replicated to the tee but I'm missing a big part of the puzzle. This was helpful but didn't solve my problem. I read this question on Stack Overflow and Dane Sparza had a nice demo project but I couldn't find a clear solution. The problem is not the self-hosting but the dependency injection.
My code (thinned out for explanation)
public class Startup { public void Configuration(IAppBuilder app) { HttpConfiguration config = new HttpConfiguration(); config.Routes.MapHttpRoute( name: "DefaultApi", routeTemplate: "api/{controller}/{id}", defaults: new { id = RouteParameter.Optional } ); var json = config.Formatters.JsonFormatter; json.SerializerSettings.PreserveReferencesHandling = Newtonsoft.Json.PreserveReferencesHandling.Objects; config.Formatters.Remove(config.Formatters.XmlFormatter); var connectioninfo = ConnectionInfo.FromAppConfig("mongodb"); var builder = new ContainerBuilder(); // Create the container builder. builder.RegisterApiControllers(Assembly.GetExecutingAssembly()); // Register the Web API controllers. builder.Register(c => new Logger()).As<ILogger>().InstancePerRequest(); // Register a logger service to be used by the controller and middleware. builder.RegisterType<AuthenticationRepository>().As<IAuthenticationRepository>().WithParameter(new NamedParameter("connectionInfo", connectioninfo)).InstancePerRequest(); var container = builder.Build(); var resolver = new AutofacWebApiDependencyResolver(container); // Create an assign a dependency resolver for Web API to use. GlobalConfiguration.Configuration.DependencyResolver = resolver; // Configure Web API with the dependency resolver app.UseCors(CorsOptions.AllowAll); app.UseWebApi(config); app.UseAutofacWebApi(config); // Make sure the Autofac lifetime scope is passed to Web API. }
Program.cs
static void Main(string[] args) { var service = new ApiService(typeof(Program), args); var baseAddress = "http://localhost:9000/"; IDisposable _server = null; service.Run( delegate() { _server = WebApp.Start<Startup>(url: baseAddress); }, delegate() { if (_server != null) { _server.Dispose(); } } ); }
ApiController
public class AuthenticationController : ApiController { private IAuthenticationRepository _repository; public AuthenticationController() { } public AuthenticationController(IAuthenticationRepository repository) { _repository = repository; } [AllowAnonymous] public IHttpActionResult Authenticate(string name, string password) { if (_repository == null) return BadRequest("User repository is null."); var valid = _repository.AuthenticateUser(name, password); return Ok(valid); } }
You should be using the HttpConfiguration
with which you're bootstrapping OWIN everywhere. So, this:
GlobalConfiguration.Configuration.DependencyResolver = resolver;
Should become:
config.DependencyResolver = resolver;
Other than that, everything looks good. Api controllers are registered, although you're not giving them a scope. Not sure if in Autofac scoping defaults to per-request for controllers or if it has the notion of per-request scoping at all (I know that LightInject has it).
Looking around, I think you followed the example on the Google Code repo for Autofac, which indeed uses GlobalConfiguration. Instead, if you look at the GitHub example, it is a bit different. Try to make the changes according to this. Including this:
// This should be the first middleware added to the IAppBuilder. app.UseAutofacMiddleware(container);
2016 update
What I said above still applies, but something extra from Autofac's docs (thanks Brad):
A common error in OWIN integration is use of the GlobalConfiguration.Configuration. In OWIN you create the configuration from scratch. You should not reference GlobalConfiguration.Configuration anywhere when using the OWIN integration.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With