【问题标题】:Resolving dbcontext per request with Unity in WebApi在 WebApi 中使用 Unity 解析每个请求的 dbcontext
【发布时间】:2015-04-11 19:21:39
【问题描述】:

我正在努力完成这项工作。我已经安装了 Unity 和 Unity.AspNet.WebApi 软件包(v 3.5.1404),并且低于软件包附带的激活码

public static class UnityWebApiActivator
{
    /// <summary>Integrates Unity when the application starts.</summary>
    public static void Start() 
    {
        var container = UnityConfig.GetConfiguredContainer();
        var resolver = new UnityHierarchicalDependencyResolver(container);

        GlobalConfiguration.Configuration.DependencyResolver = resolver;

        // DynamicModuleUtility.RegisterModule(typeof(UnityPerRequestHttpModule));
    }

    /// <summary>Disposes the Unity container when the application is shut down.</summary>
    public static void Shutdown()
    {
        var container = UnityConfig.GetConfiguredContainer();
        container.Dispose();
    }
}

我的类型注册看起来像这样:

 public static void RegisterTypes(IUnityContainer container)
        {
            container.RegisterType<IAuditService, AuditService>(
                new PerThreadLifetimeManager(),
                new InjectionConstructor(new SecurityDbContext()));
        }

到目前为止,我已经尝试过 PerThreadLifetimeManager 和 TransientLifetimeManager,但没有成功。我也有 Unity.Mvc 包,并尝试按照 msdn 的建议使用 PerRequestLifetimeManager 但没有运气。它总是给我相同的 dbcontex 实例。

我宁愿不包含任何 MVC 依赖项,因为这纯粹是 WebApi,但是当我尝试使用 Unity.Mvc 时,我也遇到了一些 http 运行时错误。

任何人都有一个很好的建议/示例来在 WebApi 中使用 Unity 解析每个请求的 dbcontext,最好没有任何 mvc 依赖项?

【问题讨论】:

    标签: c# entity-framework asp.net-web-api dependency-injection


    【解决方案1】:

    我设法通过在 WebApiConfig 类中声明我的自定义 UnityResolver 类来解决每个请求。 UnityResolver 类使用 HttpConfiguration 类,假设您使用的是 OWIN 上下文。

    public static void Register(HttpConfiguration config)
            {    
                // Web API configuration and services
                var _container = new UnityContainer();
                DependencyConfiguration.ConfigureContainer(_container);
                config.DependencyResolver = new UnityResolver(_container);
             }
    

    ConfigureContainer 类只是一个我声明 IOC 依赖项的类,如下所示:

    private static void RegisterReleaseEnv(IUnityContainer container)
            {
                //Repository Registration
                container             
                  .RegisterType(typeof(IRepository<>), typeof(GenericRepository<>), new HierarchicalLifetimeManager());
    
            }
    

    使用 HierarchicalLifetimeManager 生命周期管理器非常重要,这样您就可以为每个请求获取一个新实例。

    UnityResolver 类如下所示:

    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()
            {
                container.Dispose();
            }
        }
    

    然后我使用 Generic Repistory 获得一个新的 DB 上下文,如下所示:

    public class GenericRepository<TEntity> : IRepository<TEntity>, IDisposable where TEntity : class
    {
        internal BackendContainer context;
        internal DbSet<TEntity> dbSet;
    
        public GenericRepository(BackendContainer context)
        {
            this.context = context;
            this.dbSet = context.Set<TEntity>();
        }
    
        public GenericRepository()
            : this(new BackendContainer())
        {
        }
    
    
        public virtual IQueryable<TEntity> All()
        {
            return dbSet.AsQueryable();
        }
    }
    

    由于 Unity Resolver,Generic Repository 是根据请求实例化的,DbContext (BackendContainer) 也是如此。

    我希望这会有所帮助。

    欲了解更多信息:http://www.asp.net/web-api/overview/advanced/dependency-injection

    【讨论】:

      【解决方案2】:

      我注入数据库上下文的方式是这里的问题。 Unity 会记住创建的实例,并为创建的所有新 AuditService 实例注入相同的实例。我只需要按如下方式解析数据库上下文。

      container.RegisterType<DbContext, SecurityDbContext>(new PerThreadLifetimeManager());
      

      PerThreadLifetimeManager 完成了这项工作,考虑到每个 Web 请求将由不同的线程提供服务,应该没问题。

      【讨论】:

      • 无法获取此“SecurityDbContext”。这是一个自定义的继承 Dbcontext 类的类吗?
      • 是的,SecurityDbContext 继承了 DbContext,这是我通过覆盖 OnModelCreating 方法添加 EF 映射的地方。
      • @Otake 它是如何在 Controller 上声明以使其工作的? Tks
      • @Pascal,这取决于您想如何从控制器访问数据库。在我的例子中,我有一个名为 SecurityService 的服务类,它通过构造函数接收 SecurityDbContext,控制器通过构造函数接收 ISecurityService,它再次被 Unity 解析为 SecurityService。作为一种直接的方法,您可以将 SecurityDbContext 作为控制器构造函数参数的一部分,但除非它是一个小而简单的应用程序,否则我不建议这样做。希望这会有所帮助。
      • 在 Web 应用程序中使用 PerThreadLifetimeManagerreally, really bad idea
      猜你喜欢
      • 1970-01-01
      • 2014-04-24
      • 1970-01-01
      • 2018-02-19
      • 2018-05-22
      • 2012-06-15
      • 2017-11-24
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多