【问题标题】:Unable to inject DBContext into my Web API 2 Controller with Unity无法使用 Unity 将 DBContext 注入我的 Web API 2 控制器
【发布时间】:2016-08-12 00:02:26
【问题描述】:

我已经使用它好几天了,但我无法让 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;
        }
    }
}

【问题讨论】:

  • 您能分享一下UnitOfWorkRFContext 的代码吗?

标签: entity-framework asp.net-web-api dependency-injection asp.net-web-api2 unity-container


【解决方案1】:

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

尝试创建类型控制器时出错 'FooController'。确保控制器具有无参数 公共构造函数。

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

更新:

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

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

当一个目标类包含多个具有相同的构造函数时 参数数量,您必须应用 InjectionConstructor Unity 容器将使用的构造函数的属性 指示容器应该使用哪个构造函数。和自动一样 构造函数注入,可以将构造函数参数指定为 具体类型,或者您可以指定一个接口或基类 Unity 容器包含一个已注册的映射。

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

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

【讨论】:

  • 我已经添加了代码。 RFContext 只是一个基本的 POCO 生成的 DBContext,UnitOfWork 会加载它。我认为与这个问题有关:stackoverflow.com/questions/30397188/…。但是,我无法确定我在注册顺序上做错了什么。任何带有 RegisterType 的东西都不起作用。非常感谢您的帮助..
  • 你是我的英雄!有效。如何将 InjectionConstructor 与 PerThreadLifetimeManager 一起使用?非常感谢!
  • 我知道了 container.RegisterType(new PerThreadLifetimeManager(), new InjectionConstructor());非常感谢您的帮助和编码智慧!
猜你喜欢
  • 2012-03-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多