无法将 DBContext 注入我的 Web API 2 Controller with Unity

Unable to inject DBContext into my Web API 2 Controller with Unity

我已经用了好几天了,但我无法让 Unity 将任何带有 RegisterType<> 的东西注入我的 Controller。我在 Visual Studio 2015 年使用 Web Api 2 和 Unity 4。每当我尝试注入 IUnitOfWorkIRFContext 时,我都会得到 "message": "An error occurred when trying to create a controller of type 'ClPlayersController'. Make sure that the controller has a parameterless public constructor."。 我正在使用 Unity.AspNet.WebApi 引导程序进入 WebApi。下面是我的 UnityWebApiActivator

[assembly: WebActivatorEx.PreApplicationStartMethod(typeof(mycompany.project.api.UnityWebApiActivator), "Start")]
[assembly: WebActivatorEx.ApplicationShutdownMethod(typeof(mycompany.project.api.UnityWebApiActivator), "Shutdown")]

namespace mycompany.project.api
{
    public static class UnityWebApiActivator
    {
        public static void Start() 
        {
            var resolver = new UnityDependencyResolver(UnityConfig.GetConfiguredContainer());
            GlobalConfiguration.Configuration.DependencyResolver = resolver;
        }

        public static void Shutdown()
        {
            var container = UnityConfig.GetConfiguredContainer();
            container.Dispose();
        }
    }
}

由于 Owin,我正在使用 Start.cs。

[assembly: OwinStartup(typeof(mycompany.project.api.Startup))]
namespace mycompany.project.api
{
    public class Startup
    {
        public void Configuration(IAppBuilder app)
        {
            HttpConfiguration config = new HttpConfiguration();

            ConfigureOAuth(app);

            config.DependencyResolver = new UnityDependencyResolver(UnityConfig.GetConfiguredContainer());
            WebApiConfig.Register(config);
            app.UseCors(Microsoft.Owin.Cors.CorsOptions.AllowAll);
            app.UseWebApi(config);
        }

        public void ConfigureOAuth(IAppBuilder app)
        {
            OAuthAuthorizationServerOptions OAuthServerOptions = new OAuthAuthorizationServerOptions()
            {
                AllowInsecureHttp = true,
                TokenEndpointPath = new PathString("/token"),
                AccessTokenExpireTimeSpan = TimeSpan.FromDays(1),
                Provider = new SimpleAuthorizationServerProvider(),
                RefreshTokenProvider = new SimpleRefreshTokenProvider()
            };

            // Token Generation
            app.UseOAuthAuthorizationServer(OAuthServerOptions);
            app.UseOAuthBearerAuthentication(new OAuthBearerAuthenticationOptions());

        }
    }
}

我的WebApiConfig.cs如下:

namespace mycompany.project.api
{
    public static class WebApiConfig
    {
        public static void Register(HttpConfiguration config)
        {
            log4net.Config.XmlConfigurator.Configure();
            config.MapHttpAttributeRoutes();
            config.EnableSystemDiagnosticsTracing();
            config.Services.Add(typeof(IExceptionLogger),
                new SimpleExceptionLogger(new LogManagerAdapter()));
            config.Services.Replace(typeof(IExceptionHandler), new GlobalExceptionHandler());
        }
    }
}

我的UnityConfig.cs在下面

namespace mycompany.project.api
{
    public class UnityConfig
    {
        #region Unity Container
        private static Lazy<IUnityContainer> container = new Lazy<IUnityContainer>(() =>
        {
            var container = new UnityContainer();
            RegisterTypes(container);
            return container;
        });

        public static IUnityContainer GetConfiguredContainer()
        {
            return container.Value;
        }
        #endregion

        public static void RegisterTypes(IUnityContainer container)
        {
            var config = new MapperConfiguration(cfg =>
            {
                                //AutoMapper bindings
            });
            container.RegisterInstance<IMapper>(config.CreateMapper());
            container.RegisterType<IRFContext, RFContext>(new PerThreadLifetimeManager());
            container.RegisterType<IUnitOfWork, UnitOfWork>();
            XmlConfigurator.Configure();
            var logManager = new LogManagerAdapter();
            container.RegisterInstance<ILogManager>(logManager);
        }
    }
}

Global.asax 中的所有内容如下:

public class WebApiApplication : System.Web.HttpApplication
{
    protected void Application_Error()
    {
        var exception = Server.GetLastError();
        if (exception != null)
        {
            var log = new LogManagerAdapter().GetLog(typeof(WebApiApplication));
            log.Error("Unhandled exception.", exception);
        }
    }
}

如果我的控制器是这样的,它工作正常:

public class ClPlayersController : ApiController
{
    private readonly IMapper mapper;

