Разрешение 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