【问题标题】:Autofac DI error in WebApi2 with OWIN带有 OWIN 的 WebApi2 中的 Autofac DI 错误
【发布时间】:2017-03-30 16:06:56
【问题描述】:

我对 WebApi 中的 DI 有疑问。我已经用instruction 相应地添加了autofac。但是解析控制器有问题。

我收到一个错误:

{
"Message": "An error has occurred.",
"ExceptionMessage": "An error occurred when trying to create a controller of type 'ValuesController'. Make sure that the controller has a parameterless public constructor.",
"ExceptionType": "System.InvalidOperationException",
"StackTrace": "   at System.Web.Http.Dispatcher.DefaultHttpControllerActivator.Create(HttpRequestMessage request, HttpControllerDescriptor controllerDescriptor, Type controllerType)\r\n   at System.Web.Http.Controllers.HttpControllerDescriptor.CreateController(HttpRequestMessage request)\r\n   at System.Web.Http.Dispatcher.HttpControllerDispatcher.<SendAsync>d__1.MoveNext()",
"InnerException": {
"Message": "An error has occurred.",
"ExceptionMessage": "Type 'WebApiOwinAutoFac.Controllers.ValuesController' does not have a default constructor",
"ExceptionType": "System.ArgumentException",
"StackTrace": "   at System.Linq.Expressions.Expression.New(Type type)\r\n   at System.Web.Http.Internal.TypeActivator.Create[TBase](Type instanceType)\r\n   at System.Web.Http.Dispatcher.DefaultHttpControllerActivator.GetInstanceOrActivator(HttpRequestMessage request, Type controllerType, Func`1& activator)\r\n   at System.Web.Http.Dispatcher.DefaultHttpControllerActivator.Create(HttpRequestMessage request, HttpControllerDescriptor controllerDescriptor, Type controllerType)"
   }
}

Startup.cs

public partial class Startup
{
    public void Configuration(IAppBuilder app)
    {
        var builder = new ContainerBuilder();

        // STANDARD WEB API SETUP:

        // Get your HttpConfiguration. In OWIN, you'll create one
        // rather than using GlobalConfiguration.
        var config = new HttpConfiguration();

        // Register your Web API controllers.
        builder.RegisterApiControllers(Assembly.GetExecutingAssembly());

        // builder.RegisterType<ApplicationDbContext>().AsSelf().InstancePerLifetimeScope();
        builder.RegisterType<TestRepository>().As<ITestRepository>();

        // Run other optional steps, like registering filters,
        // per-controller-type services, etc., then set the dependency resolver
        // to be Autofac.
        var container = builder.Build();
        config.DependencyResolver = new AutofacWebApiDependencyResolver(container);

        // OWIN WEB API SETUP:

        // Register the Autofac middleware FIRST, then the Autofac Web API middleware,
        // and finally the standard Web API middleware.
        app.UseAutofacMiddleware(container);
        app.UseAutofacWebApi(config);
        app.UseWebApi(config);

        ConfigureAuth(app);
    }
}

ValuesController.cs

[RoutePrefix("api/Values")]
public class ValuesController : ApiController
{
    private ITestRepository _context { get; set; }

    public ValuesController(ITestRepository context)
    {
        _context = context;
    }

    // GET api/values/5
    [HttpGet]
    public string GetTest()
    {
        var testList = _context.GetAll();
        return String.Join(",", testList.Select(s => s.Name));
    }
}

ITestRepository.cs

public interface ITestRepository
{
    IEnumerable<TestModel> GetAll();
}

TestRepository.cs

public class TestRepository : ITestRepository
{
    private ApplicationDbContext _context = new ApplicationDbContext();

    public IEnumerable<TestModel> GetAll()
    {
        return _context.Tests;
    }
}

我尝试使其工作的示例项目可在GitHub 上找到: 感谢您的帮助。

【问题讨论】:

  • 您从问题中省略了最重要的 Global.asax 代码...这实际上指向了答案:您尚未完全转换为 OWIN。

标签: c# dependency-injection asp.net-web-api2 owin autofac


【解决方案1】:

问题是您的示例项目没有使用 OWIN。它仍在使用经典的非 OWIN ASP.NET Web API。如果您look at your Global.asax.cs,您会发现您仍在使用GlobalConfiguration。使用 OWIN 时不能使用GlobalConfiguration

您会在the Autofac docs on Web API and OWIN integration 中注意到以下内容:

OWIN 集成中的一个常见错误是使用了GlobalConfiguration.Configuration在 OWIN 中,您从头开始创建配置。在使用 OWIN 集成时,您不应在任何地方引用 GlobalConfiguration.Configuration

从您的 Global.asax 中删除 GlobalConfiguration 的使用并完全切换到 OWIN。你不能混搭,否则你会遇到这样的麻烦。

