带有OWIN的WebApi2中的Autofac DI错误

时间:2017-03-30 16:06:57

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

我在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上找到: 谢谢你的帮助。

3 个答案:

答案 0 :(得分:1)

感谢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);
    }
}

答案 1 :(得分: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 :(得分:0)

您需要告诉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);

希望有所帮助