web-dev-qa-db-ja.com

WebApiでUnityを使用してリクエストごとのdbcontextを解決する

私はこの仕事をするのに苦労しています。 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のインスタンスが表示されます。

これは純粋にWebApiであるため、MVCの依存関係は含めませんが、Unity.Mvcを使用しようとすると、いくつかのhttpランタイムエラーも発生しました。

誰もがWebApiでUnityを使用してリクエストごとにdbcontextを解決するための良い提案/例を持っています。

14
Otake

ここで問題は、dbコンテキストを挿入する方法でした。 Unityは作成されたインスタンスを記憶し、作成されたすべての新しいAuditServiceインスタンスに同じインスタンスを注入します。以下のように、dbコンテキストを解決する必要がありました。

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

PerThreadLifetimeManagerが作業を行いました。各Webリクエストが異なるスレッドによって処理されることを考えると問題ありません。

13
Otake

WebApiConfigクラス内でカスタムUnityResolverのクラスを宣言することで、リクエストごとに解決できました。 UnityResolverクラスは、OWINコンテキストを使用していると想定して、HttpConfigurationクラスを使用します。

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リゾルバーのため、Generic Repositoryはリクエストごとにインスタンス化され、DbContext(BackendContainer)もインスタンス化されます。

これがお役に立てば幸いです。

詳細情報: http://www.asp.net/web-api/overview/advanced/dependency-injection

2
Shaun Grech