DbContext is Disposed Exception using StructureMap - entity-framework

I am using StructureMap as my IOC Container. I created a seed method that runs on start-up, to be sure the database has relevant data. When this runs, i get the error
The operation cannot be completed because the DbContext has been disposed.
The seed class in question is
public class SeedDatabase : IRunAtStartup
{
private DbContext _context;
private UserManager<ApplicationUser> _userManager;
public SeedDatabase(DbContext context, UserManager<ApplicationUser> userManager)
{
_context = context;
_userManager = userManager;
}
public async void Execute()
{
if (!_context.Set<ApplicationUser>().Any())
{
//Seed Admin User
await _userManager.CreateAsync(new ApplicationUser
{
UserName = "Admin",
Company = "Test Company Ltd",
EmailAddress = "email#emailaddress.com"
}, _userManager.PasswordHasher.HashPassword("Password"));
_context.SaveChanges();
}
}
}
The error occurs on hitting .SaveChanges()
This method just runs once at startup and it accepts a UserManager and DbContext in its conctructor which are provided by means of the IOC Container.
I have tried handling the DbContext per HttpRequest, which was my preference, but also as a singleton. However, the situation did not change.
Here is some of the setup for IOC Container
//convention for DbContext
public class DbContextConvention : IRegistrationConvention
{
public void Process(Type type, Registry registry)
{
//be sure a new context is used for each request
if (type.CanBeCastTo(typeof(DbContext)) && !type.IsAbstract)
{
registry.For(type).LifecycleIs(new UniquePerRequestLifecycle());
}
}
}
Any ideas why I keeps disposing it before it has even been used?

The problem is probably caused by the asynchronous nature of your Execute method. This method will return almost immediately and will continue on a background thread. You are probably disposing the DbContext after Execute returned, but at that moment in time the background operation hasn't finished. Instead, return a Task and wait for that task to finish before cleaning up, or make the Execute method synchronous.

Related

Can i Pass DbContext as interface or delegate

