Blazor Server App and IDbContextFactory not disposing - entity-framework-core

I have a blazor server application that needs to indirectly connect to a EF core DB context.
None of the blazor components will directly inject an instance of the dbcontext. I am using mediator which will handle all business operations.
The documentation that I have seen so far recommends using IDbContextFactory. I gave it a try but I am not seeing the DbContext created by the factory being disposed. The services that inject IDbContext are not disposed on page changes nor at any other time.
public class QueryHandler : IQueryHandler<Query, Entity>, IDisposable
{
private readonly DbContext dbContext;
public QueryHandler(IDbContextFactory factory)
{
dbContext = factory.CreateDbContext();
}
public Task Handle(Query query)
{
/// do whatever needs to be done.
}
public void Dispose()
{
dbContext.Dispose(); // <-- Dispose never gets called.
}
}
Am I missing something?

The purpose of using a DbContextFactory is to have a DbContext per method.
Exactly because Blazor doesn't offer useful Scopes to handle this.
public class QueryHandler : IQueryHandler<Query, Entity> //, IDisposable
{
...
public QueryHandler(IDbContextFactory factory)
{
_factory = factory;
}
public Task Handle(Query query)
{
using var dbContext = _factory.CreateDbContext();
/// do whatever needs to be done.
}
//public void Dispose() { }
}
This way the DI container and Factory only manage the configuration of the DbContext. Lifecycle management of the DbContext is manual. The Factory is a simple Transient object, is owns no resources.
Manual management usually is with a using statement or using declaration but Blazor also offers an OwningComponentBase. I don't see it being used much.

In Server the DI container exists for the lifetime of the Hub Session and in WASM the lifetime of the Application. Any service objects created within the container, whether Scoped or Transient, implementing IDisposable, are not Disposed until the DI container itself is destroyed. You don't make clear the scope of QueryHandler, but if it's transient that's bad news. You will keep creating new DBContexts without the old ones being disposed.
The purpose of the DbContextFactory is to create unit of work DbContext instances that are used and then quickly disposed correctly. You need to take this approach because DB access will almost certainly be asynchronous. Use a single context and you will quickly hit the situation where you are awaiting one query to complete while trying to use the same context in another operation.
Henk's answer shows you how to use and consume factory created contexts.

Related

Workflow: Creating Dependency Chain with Service Locator Pattern

I'm trying to get dependencies set up correctly in my Workflow application. It seems the best way to do this is using the Service Locator pattern that is provided by Workflow's WorkflowExtensions.
My workflow uses two repositories: IAssetRepository and ISenderRepository. Both have implementations using Entity Framework: EFAssetRepository, and EFSenderRepository, but I'd like both to use the same DbContext.
I'm having trouble getting both to use the same DbContext. I'm used to using IoC for dependency injection, so I thought I'd have to inject the DbContext into the EF repositories via their constructor, but this seems like it would be mixing the service locator and IoC pattern, and I couldn't find an easy way to achieve it, so I don't think this is the way forward.
I guess I need to chain the service locator calls? So that the constructor of my EF repositories do something like this:
public class EFAssetRepository
{
private MyEntities entities;
public EFAssetRepository()
{
this.entities = ActivityContext.GetExtension<MyEntities>();
}
}
Obviously the above won't work because the reference to ActivityContext is made up.
How can I achieve some form of dependency chain using the service locator pattern provided for WF?
Thanks,
Nick
EDIT
I've posted a workaround for my issue below, but I'm still not happy with it. I want the code activity to be able to call metadata.Require<>(), because it should be ignorant of how extensions are loaded, it should just expect that they are. As it is, my metadata.Require<> call will stop the workflow because the extension appears to not be loaded.
It seems one way to do this is by implementing IWorkflowInstanceExtension on an extension class, to turn it into a sort of composite extension. Using this method, I can solve my problem thus:
public class UnitOfWorkExtension : IWorkflowInstanceExtension, IUnitOfWork
{
private MyEntities entities = new MyEntities();
IEnumerable<object> IWorkflowInstanceExtension.GetAdditionalExtensions()
{
return new object[] { new EFAssetRepository(this.entities), new EFSenderRepository(this.entities) };
}
void IWorkflowInstanceExtension.SetInstance(WorkflowInstanceProxy instance) { }
public void SaveChanges()
{
this.entities.SaveChanges();
}
}
The biggest downside to doing it this way is that you can't call metadata.RequireExtension<IAssetRepository>() or metadata.RequireExtension<ISenderRepository>() in the CacheMetadata method of a CodeActivity, which is common practice. Instead, you must call metadata.RequireExtension<IUnitOfWork>(), but it is still fine to do context.GetExtension<IAssetRepository>() in the Execute() method of the CodeActivity. I imagine this is because the CacheMetadata method is called before any workflow instances are created, and if no workflow instances are created, the extension factory won't have been called, and therefore the additional extensions won't have been loaded into the WorkflowInstanceExtensionManager, so essentially, it won't know about the additional extensions until a workflow instance is created.

