'DbContext has been disposed error' on Multiple Calls - c#

I've setup an API that has a simple getCustomers() method. The endpoint returns data on the first call, but returns an error on a second call.
Error: The operation cannot be completed because the DbContext has been disposed
The error is caused within my CustomerService on the return db.Customers...
Question: Why does this work on the first call, but fail on the second call. How can this be resolved?
GitHub Repo can be found here: https://github.com/ChaseHardin/MyBookStore
Here's a walkthrough of the code:
Controller:
[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});
}
}
Customer Service:
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; }
}
Context Setup:
public class Application
{
private static readonly MyBookStoreEntity Context = new MyBookStoreEntity();
public static MyBookStoreEntity GetDatabaseInstance()
{
return Context;
}
}

When you use a using block:
using (var db = Application.GetDatabaseInstance())
The object being "used" will be disposed at the end of the block. (using is basically syntactic shorthand for a try/finally where the finally block calls .Dispose() on the object.)
And what you're "using" is this value:
private static readonly MyBookStoreEntity Context = new MyBookStoreEntity();
This value is static, so it's the same instance of MyBookStoreEntity every time it's called. But when you call it the first time, you .Dispose() it. So any subsequent calls will be on a disposed object.
Basically, you've discovered one of the reasons why a static database context is a very bad idea. You can still encapsulate your database context into a method like you have, but make the method return a new instance each time:
public static MyBookStoreEntity GetDatabaseInstance()
{
return new MyBookStoreEntity();
}
Or, if that method isn't really providing any benefit at this point, then just create the context where you need it:
using (var db = new MyBookStoreEntity())
Creating a database context isn't a particularly heavy operation. But keeping them around when you're not using them is. (And sharing them among different operations is fraught with peril.) A good rule of thumb is to discretely define the database operations you need to perform for a given application operation, and to create/use/dispose your database connection in as tight a code block around those operations as possible.

Related

How to manage EFCore DbContext life in ASP.NET Core web API?

I'm implementing 3-tier architecture, and my question is: Where should I call SaveChanges(); (if applicable)? Where should I create and commit transaction? Please read the whole question.
In the code below I have only "read" operation, but you'll get the idea of the architecture. I'm struggling with the decision, but I came out with two options:
Reference EFCore in the Core project. Inject DbContext into Service class and via method inject it to the Data layer. Like this:
public class ItemService
{
private MyContext _ctx;
private readonly IItemData _itemData;
public ItemService(IItemData itemData)
{
_itemData = itemData;
}
public void InjectCtx(MyContext ctx)
{
_ctx = ctx;
_itemData.InjectCtx(_ctx);
}
public void Operation(int itemId)
{
using (var transaction = _ctx.Database.BeginTransaction())
{
//Do something
_ctx.SaveChanges();
transaction.Commit();
}
}
}
Create an interface in the Core for Unit of work object. Which will have SaveChanges and Transaction, Commit methods. Then implement them in the Data layer and call accordingly in the Service class.
Here is the code. I have 3 projects:
Infrstructure (Data) - references Core and EFCore
Core (Business logic) - no dependencies
Web API (MVC project) - references Core, Data and EFCore
- Core (no dependencies, not even a reference to EFCore):
public class ItemDto
{
public int ItemId { get; set; }
public string Name { get; set; }
}
public interface IItemData
{
Task<ItemDto> GetItem(int itemId);
}
public class ItemService
{
private readonly IItemData _itemData;
public ItemService(IItemData itemData)
{
_itemData = itemData;
}
public async Task<ItemDto> GetItem(int itemId)
{
return await _itemData.GetItem(itemId);
}
}
- Data (reference to Core project and EFCore)
public class ItemData : IItemData
{
private readonly MyContext _ctx;
public ItemData(MyContext ctx)
{
_ctx = ctx;
}
public async Task<ItemDto> GetItem(int itemId)
{
var item = await _ctx.Items
.Where(i => i.ItemId == itemId)
.Select(row => new ItemDto()
{
ItemId = row.ItemId,
Name = row.ItemName
})
.FirstOrDefaultAsync();
return item;
}
}
- Web API:
[Route("api/[controller]")]
[ApiController]
public class ItemsController : ControllerBase
{
private readonly ItemService _itemService;
public ItemsController(ItemService itemService)
{
_itemService = itemService;
}
[HttpGet("{itemId}")]
public async Task<ItemDto> Get(int itemId)
{
return await _itemService.GetItem(itemId);
}
}
If you really feel you need transactions, I would try to handle them 'above' your services, so that those ones are not responsible for handling them.
A way of doing this can be:
Use a scoped DbContext.
When a request starts or a service methods is invoked, create a transaction with Database.BeginTransaction().
Your service layer invokes your data layer and handles the business logic.
Your data layer applies .SaveChanges() wherever it's needed.
When a request ends or a service method invocation end, either run transaction.Commit() or transaction.Rollback().
A way of achieving those transactions creations/commits/rollbacks without making your services responsble of it can be using filters, middlewares or interceptors.

