依赖项注入不适用于Owin自托管的Web Api 2和Autofac
我正在使用Web Api 2,Owin和Autofac站起来,请提供一些指导.
I'm finding my feet with Web Api 2, Owin and Autofac and need some guidance, please.
概述
我有一个Owin自托管Web Api,它使用Autofac进行IoC和依赖注入.该项目是一个充当服务的控制台应用程序,这意味着它可以停止和启动.我有一个带有两个构造函数的Authentication控制器:一个没有参数,另一个则注入一个存储库.
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.
问题
当我运行该服务并调用api时,将调用我的无参数构造函数,并且永远不会注入我的存储库(_repository = null).
Problem
When I run the service and call the api, my parameter-less constructor is called and my repository never gets injected (_repository = null).
研究
我已经做了相当多的研究,并在Github上找到了一些有用的项目,这些项目已经复制到了发球台上,但是我却错过了很大一部分难题. 这很有帮助,但没有解决我的问题.我在堆栈溢出和Dane Sparza上阅读了这个问题有一个很好的演示项目,但我找不到明确的解决方案.问题不在于自托管,而是依赖注入.
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
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
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);
}
}
您应该使用HttpConfiguration
引导OWIN.
所以,这个:
You should be using the HttpConfiguration
with which you're bootstrapping OWIN everywhere.
So, this:
GlobalConfiguration.Configuration.DependencyResolver = resolver;
应成为:
config.DependencyResolver = resolver;
除此之外,一切看起来都不错. Api控制器已注册,尽管您没有给它们指定范围.不知道在Autofac中,作用域范围默认为对控制器的按请求作用域,还是根本没有按请求作用域的概念(我知道LightInject就是这样).
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).
环顾四周,我认为您遵循了Autofac的Google代码存储库中的示例,该示例确实使用了GlobalConfiguration.相反,如果您查看 GitHub示例 ,这有点不同.尝试根据此进行更改.包括这个:
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年更新
我上面所说的内容仍然适用,但是Autofac的文档有一些其他优点(感谢Brad):
What I said above still applies, but something extra from Autofac's docs (thanks Brad):
OWIN集成中的一个常见错误是使用 GlobalConfiguration.Configuration.在OWIN中,您可以创建 从头开始配置.你不应该参考 GlobalConfiguration.Configuration在使用OWIN的任何地方 整合.
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.