C# 无法使用Unity将依赖项注入ASP.NET Web API控制器

C# 无法使用Unity将依赖项注入ASP.NET Web API控制器,c#,.net,asp.net-web-api,unity-container,C#,.net,Asp.net Web Api,Unity Container,是否有人成功地使用IoC容器将依赖项注入ASP.NET WebAPI控制器?我似乎无法让它工作 这就是我现在正在做的 在myglobal.ascx.cs中: public static void RegisterRoutes(RouteCollection routes) { // code intentionally omitted } protected void Application_Start() {

是否有人成功地使用IoC容器将依赖项注入ASP.NET WebAPI控制器?我似乎无法让它工作

这就是我现在正在做的

在my
global.ascx.cs
中:

    public static void RegisterRoutes(RouteCollection routes)
    {
            // code intentionally omitted 
    }

    protected void Application_Start()
    {
        AreaRegistration.RegisterAllAreas();

        RegisterGlobalFilters(GlobalFilters.Filters);
        RegisterRoutes(RouteTable.Routes);

        IUnityContainer container = BuildUnityContainer();

        System.Web.Http.GlobalConfiguration.Configuration.ServiceResolver.SetResolver(
            t =>
            {
                try
                {
                    return container.Resolve(t);
                }
                catch (ResolutionFailedException)
                {
                    return null;
                }
            },
            t =>
            {
                try
                {
                    return container.ResolveAll(t);
                }
                catch (ResolutionFailedException)
                {
                    return new System.Collections.Generic.List<object>();
                }
            });

        System.Web.Mvc.ControllerBuilder.Current.SetControllerFactory(new UnityControllerFactory(container)); 

        BundleTable.Bundles.RegisterTemplateBundles();
    }

    private static IUnityContainer BuildUnityContainer()
    {
        var container = new UnityContainer().LoadConfiguration();

        return container;
    }

它似乎从未在我的unity文件中查找以解决依赖关系,我得到了如下错误:

尝试创建类型为的控制器时出错 'PersonalShopper.Services.WebApi.Controller.ShoppingListController'。 确保控制器具有无参数公共构造函数