ASP.NET MVC guidelines for static classes for database access

The way I am utilising the MVC pattern at the moment in my ASP.NET application (using Entity Framework) is as follows:
1) My Models folder contains all EF entities, as well as my ViewModels
2) I have a Helpers folders where I store classes created for the purposes of the particular application.
3) In my Helpers folder, I have a static class named MyHelper which contains methods that access the DB using EF.
namespace myApp.Helpers
{
public static class MyHelper
{
public static async Task<ProductVM> GetProductAsync(int productId)
{
using (var context = new myEntities())
{
return await context.vwxProducts.Where(x => x.ProductId == productId).Select(x => new ProductVM { A = x.A, B = x.B }).FirstOrDefaultAsync();
}
}
}
}
4) My controllers then call these functions where necessary:
namespace myApp.Controllers
{
public class ProductController : Controller
{
[HttpGet]
public async Task<ActionResult> Index(int productId)
{
var productVM = await MyHelper.GetProductAsync(productId);
return View(productVM);
}
}
}
I usually encounter comments in SO of the type "don't use a static class, static classes are evil, etc". Would this apply in such a scenario? If yes, why? Is there a better 'structure' my app should follow for best practices and for avoiding such pitfalls?
You can't really use a static class for this. Your Entity Framework context should have one and only one instance per request. Your methods here instantiate a new context for each method, which is going to cause a ton of problems with Entity Framework.
The general concept is fine, but your MyHelper class should be a normal class. Add a constructor that takes an instance of your context, and then use a DI container to inject the context into the helper class and the helper class into your controller.
UPDATE
Helper
namespace myApp.Helpers
{
public class MyHelper
{
private readonly DbContext context;
public MyHelper(DbContext context)
{
this.context = context;
}
public async Task<ProductVM> GetProductAsync(int productId)
{
return await context.vwxProducts.Where(x => x.ProductId == productId).Select(x => new ProductVM { A = x.A, B = x.B }).FirstOrDefaultAsync();
}
}
}
Controller
namespace myApp.Controllers
{
public class ProductController : Controller
{
private readonly MyHelper myHelper;
public ProductController(MyHelper myHelper)
{
this.myHelper = myHelper;
}
[HttpGet]
public async Task<ActionResult> Index(int productId)
{
var productVM = await myHelper.GetProductAsync(productId);
return View(productVM);
}
}
}
Then, you just need to set up a DI container to inject everything. The code for that is entirely dependent on which container you end up going with, so I can't really help you further. It's usually pretty straight-forward, though. Just read the docs for the container. You'll want to set the life-time scope of your objects to the request. Again, it's different for different containers, but they'll all have some sort of request-scope.
I was thinking to add comment to ChrisPratt's answer, but it ended being too long, so let me add separate answer.
Basically, this is not a life/death choice. Sure, static methods are not as flexible as classes for db access. But they are not bad per-se. One DbContext per request is a something to aim for. It is not an absolute must. It is kinda like dependency injection - you get more flexibility and in turn increase code complexity.
Look at these three questions and their answers, by taking into account everything they say, I'm sure you'll be able to answer your question yourself:
Why would I use static methods for database access
When to use static classes in C#
One DbContext per web request... why?
EDIT: Chris left good comment on my answer and I've changed answer a bit to take into account what he said.
Your idea is correct and I use it always. But the style is like this:
1) For each entity (i.e User) we have a static class inside Providers folder. In this class we can do general methods (i.e create, Get, GetAll , ..)
public static class Users
{
public static IEnumerable<kernel_Users> GetAll()
{
Kernel_Context db = new Kernel_Context();
return db.kernel_Users;
}
public static kernel_Users Get(int userId)
{
Kernel_Context db = new Kernel_Context();
return db.kernel_Users.Where(c => c.UserId == userId).FirstOrDefault();
}
...
}
2) We have another class that is not static.It is inside Models folder. This is the place that we can access to an instance of the entity :
public partial class kernel_Users
{
[Key]
public int UserId { get; set; }
public string Username { get; set; }
public string Password { get; set; }
[NotMapped]
public string FullName
{
get
{
return FirstName + " " + LastName;
}
}
public bool Delete(out string msg)
{
...
}
...
}
I use a static class that has the context injected into a static constructor for the purposes of loading a cache of data that rarely changes. And it (should) be thread safe. I hope this helps you, it's very handy in my experience:
public static class StaticCache<T> where T: class
{
private static List<T> dbSet;
public static Dictionary<string, List<T>> cache = new Dictionary<string, List<T>>();
private static readonly object Lock = new object();
public static void Load(DbContext db, string connStr, string tableName)
{
lock (Lock)
{
try
{
if (connStr != null)
{
using (db)
{
dbSet = db.Set<T>().ToList();
cache.Add(tableName, dbSet);
}
}
}
catch { }
}
}
}
void Testit()
{
var context = new YourContextSubClass(connStr);
StaticCache<TableEntity>.Load(context, connstr, "tableEntityNameString");
}

