2016-03-31 2 views
8

Startupクラスでインスタンス化されたSingletonクラスのデータベースにアクセスする必要があります。それを直接注入すると、配置されたDbContextが生成されるようです。ASPでのDbContextの使用.Net Singleton Injectedクラス

私は次のエラーを取得する:

Cannot access a disposed object. Object name: 'MyDbContext'.

私の質問は2つあり:なぜ、この仕事とどのように私はシングルトンクラスのインスタンスで私のデータベースにアクセスすることができないのですか?ここで

は私のスタートアップクラスで私のConfigureServices方法であって、ここで

public void ConfigureServices(IServiceCollection services) 
{ 
    // code removed for brevity 

    services.AddEntityFramework().AddSqlServer().AddDbContext<MyDbContext>(
     options => 
     { 
      var config = Configuration["Data:DefaultConnection:ConnectionString"]; 
      options.UseSqlServer(config); 
     }); 

    // code removed for brevity 

    services.AddSingleton<FunClass>(); 
} 

は私のコントローラクラスである:ここで

public class TestController : Controller 
{ 
    private FunClass _fun; 

    public TestController(FunClass fun) 
    { 
     _fun = fun; 
    } 

    public List<string> Index() 
    { 
     return _fun.GetUsers(); 
    } 
} 

は私FunClassです:それはdoesnの

public class FunClass 
{ 
    private MyDbContext db; 

    public FunClass(MyDbContext ctx) { 
     db = ctx; 
    } 

    public List<string> GetUsers() 
    { 
     var lst = db.Users.Select(c=>c.UserName).ToList(); 
     return lst; 
    } 
} 
+1

[回答](http://stackoverflow.com/questions/36246896/structuremap-creation-as-transient-per-request-not-working/36249145#36249145)を参照してください。オブジェクトは、自身よりも寿命が短い依存関係を持つことはできません。ファクトリを挿入してより短いインスタンスを作成するか、またはリファクタリングすることで、オブジェクトグラフのルートがシングルトンでないようにすることができます。 – NightOwl888

+2

シングルトンとしてあなたの 'DbContext'を登録することを強くお勧めします。なぜそれが悪い考えであるかを示す多くの記事がウェブ上にあります。 [Simple Injector](https://simpleinjector.org/index)の作成者が提供する[answer](http://stackoverflow.com/questions/10585478/one-dbcontext-per-web-request-why) .html)なぜその理由を説明しようとします。 * Repository *や* Unit of Work *パターンのようなパターンを使用することを強くお勧めします。 – QuantumHive

+0

@QuantumHiveありがとうございます。私は私の仕事の答えに警告を書きました。 – Tjaart

答えて

8

理由.AddDbContextの拡張機能が要求ごとに有効範囲を追加しているためです。リクエストごとのスコープは一般的に必要なもので、通常は変更を保存すると1回のリクエストにつき1回呼び出され、dbcontextはリクエストの最後に処理されます。あなたが本当にsingletondbContextを使用する必要がある場合

は、その後、あなたのFunClassクラスはおそらく、直接DbContextへの依存を取るのではなく、IServiceProviderDbContextOptionsにあなたがそれを自分で作成することができ、そのように依存関係を取る必要があります。私のアドバイスは慎重にあなたが本当にシングルトンであるためにあなたのFunClassを必要とするかどうかを検討するだろう、と述べた

public class FunClass 
{ 
    private GMBaseContext db; 

    public FunClass(IServiceProvider services, DbContextOptions dbOptions) 
    { 
     db = new GMBaseContext(services, dbOptions); 
    } 

    public List<string> GetUsers() 
    { 
     var lst = db.Users.Select(c=>c.UserName).ToList(); 
     return lst; 
    } 
} 

、私はあなたがそれシングルトン作るために非常に良い理由がない限りことを避けるだろう。

+1

コンテナまたは 'IServiceProvider'を渡すことは、あなたの型を特定のコンテナ(この場合は' IServiceProvider')にバインドするので、反パターンです。避けるべきです。これを実装するには、ファクトリメソッドまたはファクトリクラス/インターフェイスのいずれかを使用する必要があります。ファクトリメソッドは 'services.AddSingleton (services => new FunClass(new GMBaseContext));'のように実装することができます。追加のアプリケーションサービスが必要な場合は、 'services.RequestService ()'を介してファクトリメソッド内でそれらを解決し、 'GMBaseContext'のコンストラクタに渡すことができます。 – Tseng

+0

はい私はそれを避けるほうが良いと思うが、フレームワーク自体で使用されている場所を見つけることになると思います。 DBContextのコンストラクタですが、最新のコードを見ていたので、DBContextのコンストラクタでIServiceProviderが不要になったようですが、これは避けることができますが、RC1ではコンストラクタが動作するDBContextを取得する –

+0

コンテキストがIdentityDbContext から派生しているため、DbContextOptionsを渡す基本コンストラクタがないため、DbContextOptionsでDbContextをインスタンス化できません。 – Tjaart

2

ソリューションは、私のクラスは、私のスタートアップクラスのメソッドのパラメータでインスタンス化された状態でAddSingletonを呼び出すことだった:

services.AddSingleton(s => new FunClass(new MyContext(null, Configuration["Data:DefaultConnection:ConnectionString"]))); 

ソリューションは、私のDbContextクラスを変更することでした:複数の人として

public class MyContext : IdentityDbContext<ApplicationUser> 
{ 
    private string connectionString; 

    public MyContext() 
    { 

    } 

    public MyContext(DbContextOptions options, string connectionString) 
    { 
     this.connectionString = connectionString; 
    } 

    protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder) 
    { 
     // Used when instantiating db context outside IoC 
     if (connectionString != null) 
     { 
      var config = connectionString; 
      optionsBuilder.UseSqlServer(config); 
     } 

     base.OnConfiguring(optionsBuilder); 
    } 

} 

DbContextをシングルトンクラスで使用することは非常に悪い考えかもしれないと警告しています。私の使い方は、実際のコード(FunClassの例ではない)では非常に限られていますが、これを行うと他の方法を見つけるほうがよいでしょう。

+0

誰でもこの記事を読んでいますか? http://mehdi.me/ambient-dbcontext-in-ef6/私はそれが約束を示していると思います - 純粋に注入されたdbcontextとは対照的に、Webアプリケーションがファクトリを使用する方が意味があります。 DIの多くの設定では、Webリクエストのライフタイムごとに、シングルトンを使用してパフォーマンスが向上しているかもしれません。 – Andez

+0

コンストラクタ 'public MyContext(DbContextOptions options、string connectionString) 'はoptionsパラメータを無視することに注意してください。大丈夫ですか? –

関連する問題