Entity Framework SQL Connections are not getting closed or disposed

I'm using Entity Framework with Repository Pattern, but we have requirement to call stored proecedure, so we ended up in creating DAL Class with EF DBContext has local private variable in DAL Class,
private context;
I try to instantiate DBContext in Repository Class Constructor
public VRepository( IDataAccessObjectFactory daoFactory)
{
_daoFactory = daoFactory;
context = _daoFactory.GetEFContext<DbEntities>();
}
All the Services call a method of DAL's repository class and all repository class inherits from IDisposable and implemented disposable method in repository class
public void Dispose()
{
if (context != null)
{
context.Dispose();
// GC.SuppressFinalize(this);
}
}
I try to call above dispose method from service layer after completing Operation in a method, something like calling dispose method of BLL finally block to dispose the DBContext object( I'm having WEB API , WEB API -> BLL -> DAL).
Even after calling context.Dispose(), EF created Sql Connections are not getting Closed. Can Any1 suggest me right way of closing SQL connections and dispose SQL Connection. If I dont dispose, SQL connections goes to 100 which is not allowing new connections for some time or worker restart. Please let me know effective way of dispose context immediately completion of repository layer method.

Implementing passive attributes with dependencies that should be resolved by a DI container

I'm trying to implement passive attributes in an ASP.NET Web API. The filter I'm implementing has a dependency on a repository, which itself has a dependency on a custom DbContext.
In the post it says that you can resolve the component with a DI container, but also that the code should be invoked from Application_Start.
I'm not sure how to implement this, while taking advantage of the DI container's lifetime management capabilities (so that a new DbContext will be used per request). Would injecting an abstract factory be a good solution for this? or is there something simpler that I'm missing.
You can resolve this issue by sliding a Decoraptor in between the Filter and the Repository.
Not knowing a lot about your code, you should be able to define a Decoraptorepository using an Abstract Factory:
public class Decoraptorepository : IRepository
{
private readonly IFactory<IRepository> factory;
public Decoraptorepository(IFactory<IRepository> factory)
{
this.factory = factory;
}
// Just guessing IRepository's member(s) here...
public void Save(Foo foo)
{
this.factory.Create().Save(foo);
}
// other members...
}
This enables your Filter to stay a Singleton, while the actual Repository is being created in a Transient manner.
If you need to dispose of objects too, please refer to the follow-up article on how to decommission Transient objects from within a Decoraptor.

Entity Framework + Autofac - Random errors on save

Using autofac as my IoC framework.
I'd like to be able to set up my DbContext instance in my application's startup.
In my ASP.NET MVC 3 project, I register DbContext instance in Global.asax (PerLifetimeScope). But when I fire up my site on multiple browsers (or multiple tabs) at once, sometimes I get Object reference not set to an instance of an object. or New transaction is not allowed because there are other threads running in the session when I try to save changes back to database. Also I get
ExecuteReader requires an open and available Connection. The connection's current state: Broken. sometimes when I want to read data from database.
the errors seem to pop up randomly and I suspect it has something to do with my context's lifetime scope. here's my DbContext's overriden SaveChange method.
public class MyContext : DbContext
{
public override int SaveChanges()
{
var result = base.SaveChanges(); // Exception here
}
}
Here's how I register my context:
builder.Register(c => new MyContext("SomeConnectionString"))
.InstancePerLifetimeScope();
If I just have one open tab of my site in the browser everything works ok.
Also, It's worth mentioning I have CRUD operations with db every 5-10 seconds in my website by calling a controller method using Ajax.
StackTrace for New transaction is not allowed because there are other threads running in the session:
at System.Data.EntityClient.EntityConnection.BeginDbTransaction(IsolationLevel isolationLevel)
at System.Data.EntityClient.EntityConnection.BeginTransaction()
at System.Data.Objects.ObjectContext.SaveChanges(SaveOptions options)
at System.Data.Entity.Internal.InternalContext.SaveChanges()
at System.Data.Entity.Internal.LazyInternalContext.SaveChanges()
at System.Data.Entity.DbContext.SaveChanges()
at MyProject.Data.MyContext.SaveChanges() in D:\Test.cs
StackTrace for Object reference not set to an instance of an object.:
at System.Data.Objects.ObjectStateManager.DetectConflicts(IList`1 entries)
at System.Data.Objects.ObjectStateManager.DetectChanges()
at System.Data.Entity.Internal.InternalContext.DetectChanges(Boolean force)
at System.Data.Entity.Internal.InternalContext.GetStateEntries(Func`2 predicate)
at System.Data.Entity.Internal.InternalContext.GetStateEntries()
at System.Data.Entity.Infrastructure.DbChangeTracker.Entries()
at System.Data.Entity.DbContext.GetValidationErrors()
at System.Data.Entity.Internal.InternalContext.SaveChanges()
at System.Data.Entity.Internal.LazyInternalContext.SaveChanges()
at System.Data.Entity.DbContext.SaveChanges()
at MyProject.Data.MyContext.SaveChanges() in D:\Test.cs at
Registration of MyContext looks ok. Is it possible that some other service that takes a MyContext is registered as a singleton and being shared across threads?
I had the same issue, sporadic errors related to the DbContext while using Autofac to resolve the DbContext.
{System.Data.EntityCommandExecutionException: An error occurred while executing the command definition. See the inner exception for details.
etc.
{System.NullReferenceException: Object reference not set to an instance of an object.
at System.Data.Objects.ObjectStateManager.DetectConflicts(IList`1 entries)
etc.
I found a class resembling the following in my code. The dependency resolution was occurring within a static method inside of the singleton. The object being resolved had a dependency on the DbContext. I haven't had any additional issues after I found a way to restructure this class so that it was no longer a singleton.
Perhaps you have a similar situation? Another thing to try might be to make your DbContext InstancePerHttpRequest. That could help identify whether this is the issue.
public class Singleton
{
private static Singleton _instance = new Singleton();
private Singleton()
{
}
public static void DoSomething<TSource>(TSource source) where TSource : ISource
{
var items = DependencyResolver.Current.Resolve<IEnumerable<IDbContextConsumer<TSource>>>();
foreach (var item in items)
{
item.Execute(source);
}
}
}

Where does Unit Of Work belong w/ EF4, IoC (Unity), and Repository?

I see several questions relating somewhat to this, but I still can't find the answer I'm looking for, so I'm posting my question. If another question holds the answer (and I'm just not seeing it), please point me to it.
I'm trying to figure out where my UnitOfWork belongs -- and specifically, gets created -- when using EF4 and Unity with the Repository pattern.
Basically, I have a service that is used to implement my business logic. This service constructor takes in the repository, so the service gets injected with my repository. The service then uses the injected repository to carry out actions against the data store -- but I need to wrap these in a unit of work.
My unit of work, however, needs to be injected with the EF4 context (or, in my case, and interface of the context -- IObjectContext). And I'm not sure where the UoW should be created and injected w/ the context.
Here are the possible options I can think of, none of which seem ideal:
Include the UoW in the service constructor, thus having the service injected w/ the unit of work, which in turn is injected w/ my EF4 context. But this seems wrong because I don't want my UoW created on every instance of the repository.
Do an on-demand creation using container.Resolve to get an instance of the UoW, injecting my EF4 context. This seems excessive having to constantly hit the IoC container, rather than already having access to the UoW.
Inject the context directly into the service, allowing me to create a UoW(context). This seems bad since I've now exposed the context to the service, and this should be isolated to the repository.
So my question is, is one of these methods acceptable, or is there another method I'm not thinking of?
Thanks in advance.
There are probably several ways how to use this so I will describe one which I found useful.
Imho the place to define UoW is in Application logic - the logic which calls your business layer (business services). The reason for this is that UoW should represent logical business trasaction - application logic (or service facade in case of remote calls) defines what is logical transaction. So for example in MVC you can go with architecture where each controller action represents single UoW:
public class MyController : Controller
{
public MyController(IFirstService firstService, ISecondService secondService,
IUnitOfWork unitOfWork)
{ ... }
[HttpPost]
public ActionResult SomeAction(Model data)
{
_firstService.SomeProcessing(data);
_secondService.SomeProcessing(data);
_unitOfWork.SaveChanges();
return RedirectToAction(...);
}
}
In this example my controller is depenent on two business services and action calls them both - UoW then save changes performed by both services. That is the reason why I think the UoW should be available in controller because if your application layer don't have access to UoW you can't compose (reuse) your logic from several service calls (because each probably calls its own SaveChanges).
Other approach is with service facade. Facade will be public interface of your business layer and it will hide service composition:
_firstService.SomeProcessing(data);
_secondService.SomeProcessing(data);
_unitOfWork.SaveChanges();
In such case UoW will not be passed to controller but to service facade and service facade will be injected to controller. You will definitely use this approach if your business logic will be exposed over web service (or other remote technology).
The last problem which you have to deal with is passing UoW to services. Services as well as UoW are injected into controller (presenter, service facade or whatever) but in the same time UoW (or ObjectContext) must be injected into services so that internally used repositories can work with it. For this you need correct IoC lifetime manager so that it returns same instance for all injections within same "request". In case of web application you need PerHttpRequest lifetime manager (which you must implement by yourselves because Unity does not provide it).
One way is to manage this is to use the method described in http://mfelicio.wordpress.com/2010/02/07/managing-the-entity-framework-objectcontext-instance-lifetime-in-wcf-and-sharing-it-among-repositories/ That article implements the ContextManager for Wcf services. For ASP.NET app we could use something like this.
public class AspNetDBContextManager<TContext> : IDBContextManager
where TContext : IDBContext, new()
{
#region IDBContextManager Members
public IDBContext GetDBContext()
{
return this.GetOrCreateDbContext();
}
private IDBContext GetOrCreateDbContext()
{
if (HttpContext.Current == null)
{
throw new InvalidOperationException("Can be used only within ASP.NET applications");
}
string dbContextKey = string.Format("__AspNetDBCM__{0}__", HttpContext.Current.GetHashCode());
object dbContext = HttpContext.Current.Items[dbContextKey];
if (dbContext == null)
{
dbContext = new TContext();
if (dbContext != null)
{
HttpContext.Current.Items[dbContextKey] = dbContext;
}
}
return dbContext as IDBContext;
}
#endregion
}
public interface IDBContext
{
object Context { get; }
}
public interface IDBContextManager
{
IDBContext GetDBContext();
}