MVC EF database repository pattern

I have read all sorts of posts on this subject but couldn't find the answer to my question.
The general consensus is that I should be creating a context for 1 unit of work (say 1 web page). I have enclosed every method in my Database.cs (see below) with 'using' hence to me - that implies that each time a method from this class is called - a context is created. So if I was to call 2 Methods from Database.cs from the same Action in the HomeController.cs - would that mean that 2 contexts are created?
Would it not be better to declare a private field inside Database.cs like so:
private Entities db = new Entities()
And have each method within the Database.cs class access it? Which approach is the best?
My current implementation (I'm only going to include the method Verify but there are many methods in the Database class):
HomeController.cs
[AllowAnonymous]
public class HomeController : Controller
{
private IDatabase Database;
public HomeController()
{
this.Database = new Database();
}
[HttpGet]
public ActionResult Verify(string id)
{
if (Database.VerifyUser(id))
{
return View();
}
else
{
ViewBag.Error = "There was an error with the verification process";
return View();
}
}
}
Database.cs
public class Database : IDatabase
{
... some other methods ...
public bool VerifyUser(string verificationHash)
{
using (Entities db = new Entities())
{
var userToVerify = db.VerifyUser(verificationHash);
int count = userToVerify.Count();
if (count == 1)
{
return true;
}
else
{
return false;
}
}
}
}
db.VerifyUser(..) - this is a call to a stored procedure
Yes that means there are two instances of DbContext.
The better is to have one instance of DbContext in your Database class and use this instance in all your methods.
public class Database : IDatabase, IDisposeable
{
private Entities db;
public Database()
{
db = new Entities()
}
... some other methods ...
public bool VerifyUser(string verificationHash)
{
var userToVerify = db.VerifyUser(verificationHash);
int count = userToVerify.Count();
if (count == 1)
{
return true;
}
else
{
return false;
}
}
public void Dispose()
{
db.Dispose()
}
}
Then when you finish from Database instance you dispose it and it will dispose the DbContext
public class HomeController : Controller
{
private IDatabase Database;
public HomeController()
{
this.Database = new Database();
}
[HttpGet]
public ActionResult Verify(string id)
{
using(this.Database)
{
if (Database.VerifyUser(id))
{
return View();
}
else
{
ViewBag.Error = "There was an error with the verification process";
return View();
}
}
}
}
BTW: you may prefer to dispose your resources at the controller level. In that case, you don't need to add using statement in your actions
e.g. add this to your controller:
protected override void Dispose(bool disposing)
{
this.Database.Dispose();
base.Dispose(disposing);
}
Yes in your design DbContext created and disposed in every method calls.
Actually, it is not a good solution to put all database operations to a class and create DbContext over and over again. You probably have a problem in future with that class. It might have hundred methods in time and so it is hard to maintain and all entities are not related with each other semantically so it may cause confusion. I think it is a better solution to seperate entity types into classes. For example, you have an users, projects, departments. If we apply my solution to these entities then the uml class diagram will be like this.
All repositories takes a reference to DbContext. It is called Dependency Injection. It means that dbcontext is instantiated once and passes its reference through necessary repositories so there are no context re-creation. Also there is a generic repository which you can put standard procedures.
So you can use repositories like this.
[HttpGet]
public ActionResult Verify(string id){
using(var context = new DbContext())
{
var userRepo = new UserRepository(context);
//Department repository can be used over the same context.
var departmentRepo = new DepartmentRepository(context);
if(userRepo.verifyUser(id)){
return View();
}
}
}

Getting rid of HttpContext dependency - can I use thread storage instead

I'm writing WEB API service that uses a lot of legacy components. The legacy components rely heavily on calls to ContextInfo.ContextID (this is referenced like zillion of times).
public static class ContextInfo
{
public static int ContextID
{
get { return (int)HttpContext.Current.Items["ContextID"]; }
}
}
// sample legacy class
public class Legacy
{
public void Foo()
{
if (ContextInfo.ContextID == 7)
{
Bar();
}
}
}
Every single legacy web application then initializes HttpContext.Current.Items in Application_BeginRequest based on current url (domain) and some db settings.
void Application_BeginRequest()
{
HttpContext.Current.Items["ContextID"] = QueryDb(HttpContext.Current.Request.Url);
}
My web api service will have "dynamic" context. I.E.:
// sample web api method
void Get()
{
int contextID = GetContextBasedOnHttpHeader();
// Works but just icky
HttpContext.Current.Items["ContextID"] = context;
new Legacy().Foo();
}
Relying on http context in web api is just wrong. On the other rewriting all legacy components to inject contextID in a nice way is simply too much work.
I was thinking of abusing the Thread.SetData method instead - i.e.:
// sample web api method
void Get()
{
// filter would be better, but for simplicity sake
ContextInfo.ContextID = GetContextBasedOnHttpHeader();
new Legacy().Foo();
}
And rewriting the ContextInfo into something like this:
public interface IContextInfoProvider { int ContextID { get; set; } }
public class LegacyContextInfoProvider : IContextInfoProvider { ... }
public static class ContextInfo
{
public static IContextInfoProvider Provider = new LegacyContextInfoProvider();
public static int ContextID
{
return Provider.ContextID;
}
}
public class WebApiContextInfoProvider : IContextInfoProvider
{
public int ContextID {
get { return (int)Thread.GetData(Thread.AllocateNamedDataSlot("ContextID")); }
set { Thread.SetData(Thread.AllocateNamedDataSlot("ContextID"), value);
}
}
// on startup
ContextInfo.Provider = new WebApiContextInfoProvider();
We can also assume that the legacy components will run in the same thread (because you can't reference HttpContext.Current.Items once you've fired new thread - it will be null). My concern is with the thread safety - can I use it like this without any nasty side-effect ?

Moq framework Func<T,T>

I am new with Moq and TDD and what I am trying to do is to set up method on repository interface.
Here is full story.
I have a domain entity class called Tenant with property BusinessIdentificationNumber
public class Tenant:EntityBase<Tenant>,IAggregateRoot
{
...
public string BusinessIdentificationNumber {get;set;}
...
}
Next I have repository for this entity which interface is like
public interface IRepository<T>
{
...
T FindBy(Func<T,bool> func);
...
}
where the problem is, I use a domain service which holds the rules for creating a tenant and is like
public class TenantCreationService:ITenantCreationService
{
public TenantCreationService(IRepository<Tenant> tenantRepository){...}
public void CreateTenant(Tenant tenant)
{
//from here there is call to IRepository<Tenant>.FindBy(funcMethod);
}
}
And in unit testing where I am testing the TenantCreationService I mock the repository passed to constructor, but I would like to test the feature :
when tenant with BusinessIdentificationNumber already exists in storage or session it should be returned.
So I was trying to do it like
repositoryMock.Setup(x=>x.FindBy(It.Is<Tenant>(t=>t.BusinessIdentificationNumber
== _tenantInTest.BusinessIdentificationNumber))).Returns(_tenantInTest)
but it does not compile. You know what I want to do?
EDIT:
when i try to compile the snippet below
repositoryMock.Setup(e => e.FindBy(t => t.BusinessNumber == _validTenant.BusinessNumber)).Returns(
_validTenant);
i get exception
Unsupported expression: t => (t.BusinessNumber == value(DP.IPagac.UnitTests.DP.IPagac.Module.TenantManagement.TenantDomainServiceTests)._validTenant.BusinessNumber)
I think what you are trying the acheive is this (removed some things that were extraneous for example and created ITenent so it can be mocked dynamically):
[TestFixture]
public class Test
{
[Test]
public void CreateTenentAlreadyExistsTest()
{
var tenentMock = new Mock<ITenant>();
var repoMock = new Mock<IRepository<ITenant>>();
tenentMock.Setup(t => t.BusinessIdentificationNumber).Returns("aNumber");
repoMock.Setup(r => r.FindBy(It.Is<System.Func<ITenant, bool>>(func1 => func1.Invoke(tenentMock.Object)))).Returns(tenentMock.Object);
var tenantCreationService = new TenantCreationService(repoMock.Object);
tenantCreationService.CreateTenant(tenentMock.Object);
tenentMock.VerifyAll();
repoMock.VerifyAll();
}
}
public interface ITenant
{
string BusinessIdentificationNumber { get; set; }
}
public class Tenant : ITenant
{
public string BusinessIdentificationNumber { get; set; }
}
public interface IRepository<T>
{
T FindBy(System.Func<T, bool> func);
}
public class TenantCreationService : ITenantCreationService
{
private readonly IRepository<ITenant> _tenantRepository;
public TenantCreationService(IRepository<ITenant> tenantRepository)
{
_tenantRepository = tenantRepository;
}
public void CreateTenant(ITenant tenant)
{
var existingTenant =
_tenantRepository.FindBy(t => t.BusinessIdentificationNumber == tenant.BusinessIdentificationNumber);
if (existingTenant == null)
{
//do stuff
}
}
}
public interface ITenantCreationService
{
void CreateTenant(ITenant tenant);
}
"when tenant with BusinessIdentificationNumber already exists in storage or session it should be returned." - from this test description I understood that this behavior you should test in repository class not in on service class
In unit test for services you should not test data accesses layer I mean your repositories,
you should just verify that the repository method FindBy was called.
and my suggest Create ITenantRepositry that derive from IRepository interface and from base class Repostiry.

Categories

Resources