2017-02-04 4 views
1

単純なgetCustomers()メソッドを持つAPIをセットアップしました。エンドポイントは最初の呼び出しでデータを返しますが、2回目の呼び出しではエラーを返します。複数のコールで 'DbContextが処理されませんでした'

Error: The operation cannot be completed because the DbContext has been disposed

エラーが上で私のCustomerService内引き起こされreturn db.Customers...

Question: Why does this work on the first call, but fail on the second call. How can this be resolved?

GitHubのレポは、ここで見つけることができます:

:ここ https://github.com/ChaseHardin/MyBookStore

は、コードのウォークスルーです

コントローラ:

[RoutePrefix("api/customers")] 
public class CustomerController : ApiController 
{ 
    private readonly CustomerService _service = new CustomerService(); 

    [HttpGet, Route("")] 
    public virtual IHttpActionResult Get() 
    { 
     var customers = _service.GetCustomers(); 
     return Ok(new {customers}); 
    } 
} 

カスタマーサービス:

public class CustomerService : BaseService 
{ 
    public List<CustomerViewModel> GetCustomers() 
    { 
     using (var db = Application.GetDatabaseInstance()) 
     { 
      return db.Customers.Select(AutoMapper.Mapper.Map<CustomerViewModel>).ToList(); 
     } 
    } 
} 

BaseService

public class BaseService 
{ 
    public BaseService() 
    { 
     AutoMapperConfiguration(); 
    } 

    public void AutoMapperConfiguration() 
    { 
     Assembly.GetExecutingAssembly() 
       .GetTypes() 
       .Where(x => x.IsClass && x.Namespace == "MyBookStore.Business.ViewModels") 
       .ForEach(x => System.Runtime.CompilerServices.RuntimeHelpers.RunClassConstructor(x.TypeHandle)); 

     AutoMapper.Mapper.CreateMap<bool, short?>().ConvertUsing(x => x ? (short)1 : (short)0); 
     AutoMapper.Mapper.CreateMap<short, bool>().ConvertUsing(x => x == 1); 

     AutoMapper.Mapper.CreateMap<bool, int?>().ConvertUsing(x => x ? 1 : 0); 
     AutoMapper.Mapper.CreateMap<int?, bool>().ConvertUsing(x => x.HasValue && x.Value == 1); 

     AutoMapper.Mapper.CreateMap<short, int>().ConvertUsing(x => (int)x); 
     AutoMapper.Mapper.CreateMap<int, int?>().ConvertUsing(x => x); 
    } 
} 

CustomerViewModel

public class CustomerViewModel 
{ 
    static CustomerViewModel() 
    { 
     AutoMapper.Mapper.CreateMap<Customer, CustomerViewModel>().ReverseMap(); 
    } 

    public Guid CustomerId { get; set; } 
    public string FirstName { get; set; } 
    public string LastName { get; set; } 
} 

コンテキストセットアップ:

public class Application 
{ 
    private static readonly MyBookStoreEntity Context = new MyBookStoreEntity(); 

    public static MyBookStoreEntity GetDatabaseInstance() 
    { 
     return Context; 
    } 
} 
+0

コンテキストがシングルトンで、使用後に処分しているようです。 –

+0

あなたはusingステートメント内で静的コンテキストを使用していますので、一度使用すれば処分されます。静的コンテキストを使用しないでください! – DavidG

+0

静的なデータベースコンテキストは、有名な*悪い考えです。理由の1つを発見しました。 – David

答えて

3

あなたがusingブロックを使用します。

using (var db = Application.GetDatabaseInstance()) 

ブロックの端部に配置される "使用" されているオブジェクト。

(。usingは基本的にfinallyブロックがオブジェクトの上に.Dispose()を呼び出しtry/finallyための構文上の速記です)そして、何あなたが「使用」していることは、この値は次のとおりです。

private static readonly MyBookStoreEntity Context = new MyBookStoreEntity(); 

この値はstaticあるので、それはですそれが呼び出されるたびにMyBookStoreEntityの同じインスタンス。しかし、初めて電話をするときは、.Dispose()です。したがって、後続の呼び出しはすべて廃棄オブジェクトになります。

基本的にstaticデータベースコンテキストがという悪い考えである理由の1つを発見しました。ただ、その後、その方法は本当にこの時点で、任意の利益を提供していない場合は、

public static MyBookStoreEntity GetDatabaseInstance() 
{ 
    return new MyBookStoreEntity(); 
} 

または:あなたはまだあなたが持っているように、メソッドにデータベースコンテキストをカプセル化しますが、この方法は、新しいインスタンスを毎回返すことができます

using (var db = new MyBookStoreEntity()) 

データベースコンテキストの作成は、特に重い操作ではありません。しかし、あなたがそれらを使用していないときにそれらを保つことは、です。(そして、さまざまな操作間でそれらを共有することは危険に満ちています。)適切な経験則として、特定のアプリケーション操作で実行する必要があるデータベース操作を個別に定義し、厳密なコードでデータベース接続を作成/使用/これらの操作を可能な限りブロックします。

+0

これは素晴らしいです、ありがとうございます! – ChaseHardin

関連する問題