Unity.WebApi |确保控制器具有无参数的公共构造函数

时间:2016-01-21 23:56:08

标签: c# asp.net-web-api dependency-injection inversion-of-control unity-container

我在ASP.NET WebApi解决方案中使用Unity.WebApi NuGet包(Unity 4.0.1和Unity.WebApi 5.2.3)。我面临的问题是,在尝试运行代码时,我收到错误:Make sure that the controller has a parameterless public constructor。我在这里搜索过类似的帖子,但我找不到符合我问题的帖子。

请不要说"添加无参数构造函数"因为它显示你显然不知道IoC是什么以及为什么这个陈述完全没有意义并且违背了IoC的目的。我之所以这么说是因为我在迄今为止看过的很多其他主题中看到了这一点。

这是我的Startup.cs(我使用Owin,所以我没有Global.asax):

public void Configuration(IAppBuilder app) {
    var config = new HttpConfiguration();
        config.MapHttpAttributeRoutes();

        // Registering unity stuff
        UnityConfig.RegisterComponents();

        app.UseWebApi(config);
}

这是我的UnityConfig.cs:

public static class UnityConfig {
    public static void RegisterComponents() {
        var container = new UnityContainer();
            // Register controller
            container.RegisterType<MyController>();

            // Register interface
            container.RegisterType<IService, Service>();

            GlobalConfiguration.Configuration.DependencyResolver = new UnityDependencyResolver(container);
    }
}

这是我的API控制器:

public class MyController : ApiController {
    private IService service

    public MyController(IService service) {
        this.service = service;
    }

    public IHttpActionResult Get() {
        return Ok("All systems go!");
    }
}

修改

我拿出了使用声明,因为无论使用声明是否存在,人们都很难理解问题。

6 个答案:

答案 0 :(得分:14)

根据我的经验,出现这种情况会有两种不同的情况。

1。 确保可以解析Service构造函数中的所有参数。它是否有任何您尚未注册的依赖项?

Make sure that the controller has a parameterless public constructor in Unity

2。 确保使用Web API注册Unity。像这样:

public static class WebApiConfig
{
    public static void Register(HttpConfiguration config)
    {
        // Routes and other stuff here...

        var container = IocContainer.Instance; // Or any other way to fetch your container.
        config.DependencyResolver = new UnityDependencyResolver(container);
    }
}

这里的例子:

Injecting Dependency into Web API Controller

http://codeclimber.net.nz/archive/2015/02/20/Using-Entity-Framework-within-an-Owin-hosted-Web-API-with.aspx

编辑1:

如评论中提到的@ NightOwl888,您不应该丢弃容器。注册在容器上注册,当容器被丢弃时,它将不知道如何解决依赖关系。这可能会导致您看到的错误。

编辑2:

由于您正在使用Owin,您应该可以执行以下操作:

    public void Configuration(IAppBuilder appBuilder) 
    { 
      // Configure Web API for self-host. 
      HttpConfiguration config = new HttpConfiguration();
      config.DependencyResolver = new UnityDependencyResolver(
          UnityConfig.GetConfiguredContainer());

      config.Routes.MapHttpRoute( 
                    name: "DefaultApi", 
                    routeTemplate: "api/{controller}/{id}", 
                    defaults: new { id = RouteParameter.Optional } 
                ); 

      appBuilder.UseWebApi(config); 
    }

并将UnityConfig更新为:

    public static class UnityConfig {
       public static IUnityContainer GetConfiguredContainer() {
            var container = new UnityContainer();
            // Register controller
            container.RegisterType<MyController>();

            // Register interface
            container.RegisterType<IService, Service>();

            //This is done in Startup instead.
            //GlobalConfiguration.Configuration.DependencyResolver = new UnityDependencyResolver(container);
            return container;
    }
}

从这个来源: How to use DI container when OwinStartup

http://damienbod.com/2013/10/01/self-host-webapi-with-owin-and-unity/

  

在此方法中,HttpConfiguration.DependencyResolver设置为a   UnityDependencyResolver实例。这是构造函数所必需的   注入可以在webApi控制器中使用。该   UnityDependencyResolver类与。完全相同   Unity.WebApi.UnityDependencyResolver类。 Unity.WebApi未使用   因为这是一个自托管的OWIN应用程序。

答案 1 :(得分:1)

另一种可能的调查路径以及导致此问题的原因。我在全局异常处理程序上设置了断点,并查看了异常实例上的嵌套异常属性。我得到的错误是没有可访问的构造函数,这是真的,因为我要注入的类型确实具有私有构造函数(我正在重构单例)。

答案 2 :(得分:0)

DependencyResolver设置为您在启动时创建的HttpConfiguration,而不是GlobalConfiguration.Configuration,并确保所有服务构造函数都是公开的,希望这有帮助

答案 3 :(得分:0)

确保正确解析任何也注入的嵌套类型。即使嵌套类型被错误地解析,您也会在控制器级别上收到错误消息。

答案 4 :(得分:0)

我正在使用Unity版的4.0.1,在我的情况下,嵌套依赖项Repository有两个公共构造函数,而Unity却没有选择无参数构造函数。

因此,我刚刚将另一项指定为受保护项以快速解决此问题。

    public Repository() : this( ... ) { ... }

    // if need to make public, make sure that the dependency injection container
    // will choose the parameterless constructor;
    // Unity has had issues with that by default
    protected Repository(DbContext context) : base() { ... }

IMO,Unity可以设法找到“可能调用”的构造函数-因为它没有注册DbContext(或任何派生的上下文)。

请注意,默认情况下,Unity选择具有最大参数数量的构造函数。

是的,也可以用InjectionConstructorAttribute装饰herehere的正确构造函数-但我什至没有Unity引用我的数据访问层(不想)。

请告诉我这种行为在以后的版本中是否已更改。

答案 5 :(得分:0)

不幸的是,这些答案都不对我有用。我已经按照下面描述的步骤使用了smoksnes提供的方法:https://docs.microsoft.com/en-us/aspnet/web-api/overview/advanced/dependency-injection

我的问题已通过使用特定于Web api的统一程序包(Unity.AspNet.WebApi)而不是如Microsoft指南中所述的常规.net程序包得以解决。