    public ClPlayersController(IMapper _mapper, IUnityContainer container)
    {
        mapper = _mapper;
    }

但是放置 IUnitOfWork,如下所示,或 IRFContext,我得到错误:

    private readonly IMapper mapper;
    private readonly IUnitOfWork unitOfWork;

    public ClPlayersController(IMapper _mapper, IUnityContainer container, IUnitOfWork _unitOfWork)
    {
        mapper = _mapper;
        unitOfWork = _unitOfWork;
    }

我一辈子都找不到我做错了什么。如果我在构造函数上循环遍历 container.Registrations,我会找到映射,但它们拒绝注入。有什么提示吗?

编辑

下面是 UnitOfWork 和 RFContext 的代码

namespace mycompany.project.data.configuracao
{
    public class UnitOfWork : IUnitOfWork
    {
        private readonly IRFContext _rfContext;
        private bool _disposed = false;

        public UnitOfWork(IRFContext rfContext)
        {
            _rfContext = rfContext;
        }
        public void Commit()
        {
            if (_disposed)
            {
                throw new ObjectDisposedException(this.GetType().FullName);
            }

            _rfContext.SaveChanges();
        }
        public void Dispose()
        {
            Dispose(true);
            GC.SuppressFinalize(this);
        }

        protected virtual void Dispose(bool disposing)
        {
            if (_disposed) return;

            if (disposing && _rfContext != null)
            {
                _rfContext.Dispose();
            }

            _disposed = true;
        }
    }
}

namespace mycompany.project.data.configuracao
{
    public interface IUnitOfWork : IDisposable
    {
        void Commit();
    }
}

并且 RFContext 是一个基本的 POCO 生成的 DBContext

namespace mycompany.project.data.configuracao
{
    using System.Linq;

    public class RFContext : System.Data.Entity.DbContext, IRFContext
    {
        public System.Data.Entity.DbSet<ClGrupoEconomico> ClGrupoEconomicoes { get; set; }
                //all my DbSets
        public System.Data.Entity.DbSet<SpTipoLog> SpTipoLogs { get; set; }

        static RFContext()
        {
            System.Data.Entity.Database.SetInitializer<RFContext>(null);
        }

        public RFContext()
            : base("Name=RFContext")
        {
        }

        public RFContext(string connectionString)
            : base(connectionString)
        {
        }

        public RFContext(string connectionString, System.Data.Entity.Infrastructure.DbCompiledModel model)
            : base(connectionString, model)
        {
        }

        public RFContext(System.Data.Common.DbConnection existingConnection, bool contextOwnsConnection)
            : base(existingConnection, contextOwnsConnection)
        {
        }

        public RFContext(System.Data.Common.DbConnection existingConnection, System.Data.Entity.Infrastructure.DbCompiledModel model, bool contextOwnsConnection)
            : base(existingConnection, model, contextOwnsConnection)
        {
        }

        protected override void Dispose(bool disposing)
        {
            base.Dispose(disposing);
        }

        protected override void OnModelCreating(System.Data.Entity.DbModelBuilder modelBuilder)
        {
            base.OnModelCreating(modelBuilder);

            modelBuilder.Configurations.Add(new ClGrupoEconomicoConfiguration());
                        //all my Configuration classes
            modelBuilder.Configurations.Add(new SpTipoLogConfiguration());
        }

        public static System.Data.Entity.DbModelBuilder CreateModel(System.Data.Entity.DbModelBuilder modelBuilder, string schema)
        {
            modelBuilder.Configurations.Add(new ClGrupoEconomicoConfiguration(schema));
                        //all my configuration classes
            modelBuilder.Configurations.Add(new SpTipoLogConfiguration(schema));
            return modelBuilder;
        }
    }
}

不幸的是,您看到的异常可能由于多种原因而发生。其中之一是 Unity 无法解决您的一次或多次注射。

An error occurred when trying to create a controller of type 'FooController'. Make sure that the controller has a parameterless public constructor.

因此,根据您问题中的信息,您的设置显然是正确的,因为可以注入 IMapper。因此,我 猜测 UnitOfWorkRFContext 具有 Unity 无法解析的依赖项。也许是存储库?

更新:

这里的问题是你的 RFContext 有几个构造函数。

https://msdn.microsoft.com/en-us/library/cc440940.aspx#cnstrctinj_multiple

When a target class contains more than one constructor with the same number of parameters, you must apply the InjectionConstructor attribute to the constructor that the Unity container will use to indicate which constructor the container should use. As with automatic constructor injection, you can specify the constructor parameters as a concrete type, or you can specify an interface or base class for which the Unity container contains a registered mapping.

在这种情况下,Unity 不知道如何解析你的 RFContext,并且会尝试使用参数最多的构造函数。您可以使用

解决它
container.RegisterType<IRFContext, RFContext>(new InjectionConstructor());