在 System.Web.Http.Dispatcher.DefaultHttpControllerActivator.Create(HttpControllerContext controllerContext,类型controllerType) 位于System.Web.Http.Dispatcher.DefaultHttpControllerFactory.CreateInstance(HttpControllerContext controllerContext,HttpControllerDescriptor(控制器描述器) 位于System.Web.Http.Dispatcher.DefaultHttpControllerFactory.CreateController(HttpControllerContext controllerContext,字符串controllerName) 位于System.Web.Http.Dispatcher.HttpControllerDispatcher.SendAsyncInternal(HttpRequestMessage 请求,取消令牌(取消令牌) 位于System.Web.Http.Dispatcher.HttpControllerDispatcher.SendAsync(HttpRequestMessage 请求,取消令牌(取消令牌)

控制器看起来像:

public class ShoppingListController : System.Web.Http.ApiController
    {
        private Repositories.IProductListRepository _ProductListRepository;


        public ShoppingListController(Repositories.IUserRepository userRepository,
            Repositories.IProductListRepository productListRepository)
        {
            _ProductListRepository = productListRepository;
        }
}
<unity xmlns="http://schemas.microsoft.com/practices/2010/unity">
  <container>
    <register type="PersonalShopper.Repositories.IProductListRepository, PersonalShopper.Repositories" mapTo="PersonalShopper.Implementations.MongoRepositories.ProductListRepository, PersonalShopper.Implementations" />
  </container>
</unity>

我的unity文件如下所示:

public class ShoppingListController : System.Web.Http.ApiController
    {
        private Repositories.IProductListRepository _ProductListRepository;


        public ShoppingListController(Repositories.IUserRepository userRepository,
            Repositories.IProductListRepository productListRepository)
        {
            _ProductListRepository = productListRepository;
        }
}
<unity xmlns="http://schemas.microsoft.com/practices/2010/unity">
  <container>
    <register type="PersonalShopper.Repositories.IProductListRepository, PersonalShopper.Repositories" mapTo="PersonalShopper.Implementations.MongoRepositories.ProductListRepository, PersonalShopper.Implementations" />
  </container>
</unity>

请注意,我没有控制器本身的注册,因为在以前的mvc版本中,控制器工厂会发现需要解决依赖关系


似乎从未调用过我的控制器工厂。

我遇到了相同的异常被抛出,在我的例子中,MVC3和MVC4二进制文件之间存在冲突。这使我的控制器无法在IOC容器中正确注册。检查您的web.config,确保它指向正确的MVC版本。

找到了它

对于ApiControllers,MVC4使用System.Web.Http.Dispatcher.IHttpControllerFactorySystem.Web.Http.Dispatcher.IHttpControllerActivator来创建控制器。如果没有静态方法来注册这些方法的实现;当它们被解析时,mvc框架在依赖项解析器中查找实现,如果没有找到,则使用默认实现

通过执行以下操作,我获得了控制器依赖项的统一解析:

创建了UnityHttpController激活器:

public class UnityHttpControllerActivator : IHttpControllerActivator
{
    private IUnityContainer _container;

    public UnityHttpControllerActivator(IUnityContainer container)
    {
        _container = container;
    }

    public IHttpController Create(HttpControllerContext controllerContext, Type controllerType)
    {
        return (IHttpController)_container.Resolve(controllerType);
    }
}
将该控制器激活器注册为unity容器本身中的实现:

protected void Application_Start()
{
    // code intentionally omitted

    IUnityContainer container = BuildUnityContainer();
    container.RegisterInstance<IHttpControllerActivator>(new UnityHttpControllerActivator(container));

    ServiceResolver.SetResolver(t =>
       {
         // rest of code is the same as in question above, and is omitted.
       });
}
受保护的无效应用程序\u Start()
{
//故意省略的代码
IUnityContainer容器=BuildUnityContainer();
container.RegisterInstance(新的UnityHttpController激活器(container));
ServiceResolver.SetResolver(t=>
{
//代码的其余部分与上面讨论的相同,并被省略。
});
}

您可能想看看Unity.WebApi NuGet包,它将解决所有这些问题,同时还支持IDisposable组件


这里有一个更好的解决方案可以正常工作


在最近的一次RC中,我发现不再有SetResolver方法。为了同时启用控制器和webapi的IoC,我使用Unity.webapi(NuGet)和以下代码:

public static class Bootstrapper
{
    public static void Initialise()
    {
        var container = BuildUnityContainer();

        GlobalConfiguration.Configuration.DependencyResolver = new Unity.WebApi.UnityDependencyResolver(container);

        ControllerBuilder.Current.SetControllerFactory(new DefaultControllerFactory(new ControllerActivator()));
    }

    private static IUnityContainer BuildUnityContainer()
    {
        var container = new UnityContainer();

        container.Configure(c => c.Scan(scan =>
        {
            scan.AssembliesInBaseDirectory();
            scan.With<UnityConfiguration.FirstInterfaceConvention>().IgnoreInterfacesOnBaseTypes();
        }));

        return container;
    }
}

public class ControllerActivator : IControllerActivator
{
    IController IControllerActivator.Create(RequestContext requestContext, Type controllerType)
    {
        return GlobalConfiguration.Configuration.DependencyResolver.GetService(controllerType) as IController;
    }
}
公共静态类引导程序
{
公共静态无效初始化()
{
var container=BuildUnityContainer();
GlobalConfiguration.Configuration.DependencyResolver=新的Unity.WebApi.UnityDependencyResolver(容器);
ControllerBuilder.Current.SetControllerFactory(新的DefaultControllerFactory(新的ControllerActivator());
}
私有静态IUnityContainer BuildUnityContainer()
{
var container=new UnityContainer();
container.Configure(c=>c.Scan(Scan=>
{
scan.AssembliesInBaseDirectory();
scan.With().IgnoreInterfacesOnBaseTypes();
}));
返回容器;
}
}
公共类控制器激活器:IControllerActivator
{
IController IControllerActivator.Create(RequestContext RequestContext,类型controllerType)
{
返回GlobalConfiguration.Configuration.DependencyResolver.GetService(controllerType)作为IController;
}
}

我还使用UnityConfiguration(同样来自NuGet)来实现IoC魔术

在阅读了答案之后,我仍然需要做大量的挖掘工作才能在这里登陆,所以这里是为了同行的利益: 这就是在ASP.NET 4 Web API RC中需要做的全部工作(截至2013年8月8日):

  • 添加对“Microsoft.Practices.Unity.dll”的引用[我使用的是版本] 3.0.0.0,通过NuGet添加]
  • 添加对“Unity.WebApi.dll”的引用[我使用的是0.10.0.0版,通过NuGet添加]
  • 向容器注册类型映射-类似于由Unity.WebApi项目添加到项目中的Bootstrapper.cs中的代码
  • 在继承自ApiController类的控制器中,创建参数化构造函数,将其参数类型作为映射类型
  • 瞧,您将依赖项注入到构造函数中,而无需另一行代码


    注意:我是从其作者在博客中的一条评论中获得此信息的。

    我在使用Unity.WebAPI NuGet包时遇到了同样的问题。问题是该包从未在my Global.asax中添加对
    UnityConfig.RegisterComponents()的调用

    Global.asax.cs应如下所示:

    public class WebApiApplication : System.Web.HttpApplication
    {
        protected void Application_Start()
        {
            UnityConfig.RegisterComponents();
            ...
        }
    }
    

    发生此问题的原因是向Unity注册控制器。我通过按约定注册解决了这个问题,如下所示。请根据需要过滤掉任何其他类型

        IUnityContainer container = new UnityContainer();
    
        // Do not register ApiControllers with Unity.
        List<Type> typesOtherThanApiControllers
            = AllClasses.FromLoadedAssemblies()
                .Where(type => (null != type.BaseType)
                               && (type.BaseType != typeof (ApiController))).ToList();
    
        container.RegisterTypes(
            typesOtherThanApiControllers,
            WithMappings.FromMatchingInterface,
            WithName.Default,
            WithLifetime.ContainerControlled);
    
    IUnityContainer container=newunitycontainer();
    //不要向Unity注册APIController。
    
    using Microsoft.Practices.Unity;
    using System;
    using System.Collections.Generic;
    using System.Web.Http.Dependencies;
    
    public class UnityResolver : IDependencyResolver
    {
        protected IUnityContainer container;
    
        public UnityResolver(IUnityContainer container)
        {
            if (container == null)
            {
                throw new ArgumentNullException("container");
            }
            this.container = container;
        }
    
        public object GetService(Type serviceType)
        {
            try
            {
                return container.Resolve(serviceType);
            }
            catch (ResolutionFailedException)
            {
                return null;
            }
        }
    
        public IEnumerable<object> GetServices(Type serviceType)
        {
            try
            {
                return container.ResolveAll(serviceType);
            }
            catch (ResolutionFailedException)
            {
                return new List<object>();
            }
        }
    
        public IDependencyScope BeginScope()
        {
            var child = container.CreateChildContainer();
            return new UnityResolver(child);
        }
    
        public void Dispose()
        {
            Dispose(true);
        }
    
        protected virtual void Dispose(bool disposing)
        {
            container.Dispose();
        }
    }
    
    public static class UnityConfig
    {
        public static void ConfigureUnity(HttpConfiguration config)
        {
            var container = new UnityContainer();
            container.RegisterType<ISomethingRepository, SomethingRepository>();
            config.DependencyResolver = new UnityResolver(container);
        }
    }
    
    public static void Register(HttpConfiguration config)
    {
        UnityConfig.ConfigureUnity(config);
        ...