【讨论】:

    【解决方案2】:

    感谢 Travis Illig。我今天也学到了新东西。

    您需要做两件事 - 删除 Global.ascx.cs 中的 GlobalConfiguration,并使用 OWIN 注册 Web API 路由。

    [assembly: OwinStartup(typeof(WebApiOwinAutoFac.Startup))]
    namespace WebApiOwinAutoFac
    {
        public partial class Startup
        {
            public void Configuration(IAppBuilder app)
            {
                var builder = new ContainerBuilder();
    
                // STANDARD WEB API SETUP:
    
                // Get your HttpConfiguration. In OWIN, you'll create one
                // rather than using GlobalConfiguration.
                var config = new HttpConfiguration();
                config.Routes.MapHttpRoute(
                    name: "DefaultApi",
                    routeTemplate: "api/{controller}/{id}",
                    defaults: new { id = RouteParameter.Optional }
                );
    
                // Register your Web API controllers.
                builder.RegisterApiControllers(Assembly.GetExecutingAssembly());
    
                // builder.RegisterType<ApplicationDbContext>().AsSelf().InstancePerLifetimeScope();
                builder.RegisterType<TestRepository>().As<ITestRepository>();
    
                // Run other optional steps, like registering filters,
                // per-controller-type services, etc., then set the dependency resolver
                // to be Autofac.
                var container = builder.Build();
                config.DependencyResolver = new AutofacWebApiDependencyResolver(container);
    
                // OWIN WEB API SETUP:
    
                // Register the Autofac middleware FIRST, then the Autofac Web API middleware,
                // and finally the standard Web API middleware.
                app.UseAutofacMiddleware(container);
                app.UseAutofacWebApi(config);
                app.UseWebApi(config);
    
                ConfigureAuth(app);
            }
        }
    }
    

    Global.ascx.cs

    public class WebApiApplication : System.Web.HttpApplication
    {
        protected void Application_Start()
        {
            AreaRegistration.RegisterAllAreas();
            //GlobalConfiguration.Configure(WebApiConfig.Register); <-- Delete this line
            FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
            RouteConfig.RegisterRoutes(RouteTable.Routes);
            BundleConfig.RegisterBundles(BundleTable.Bundles);
        }
    }
    

    【讨论】:

    • 只有在你不使用 OWIN 的情况下才会这样。
    • @TravisIllig 我从 GitHub 下载并测试了 OP 的示例项目。在我用 GlobalConfiguration.Configuration.DependencyResolver 替换 config.DependencyResolver 后它可以工作。
    • 如果是这种情况,那么 OP 没有使用 OWIN... 或者试图同时使用两者。重点是,当前的问题是 OWIN,因此建议对 GlobalConfiguration 对象进行任何操作都是错误的。答案是修复 OP 的代码以使用 OWIN。
    • @TravisIllig Autofac 在非 .Net Core 项目中使用 OWIN 对我来说也是新的。谢谢你让我大开眼界。
    【解决方案3】:

    您需要告诉 WebApi 如何创建您的控制器。我喜欢通过创建一个组合根来做到这一点。 Mark Seemann 有一篇很棒的文章here。我的实现看起来像这样。我使用的是 StructureMap,但 AutoFac 会有类似的设置。在构造函数中,我传递 IoC 容器,在 Create 方法中,我使用 controllerType 参数从容器中获取控制器实例。

    public class CompositionRoot : IHttpControllerActivator
    {
        private readonly IContainer _container;
    
        public CompositionRoot(IContainer container)
        {
            if (container == null) throw new ArgumentNullException(nameof(container));
            _container = container;
        }
    
        public IHttpController Create(HttpRequestMessage request, HttpControllerDescriptor controllerDescriptor, Type controllerType)
        {
            var controller = (IHttpController) _container.GetInstance(controllerType);
    
            return controller;
        }
    

    你在你的 startup.cs 中像这样连接它(同样,使用 StructureMap):

    config.Services.Replace(typeof (IHttpControllerActivator), new CompositionRoot(container));
    

    这是一个更加手动的接线,这意味着您可能不需要这些线路:

    app.UseAutofacMiddleware(container);
    app.UseAutofacWebApi(config);
    

    希望有帮助

    【讨论】:

    • 您不必连接不同的控制器激活器 - Web API 2 会自动尝试使用请求范围来解析控制器。 Here's the DefaultControllerActivator source.确实需要调用app.UseAutofacWebApi 以确保请求范围可用于默认控制器激活器工作。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-08-14
    • 1970-01-01
    • 2014-10-14
    • 2015-05-06
    • 1970-01-01
    • 2020-06-03
    相关资源
    最近更新 更多