Разрешение dbcontext на запрос с Unity в WebApi

Я изо всех сил стараюсь сделать эту работу. У меня есть 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 и попытался использовать PerRequestLifetimeManager, как было предложено msdn, но не повезло. Он всегда дает мне тот же экземпляр dbcontex.

Я скорее не включаю зависимость MVC, так как это просто WebApi, но когда я пытаюсь использовать Unity.Mvc, я также столкнулся с некоторыми ошибками времени выполнения.

У кого-нибудь есть хорошее предложение/пример для разрешения dbcontext для запроса с Unity в WebApi, желательно без какой-либо зависимости mvc?

Ответ 1

То, как я вводил контекст db, было проблемой здесь. Unity запоминает созданный экземпляр и вводит один и тот же экземпляр для всех созданных экземпляров AuditService. Мне просто нужно было разрешить контекст db, как показано ниже.

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

PerThreadLifetimeManager выполнил эту работу, и должно быть хорошо, учитывая, что каждый веб-запрос будет обслуживаться другим потоком.

Ответ 2

Мне удалось решить каждый запрос, объявив мой пользовательский класс UnityResolver в классе WebApiConfig. Класс 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, как показано ниже:

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 общий репозиторий создается для каждого запроса, а также DbContext (BackendContainer).

Надеюсь, это поможет.

Для получения дополнительной информации: http://www.asp.net/web-api/overview/advanced/dependency-injection