2016-08-12 18 views
2

スコープ:このDbContextFunc<T>工場、using the guidelines in the Simple Injector documentation使用して配線されているDbContextと私はシンプルな<code>DbContext</code>は次のように見ている依存

public class MyDbContext : DbContext 
{ 
    private readonly IUserContext _userContext; 

    public MyDbContext(IUserContext userContext) : base("DefaultConnectionString") 
    { 
     _userContext = userContext; 

     Database.SetInitializer(new MigrateDatabaseToLatestVersion<MyDbContext, Configuration>()); 
    } 

    protected override void OnModelCreating(DbModelBuilder modelBuilder) 
    { 
     // ... Here I need to creates some filters using the IUserContext dependency 

     base.OnModelCreating(modelBuilder); 
    } 

} 

container.RegisterFuncFactory<DbContext, MyDbContext>(Lifestyle.Scoped);

public static void RegisterFuncFactory<TService, TImpl>(
    this Container container, Lifestyle lifestyle = null) 
    where TService : class 
    where TImpl : class, TService 
{ 
    lifestyle = lifestyle ?? Lifestyle.Transient; 
    var producer = lifestyle.CreateProducer<TService, TImpl>(container); 
    container.RegisterSingleton<Func<TService>>(producer.GetInstance); 
} 

をしかしapperently、このような単純なケースはでは不可能ですこのメッセージのためDbContextがあります。

ターゲットコンテキスト 'MyDbContext'は構成可能ではありません。デフォルトの コンストラクタを追加するか、IDbContextFactoryの実装を提供してください。

私が思い付くことができる唯一の解決策は、MyDbContextの依存を削除するには、プロパティとして設定し、RegisterFuncFactory方法を変更し、手動でコンテキストを初期化することですので、私は、IDbContextFactoryのアイデアのように本当にいけません:

internal static void RegisterFuncFactory<TService, TImpl>(this Container container, Func<TImpl> instanceProducer, Lifestyle lifestyle = null) where TService : class where TImpl : class, TService 
{ 
    lifestyle = lifestyle ?? Lifestyle.Transient; 
    var producer = lifestyle.CreateProducer<TService>(instanceProducer, container); 
    container.Register<Func<TService>>(() => producer.GetInstance, Lifestyle.Singleton); 
} 

container.RegisterFuncFactory<DbContext, MyDbContext>(() => new MyDbContext 
{ 
    UserContext = container.GetInstance<IUserContext>() 
}, Lifestyle.Scoped); 

エレガントではありませんが、私が必要としている別の「より良い」方法はありますか?私は文脈に依存していることは明白ですが、不可能と思われます。

はUPDATE

エラーから来ている:

'System.Data.Entity.Migrations.Infrastructure.MigrationsException' はEntityFramework.dllで発生したが、ユーザーコード

で処理されませんでした

このコードでは、クエリメソッドのreturn文は次のとおりです。

internal sealed class EntityFrameworkRepository<TEntity> : IEntityWriter<TEntity>, IEntityReader<TEntity> where TEntity : Entity 
{ 
    private readonly Func<DbContext> _contextProvider; 

    public EntityFrameworkRepository(Func<DbContext> contextProvider) 
    { 
     _contextProvider = contextProvider; 
    } 

    public IQueryable<TEntity> Query() 
    { 
     var context = _contextProvider(); 
     return context.Set<TEntity>().AsNoTracking(); 
    } 

    // Methods removed for brevity 

} 
+0

public class MyDbContext : DbContext { private readonly IUserContext _userContext; // For migrations public MyDbContext() : base("DefaultConnectionString") { Database.SetInitializer(new MigrateDatabaseToLatestVersion<MyDbContext, Configuration>()); } // For applications public MyDbContext(IUserContext userContext) : base("DefaultConnectionString") { _userContext = userContext; } protected override void OnModelCreating(DbModelBuilder modelBuilder) { // ... Code removed for brevity base.OnModelCreating(modelBuilder); } } 

この

はその後のような構図のルートで配線されていますか? EFの移行? – Steven

+0

はい、エラーは、System.Data.Entity.Migrations.Infrastructure.MigrationsExceptionがEntityFrameworkで発生しています。dllが、ユーザコードでは扱われませんでした」と返されました。ここでは 'var context = _contextProvider(); return context.Set ().AsNoTracking(); ' – janhartmann

+0

@janhartmann'エンティティ '(制約)とは何ですか?今は 'TEntity'が許可されていないインターフェースになる可能性があるので、' class'制約も指定するべきだと思います。 –

答えて

2

2番目(デフォルト)のコンストラクタを追加します。このようにして、EFの移行では、コマンドラインから実行するときにこのコンストラクタを使用できますが、アプリケーションで2番目のコンストラクタを使用できるようにすることもできます。

この2番目のコンストラクタを追加すると、DbContextにSimple Injectorの自動配線機能が失われますが、問題はありません。

IUserContext userContext = new AspNetUserContext(); 

container.RegisterSingleton<IUserContext>(userContext); 

var contextProducer = Lifestyle.Scoped.CreateProducer<DbContext>(
    () => new MyDbContext(userContext), 
    container); 

container.RegisterSingleton<Func<DbContext>>(contextProducer.GetInstance); 
+0

スティーブンに感謝、これを試してみよう。コンプライアンスのためのシングルトン登録を次のように変更しなければならなかった: 'container.RegisterSingleton >(()=> contextProducer.GetInstance);' – janhartmann

+0

チャームのように働いた!私はあなたの答えを解決策としてマークし、他の人のための完全な解決策の回答を投稿します(またはこれは許可されていませんか?)。 – janhartmann

+0

@janhartmann:私は完全なソリューションを投稿するのが良い方法だと思います。もっと多くの人々がそれを行うべきです。 – Steven

0

この回答は、私が最後に行ったことだけを表示するためのものです。 @スティーブンの答えが正しい答えです。

移行をサポートしながらDbContextに依存関係を注入できるようにするには、2つのコンストラクタを使用する必要があります。 1つは移行用、もう1つはアプリケーション用です。あなたにこのメッセージを与えている

public static void RegisterEntityFramework<TContext>(this Container container, Func<TContext> context) where TContext : DbContext 
{ 
    if (container == null) throw new ArgumentNullException(nameof(container)); 

    var contextProducer = Lifestyle.Scoped.CreateProducer<DbContext>(context, container); 
    container.RegisterSingleton<Func<DbContext>>(() => contextProducer.GetInstance); 
} 

var userContext = new AspNetHttpUserContext(); 
var container = new Container(); 
container.Options.DefaultScopedLifestyle = new WebApiRequestLifestyle(); 
container.RegisterSingleton<IUserContext>(userContext); 
container.RegisterEntityFramework(() => new WayFinderDbContext(userContext)); 
container.Verify(); 
関連する問題