I am having two dbcontext so want to pass it though some function so I can switch between the two dbcontext or I have to change in all the api controller
public class AccountClassesController : ControllerBase
{
private readonly ApplicationDbContext _context;
public AccountClassesController(ApplicationDbContext context)
{
_context = context;
}
// GET: api/AccountClasses
[HttpGet]
public async Task<ActionResult<IEnumerable<AccountClass>>> GetAccountClass()
{
return await _context.AccountClass.ToListAsync();
}
don't want to call the ApplicationDbContext from controller call it through some function or something
I have implemented database connection for postgresql and sqlserver now for them each one creates a different type of migration in code first, so had to create two dbcontext, now I want to be able to switch between dbcontext when I using postgresql or sql server
Yes, you can create interfaces and modify your ApplicationDbContext to implement.
interface
public interface IAccountClass {
Task<IEnumerable<AccountClass>> GetAccountClass();
}
public class AppDbContext: DbContext, IAccount {
/* implementing interface
*/
public Task<IEnumerable<AccountClass>> GetAccountClass() {
return this.AccountClass.ToListAsync();
}
}
Inject DbContext instance casting as interface in your controller:
public AccountClassesController(IAccountClass accountClass)
{
_accountClass = accountClass;
}
// GET: api/AccountClasses
[HttpGet]
public async Task<ActionResult<IEnumerable<AccountClass>>> GetAccountClass()
{
return await this._accountClass.GetAccountClass();
}
You must configure you dependency injection framework to inject a new ApplicationDbContext as IAccountClass.
You can check this answer here is it a good practice to pass an EF DbContext as delegate in services to attach all changes on it.
But if you application don't have any performance issues is fine even if you instance new context due EF is incredible fast managing and building it up.

UnitOfWork and DbContext: thread safety with DI

I'm working on a .NET Core 2.2 Console Application that hosts an IHostedService:
public class MqttClientHostedService : IHostedService, IDisposable
{
[...]
public MqttClientHostedService(
ILogger<MqttClientHostedService> logger,
IOptions<MqttClientConfiguration> mqttConfiguration,
IPositionService positionService)
{
this.logger = logger;
this.config = mqttConfiguration;
this.positionService = positionService;
}
public async Task StartAsync(CancellationToken cancellationToken)
{
mqttClient = new MqttFactory().CreateMqttClient();
mqttClient.Connected += async (s, e) => await MqttClient_Connected(s, e);
mqttClient.ApplicationMessageReceived +=
async (s, e) => await MqttClient_ApplicationMessageReceived(s, e);
await mqttClient.ConnectAsync(
new MqttClientOptionsBuilder()
.WithTcpServer(config.Value.Host, config.Value.Port).Build());
}
private async Task MqttClient_ApplicationMessageReceived(
object sender, MqttApplicationMessageReceivedEventArgs e)
{
string message = Encoding.UTF8.GetString(e.ApplicationMessage.Payload);
await positionService.HandleMessage(message);
}
[...]
}
This IPositionService is a manager that inspects the message and checks if it can be saved inside our database:
public class PositionService : IPositionService
{
[...]
public PositionService(
IUnitOfWork unitOfWork, ILogger<PositionService> logger)
{
this.unitOfWork = unitOfWork;
this.logger = logger;
}
public async Task HandleMessage(string message)
{
Entity entity = await unitOfWork.EntityRepository.GetByMessage(message);
[...]
await unitOfWork.EntityRepository.UpdateAsync(entity);
await unitOfWork.Save();
}
[...]
}
IUnitOfWork is a wrapper around Entity Framework Core DbContext (please don't judge me, I have reasons to do this):
public class UnitOfWork : IUnitOfWork
{
[...]
public UnitOfWork(MyContext myContext)
{
this.myContext = myContext;
EntityRepository = new EFRepository<Entity>(myContext);
}
public async Task Save()
{
await myContext.SaveChangesAsync();
}
}
EFRepository<T>, that implements IRepository<T> interface, is a wrapper around DbSet<T> (again, please don't judge me). No relevant code here.
Console Application's Program.cs is configured like that:
[...]
.ConfigureServices((hostContext, services) =>
{
services.AddDbContext<MyContext>(
c => c.UseSqlServer("[...]", options => options.UseNetTopologySuite()),
ServiceLifetime.Transient);
services.AddTransient<IPositionService, PositionService>();
services.AddTransient(typeof(IRepository<>), typeof(EFRepository<>));
services.AddTransient<IUnitOfWork, UnitOfWork>();
services.AddHostedService<MqttClientHostedService>();
[...]
});
Problem is that PositionService.HandleMessage is being called many times per second, and being that DbContext is not thread safe I get this error message:
A second operation started on this context before a previous operation
completed.
I solved this issue by removing IUnitOfWork from PositionService's dependencies, injecting instead an IServiceScopeFactory, and doing:
using (IServiceScope serviceScope = serviceScopeFactory.CreateScope())
{
IUnitOfWork unitOfWork = serviceScope.ServiceProvider.GetService<IUnitOfWork>();
[...]
}
This way works, but I don't like it. It seems like a trick, and I don't like the fact that my PositionService knows about Dependency Injection and has to deal with scopes.
My question is: there's a better way to solve this problem without touching my classes? Should I make the whole UnitOfWork thread safe? Or maybe create it by hand without using DI?
The source of the problem is that MyContext is held captive as a Captive Dependency in the following object graph:
MqttClientHostedService
-> PositionService
-> UnitOfWork
-> MyContext
All types in this graph are registered as Transient, but still, services that act as hosted service (e.g. your MqttClientHostedService) are resolved only once for the duration of the application and cached indefinately. This effectively makes them a singleton.
In other words, MyContext is accidentally kept alive by the single MqttClientHostedService and because multiple messages can come in in parallel, you have yourself a race condition.
The solution is to let each ApplicationMessageReceived event run in its own unique little bubble (a scope) and resolve a new IPositionService from within that bubble. For instance:
public class MqttClientHostedService : IHostedService, IDisposable
{
[...]
public MqttClientHostedService(
ILogger<MqttClientHostedService> logger,
IOptions<MqttClientConfiguration> mqttConfiguration,
IServiceProvider provider)
{
this.logger = logger;
this.config = mqttConfiguration;
this.provider = provider;
}
[...]
private async Task MqttClient_ApplicationMessageReceived(
object sender, MqttApplicationMessageReceivedEventArgs e)
{
using (var scope = provider.CreateScope())
{
positionService = scope.ServiceProvider
.GetRequiredService<IPositionService>();
string message = Encoding.UTF8.GetString(e.ApplicationMessage.Payload);
await positionService.HandleMessage(message);
}
}
[...]
}

Unity with HierarchicalLifetimeManager. Do I need a 'Using' Statement with Entity Framework

I am using Unity and Entity Framework in a Web API 2 application. I register types with the HierarchicalLifetimeManager.
var container = new UnityContainer();
container.RegisterType<IService, Service>(new HierarchicalLifetimeManager());
Do I need to wrap all my dbContext calls in a using statement like this? Is this needed? I thought Unity will dispose the context for me.
using (var client = new dbContext())
{
var result = client.Customers.toList();
}
Or can I just use dbContext without the using statement?
Do I need to wrap all my dbContext calls in a using statement like
this?
I would say that it depends on how you use your context. Take this example:
public class Service : IService, IDisposable
{
private DbContext _context;
public Service(DbContext context)
{
_context = context;
}
public object Get(int id)
{
return _context.Customers.Find(id);
}
public object Update(object obj)
{
// Code for updating
}
public void Dispose()
{
_context.Dispose();
}
}
If you register Service with HierarchicalLifetimeManager the context will practially never be disposed, since nothing will dispose the service and thus never dispose the context. However, the example above should work fine with TransientLifetimeManager.
From MSDN:
HierarchicalLifetimeManager. For this lifetime manager, as for the
ContainerControlledLifetimeManager, Unity returns the same instance of
the registered type or object each time you call the Resolve or
ResolveAll method or when the dependency mechanism injects instances
into other classes.
If you instead dispose it in each method, then it will be correctly disposed regardless of what lifetimemanager you use. Also, the consumer of IService doesn't need to care about disposing IService.
public class Service : IService
{
public object Get(int id)
{
using (var context = new DbContext())
{
return context.Customers.Find(id);
}
}
public object Update(object obj)
{
// Code for updating
}
}
Also, consider what happens if your Service was Transient, and is injected in a manager that is ContainerController. Since the manager never is disposed, neither is the service. The manager will keep the same instance of the service throughout the lifetime of the container. Therefore I personally suggest that you keep the disposing of the context outside of the containers control. It can work very well with the help of lifetimemanagers if you make sure that you have a chain of disposings. There are several posts here and on codereview that show examples of UoW with Unity to dispose the context.

Code first DbContext usage

I have been trying to work with Entity Framework's Code First. I wrote the below line of code
DbContext _context = new DbContext(ConfigurationManager.ConnectionStrings["con"].ConnectionString);
However on execution, the connection remains closed. Is there something wrong with this code??
I have created a generic repository class using the DBContext shown below
public class GenericRepository<T> where T:class
{
public DbContext _context = new DbContext(ConfigurationManager.ConnectionStrings["con"].ConnectionString);
private DbSet<T> _dbset;
public DbSet<T> Dbset
{
set { _dbset = _context.Set<T>(); }
get { return _dbset; }
}
public IQueryable<T> GetAll()
{
return Dbset;
}
}
and I then call this class on the page load event, where Teacher is an entity class which maps to a table in the database
protected void Page_Load(object sender, EventArgs e)
{
GenericRepository<Teacher> studentrepository = new GenericRepository<Teacher>();
rptSchoolData.DataSource = studentrepository.GetAll().ToList();
rptSchoolData.DataBind();
}
but the connection remains closed and there is also an InvalidOperation Exception in the ServerVersion of the context object.
Am I missing something??
This property
public DbSet<T> Dbset
{
set { _dbset = _context.Set<T>(); }
get { return _dbset; }
}
has a heavy smell to it. A setter that does nothing with value is an anti pattern big time. Do you expect to set the DbSet after creating a GenericRepository?
I don't understand that your code even works because you never initialize _dbset, it should throw a null object reference exception.
The _dbset and DbSet shouldn't be there in the first place. GetAll should return _context.Set<T>(). EF should open and close the connection all by itself. Maybe the fact that you don't initialize the DbSet causes a connection never to open, causing problems in other pieces of code not revealed here.

Is there any reason to use ObjectContext transaction handling with DbContext's SaveChanges?

I have a code like this:
public abstract class DataContextBase
{
public DbContext DbContext { get; protected internal set; }
public ObjectContext ObjectContext { get; protected internal set; }
protected DbTransaction transaction;
protected void SetContext(DbContext db, ObjectContext oc)
{
DbContext = db;
ObjectContext = oc;
}
public void BeginTransaction()
{
if (ObjectContext.Connection.State != System.Data.ConnectionState.Open)
{
ObjectContext.Connection.Open();
}
transaction = ObjectContext.Connection.BeginTransaction();
}
public void CommitTransaction()
{
try
{
transaction.Commit();
}
finally
{
transaction = null;
ObjectContext.Connection.Close();
}
}
public void RollbackTransaction()
{
try
{
transaction.Rollback();
}
finally
{
transaction = null;
ObjectContext.Connection.Close();
}
}
public void Save()
{
DbContext.SaveChanges();
}
}
It is from a sample application, and I use this as a base class of my application's main data context. I'm using Entity Framework 5, and I have just read that when I call the DbContext's SaveChanges method, it always runs in a database transaction and it will throw an exception when the transaction have to be rollbacked and in this case the changes are not saved into the database.
But in the sample application, almost every service method begins with a DataContextBase.BeginTransaction call and ends with a DataContextBase.CommitTransaction call (in an exceptional case it ends with DataContextBase.RollbackTransaction) even though that DataContextBase.Save is called (which calls DbContext.SaveChanges()).
It looks like there is an extra transaction wrapping the built in transaction of the DbContext.SaveChanges call.
Could there be any situation which needs this extra transaction?
NOTE: The DataContextBase's ObjectContext is come from the DbContext with a trick:
((IObjectContextAdapter)this).ObjectContext; // inside the DbContext class
Having an extra transaction is redundant because ObjectContext/DbContext implements Unit of Work. If you have other means of communicating with the database and they also need to be part of the transaction the use TransactionScope.
Connection management is also done by EF and you do not have to