2016-03-31 9 views
8

Veritabanıma Startup sınıfımda başlatılan bir Singleton sınıfında erişmem gerekiyor. Doğrudan enjekte edilen bir DbContext ile sonuçlanan görünüyor.ASP. Net Singleton Enjekte Edilmiş Sınıfta DbContext Kullanın

aşağıdaki hatayı alıyorum:

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

sorum ikilidir: Neden ve nasıl benim veritabanı bir Singleton sınıf örneğinde değil bu iş erişebilir geliyor?

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

Bkz. [Bu yanıt] (http://stackoverflow.com/questions/36246896/structuremap-creation-as-transient-per-request-not-working/36249145#36249145). Bir nesne, kendisinden daha kısa bir yaşam süresine sahip bağımlılıklara sahip olamaz. Daha kısa ömürlü örnekler oluşturmak için bir fabrika enjekte edebilir veya nesne grafiğinin kökü bir tek kişilik olmadığından yeniden düzenleyici ekleyebilirsiniz. – NightOwl888

+2

“DbContext” inizi bir Singleton olarak kaydettirmenizi şiddetle tavsiye ediyorum, web'de size neden kötü bir fikir olduğunu söyleyen birçok makale var. İşte [Basit Enjektör] (https://simpleinjector.org/index) tarafından sağlanan [cevap] (http://stackoverflow.com/questions/10585478/one-dbcontext-per-web-request-why) .html) nedenini açıklamaya çalışır. * Repository * veya * Unit of Work * desenleri gibi bir desen kullanmayı şiddetle öneririm. – QuantumHive

+0

@QuantumHive teşekkürler. Çalışma cevabımda bir uyarı belirttim. – Tjaart

cevap

8

Götürmezse nedeni: Burada

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>(); 
} 

benim denetleyicisi sınıftır: Burada

benim Başlangıç ​​sınıfında benim ConfigureServices yöntemidir benim FunClass İşte

public class TestController : Controller 
{ 
    private FunClass _fun; 

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

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

olduğunu Çalışmak, .AddDbContext uzantısının istek başına kapsamda eklenmesidir. İstek başına, genel olarak istediğiniz gibi olur ve tipik olarak, değişiklikleri kaydeder istek başına bir kez çağrılır ve ardından isteğin sonunda dbcontext belirtilir. Eğer gerçekten bir singleton içinde bir dbContext kullanmanız gerekirse

, sonra FunClass sınıf muhtemelen doğrudan DbContext bir bağımlılık alarak yerine IServiceProvider ve DbContextOptions üzerine bunu kendiniz oluşturabilirsiniz bu şekilde bir bağımlılık almalıdır. Benim tavsiyem dikkatli bunu bir tekil yapmak için çok iyi bir nedeniniz olmadıkça gerçekten, bunu önleyeceğini a tek olmak için FunClass gerekip gerekmediğini dikkate almak olacağını söyledi

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; 
    } 
} 

.

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); 
    } 

} 

olarak birden fazla kişi:

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

çözüm benim DBContext sınıfını değiştirmek oldu:

+1

Kapsayıcıyı ya da 'IServiceProvider' türlerini belirli bir kapsayıcıya (bu durumda IServiceProvider') bağlayan bir anti-düzendir ve kaçınılmalıdır.Bunu uygulamak için fabrika yöntemini veya fabrika sınıfını/arayüzünü kullanmalıdır. fabrika yöntemi 'services.AddSingleton (services => new FunClass (yeni GMBaseContext)); Ek uygulama hizmetlerine gereksinim duyarsanız, bunları "services.RequestService ()" ile fabrika yöntemiyle çözebilir ve GMBaseContext öğesinin yapıcısına iletebilirsiniz. – Tseng

+0

evet Bundan kaçınmanın daha iyi olacağına katılıyorum, ancak çerçevenin kendisinde kullanıldığı yerleri bulacağınızı düşünüyorum. yani DBContext'in kurucusu, fakat şimdi en son koda baktığımda, ISCiceProvider'ın DBContext için en son koddaki kurucuda artık gerekmediği, bu yüzden kaçınılması gerektiği gibi görünüyor, ama RC1'den itibaren bence ihtiyacı var. –

+0

çalışan bir DBContext almak için kurucu DbContext ile DbContextOptions ile örnek oluşturamıyor çünkü benim içeriğim IdentityDbContext türetilmiş, bu nedenle DbContextOptions için bir temel kurucu yok. En son kimlik/ef kodunda – Tjaart

2

çözüm benim sınıf benim Başlangıç ​​sınıfında yöntem parametresinde örneğinin oluşturulmasını ile AddSingleton aramak oldu Ancak uyardı, tek bir sınıfta bir DbContext kullanarak çok kötü bir fikir olabilir. Benim kullanımım gerçek kodda çok sınırlı (örnek FunClass değil), ama sanırım bunu yapıyorsanız başka yollar bulmak daha iyi olacaktır.

+0

Bu makaleyi okuyan var mı? http://mehdi.me/ambient-dbcontext-in-ef6/ Bence bu vaatler gösteriyor - benim için web uygulamalarının tamamen enjekte edilmiş bir dbcontext'in aksine bir fabrikayı kullanması daha mantıklı. Bir performans kazancı, web isteği ömürleri başına tekil olarak kullanabileceği bir çok DI yapılandırma. – Andez

+0

Yapılandırıcının 'public MyContext (DbContextOptions seçenekleri, string connectionString) 'seçeneğinin göz ardı edildiğini unutmayın. Tamam mı? –