Autofac - DataContext not being disposed at end of lifetime scope - c#

I have a command-line program which is importing data into my system. Because it's inserting data into many tables, I require change tracking. To try and prevent the job from slowing down over time, I have used Autofac (my dependency injection framework) to create an inner lifetime scope from which I resolve dependencies. At the end of each batch, I recreate the lifetime scope and get new instances of my dependencies. The problem is that when I do this, my DataContext which the UnitOfWork depends on is not being refreshed each time, leading to a situation where the job slows down and eventually terminates before completing.
I can see this when debugging by setting the 'Make Object ID' on my DbContext, e.g.
After each batch, the object ID remains $2, demonstrating that the DataContext instance is not getting a new instance. Why is it not getting a new instance?
My code looks something like this:
foreach (var batch in data.Batch(10))
{
using (var scope = LifetimeScope.BeginLifetimeScope(b =>
{
b.RegisterType<UnitOfWork>.AsImplementedInterfaces().PropertiesAutowired().InstancePerLifetimeScope();
b.RegisterType<MyService1>.AsImplementedInterfaces().PropertiesAutowired().InstancePerLifetimeScope();
b.RegisterType<MyService2>.AsImplementedInterfaces().PropertiesAutowired().InstancePerLifetimeScope();
b.RegisterGeneric(typeof(EntityBaseRepository<>)).As(typeof(IEntityBaseRepository<>)).InstancePerLifetimeScope();
}))
{
UnitOfWork = scope.Resolve<IUnitOfWork>();
MyService1 = scope.Resolve<IMyService1>();
MyService2 = scope.Resolve<IMyService2>();
Thing1Repository = scope.Resolve<IEntityBaseRepository<Thing1Repository>>();
Thing2Repository = scope.Resolve<IEntityBaseRepository<Thing2Repository>>();
foreach (var row in batch)
{
try
{
ParseRow(row);
}
catch (Exception e)
{
JobLogger.Error(e, "Failed to parse row. Exception: " + e.Message);
throw;
}
}
}
}
It was my understanding that when I get a new instance of my dependencies, the child dependencies will get new instances as well? Why is the original DataContext still hanging about?
My UnitOfWork looks like this:
public class UnitOfWork : Disposable, IUnitOfWork
{
private readonly IDbFactory _dbFactory;
private DataContext _dbContext;
public UnitOfWork(IDbFactory dbFactory)
{
_dbFactory = dbFactory;
}
public DataContext DbContext => _dbContext ?? (_dbContext = _dbFactory.Initialise());
public void Commit()
{
DbContext.Commit();
}
}
My DbFactory is responsible for creating a new instance of my DataContext:
public class DbFactory : Disposable, IDbFactory
{
DataContext _dbContext;
public DbFactory()
{
_dbContext = new DataContext();
}
public DataContext Initialise()
{
return _dbContext ?? (_dbContext = new DataContext());
}
protected override void DisposeCore()
{
_dbContext?.Dispose();
}
}
My services are registered by scanning the assembly when the program first starts by calling this method:
AutofacConfig.InitialiseJobRunner();
Inside this method, I register my types like this:
builder.RegisterType<DataContext>().AsSelf().InstancePerMatchingLifetimeScope(lifetimeScope);
builder.RegisterGenericInstance(typeof(EntityBaseRepository<>), typeof(IEntityBaseRepository<>), lifetimeScope);
builder.RegisterAssemblyInterfaces(Assembly.Load(Data), lifetimeScope);
RegisterAssemblyInterfaces is implemented as:
public static IRegistrationBuilder<object, ScanningActivatorData, DynamicRegistrationStyle>
RegisterAssemblyInterfaces(this ContainerBuilder builder, Assembly assembly, object lifetimeScope)
{
return builder.RegisterAssemblyTypes(assembly)
.AsImplementedInterfaces()
.InstancePerMatchingLifetimeScope(lifetimeScope);
}

As you register assembly interfaces like below
public static IRegistrationBuilder<object, ScanningActivatorData, DynamicRegistrationStyle>
RegisterAssemblyInterfaces(this ContainerBuilder builder, Assembly assembly, object lifetimeScope)
{
return builder.RegisterAssemblyTypes(assembly)
.AsImplementedInterfaces()
.InstancePerMatchingLifetimeScope(lifetimeScope);
}
my guess is that your DbFactory is also registered this way. In such case (according to: https://autofac.readthedocs.io/en/latest/lifetime/instance-scope.html#instance-per-matching-lifetime-scope ) you will get the same instance of your factory as your child scope is not named. Try to add
b.RegisterType<DbFactory>.AsImplementedInterfaces().PropertiesAutowired().InstancePerLifetimeScope();
in your loop or change DbFactory to always return new context in Initialise method instead returning the same if it's already instantiated.

Related

Access dependency-injected Entity Framework database from static class method

In my project, I have a static converter method to convert client and database objects into each other. One of those static methods needs to access the database. Before introducing dependency injection into my project, that was quite simple:
internal async static Task<ViewerColumn> FromClientColumn(ViewerColumnSettings col) {
using MpaContext db = new MpaContext();
return new ViewerColumn() {
// ...
SourceColumnID = await db.SourceColumns
.Where(sc => sc.Key == col.DataField)
.Select(sc => sc.ID)
.SingleAsync()
};
}
I want to change this by introducing dependency injection project-wide. My first approach was to simply add the database context as a separate parameter:
internal async static Task<ViewerColumn> FromClientColumn(ViewerColumnSettings col, MpaContext context) {
using MpaContext db = context;
// ...
}
This, however, leads to problems, if the context from the parameter gets disposed somewhere else. So my idea was to dependency-inject the context to the class inself. This, however, doesn't work, because you obviously can't use parameters for static constructors.
Here's how the method is called (currently with the context parameter):
// Controller method with dependency injection
[HttpPut("ViewerRoles/{vrID}")]
public async Task<ActionResult> UpdateViewSettings(int vrID, ViewerRoleSettings updatedData) {
using MpaContext db = _mpaContext;
await storedViewerRole.ApplyViewerRoleSettingsAsync(updatedData, _mpaContext);
}
// ViewerRole.cs
internal async Task ApplyViewerRoleSettingsAsync(ViewerRoleSettings updatedData, MpaContext context) {
// Create new entries
foreach (Client.ViewerColumnSettings col in updatedData.ViewerColumns) {
ViewerColumns.Add(await ViewerColumn.FromClientColumn(col, context));
}
}
This approach fails, because the context gets disposed in UpdateViewSettings and in FromClientColumn.
What's the best-practice approach for such a case? I could dispose the context only, if it wasn't open beforehand, but that sounds stupid to me.
Dependency Inversion / Dependency Injection does not play well with static.
Make an abstraction and derived implementation with injected context
public class ViewerColumnService : IViewerColumnService {
private readonly MpaContext db ;
public ViewerColumnService (MpaContext db) {
this.db = db;
}
public async Task<ViewerColumn> FromClientColumn(ViewerColumnSettings col) {
return new ViewerColumn() {
// ...
SourceColumnID = await db.SourceColumns
.Where(sc => sc.Key == col.DataField)
.Select(sc => sc.ID)
.SingleAsync()
};
}
}
Register this new service and explicitly inject it where it is needed. Stop manually disposing of the context by wrapping it in a using statement. Let the DI container handle the lifetime of the components.

Autofac - memory leak

I've created simple factory to creating Entity Framework's DbContext. It's implemented like this (simplified code):
public class ContextFactory : IContextFactory
{
private Func<IDbContext> _dbContext;
public ContextFactory(Func<IDbContext> dbContext)
{
_dbContext = dbContext;
}
public IDbContext CreateContext()
{
var context = _dbContext();
context.Configuration.ProxyCreationEnabled = false;
return context;
}
}
As you see DbContext is injected to my factory as Func and created every time when CreateContext() is called.
Registration in bootstrapper is:
builder
.RegisterType<ContextFactory>()
.As<IContextFactory>()
.SingleInstance();
So factory is singleton and context registration:
builder
.RegisterType<OdynDbContext>()
.AsImplementedInterfaces()
.InstancePerDependency();
is instance per dependency.
I use created context in using() block so it should be disposed every time:
public TestClass
{
private readonly IContextFactory _contextFactory;
public TestClass(IContextFactory contextFactory)
{
_contextFactory = contextFactory;
}
public void TestMethod()
{
using(var context = _contextFactory.CreateContext())
{
... operations on context
}
}
And unfortunately context isn't disposed correctly. It stays somewhere in memory and causes leak. I don't know why. I overrided Dispose() method in DbContext and it is called. Anyone has met with such a problem?
The answer is to use .ExternallyOwned() extension method while registering DbContext:
builder
.RegisterType<DbContext>()
.AsImplementedInterfaces()
.ExternallyOwned()
Then wrapping it in using block causes proper disposal of object.

Unable to register DbConnection with Unity and Entity Framework

I am not at all sure what the underlying problem is that is causing this exception.
I am using ASP.NET MVC, with Unity.Mvc, and Entity Framework 6. I have the following code to register my repositories:
public static void RegisterTypes(IUnityContainer container)
{
// NOTE: To load from web.config uncomment the line below. Make sure to add a Microsoft.Practices.Unity.Configuration to the using statements.
// container.LoadConfiguration();
// TODO: Register your types here
// container.RegisterType<IProductRepository, ProductRepository>();
container.RegisterType<IGenericRepository<Customer>, GenericRepository<Customer>>();
container.RegisterType<IGenericRepository<Product>, GenericRepository<Product>>();
container.RegisterType<IGenericRepository<Order>, GenericRepository<Order>>();
container.RegisterType<IGenericRepository<OrderItem>, GenericRepository<OrderItem>>();
container.RegisterType<IGenericRepository<Supplier>, GenericRepository<Supplier>>();
}
And then in a controller I have:
public class IndexController : Controller
{
public IndexController(IGenericRepository<Customer> testGenericRepository)
{
var result = testGenericRepository.SelectAll();
}
public ActionResult Index()
{
return View();
}
}
And the repository has the following code:
public class GenericRepository<T> : IGenericRepository<T>
where T : class
{
private readonly DbContext _dbContext;
private readonly IDbSet<T> _dbSet;
public GenericRepository(DbContext dbContext)
{
if (dbContext == null)
{
throw new ArgumentNullException(nameof(dbContext));
}
_dbContext = dbContext;
_dbSet = _dbContext.Set<T>();
}
public IEnumerable<T> SelectAll()
{
return _dbSet.AsEnumerable<T>();
}
}
The problem that I'm having is that if I have a breakpoint in the "RegisterTypes" method, I can see that the container is definitely getting all the repositories registered, but a breakpoint in the constructor of the repositories never gets hit.
So I think that the fact that the breakpoint does not get hit, and I have not registered a "System.Data.Common.DbConnection" means that the DbContext that the repository uses never gets set.
I can't find any useful information about how to use "System.Data.Common.DbConnection" with Unity and the DbContext from Entity Framework.
How do I resolve this?
You should add to your RegisterTypes how to build your DbContext, and probably with which lifetime.
If you have your own class (say CustomContext) inheriting from DbContext, register it. Supposing your default lifetime is adequate:
container.RegisterType<DBContext, CustomContext>();
If you use directly DbContext, instruct Unity which constructor it should use. By example, supposing your connection string is named appConnectionString:
container.RegisterType<DBContext>(
new InjectionConstructor("name=appConnectionString"));

Using IAuthorizationFilter with Ninject and EF gives DbContext has been disposed error

I'm trying to use my UnitOfWork inside an implementation of IAuthorizationFilter, but after I navigate between a few pages I get this exception:
System.InvalidOperationException: The operation cannot be completed because the DbContext has been disposed.
FilterConfig.cs
filters.Add(DependencyResolver.Current.GetService(typeof(PermissionFilter)));
NinjectMappings.cs
public class NinjectMappings : NinjectModule
{
public override void Load()
{
Bind<MyContext>().ToSelf().InRequestScope();
Bind<IUnitOfWork>().To<UnitOfWork>();
}
}
PermissionFilter.cs
public class PermissionFilter : IAuthorizationFilter
{
public PermissionFilter(IUnitOfWork unitOfWork)
{
// etc...
}
}
I was able to get around this with:
// NinjectMappings
Bind<IUnitOfWork>()
.ToMethod(m => GetUnitOfWork())
.WhenInjectedExactlyInto(typeof(PermissionFilter));
private IUnitOfWork GetUnitOfWork()
{
return new UnitOfWork(new MyContext());
}
The problem now is that GetUnitOfWork is only called once, at app start. I tried alternating between InTransientScope and InRequestScope to no avail. So updates to the database are not retrieved, instead my UnitOfWork always returns the same data.
I have read quite a few questions dealing with DbContext has been disposed but none of them were implementing an IAuthorizationFilter.
What is the best way to solve this? I'd like to avoid new or using() inside the filter or using the Service Locator pattern.
Your problem comes from the fact that your MyContext is instantiated in the scope of a request and is disposed at the end of the request.
To solve this avoiding new(), using, or ServiceLocator pattern, you may rely on a dedicated IFilterProvider
public class PermissionFilterProvider : IFilterProvider
{
private readonly Func<PermissionFilter> _permissionFilterFactory = null;
public PermissionFilterProvider(Func<PermissionFilter> filterFactory)
{
_permissionFilterFactory = filterFactory;
}
public IEnumerable<Filter> GetFilters(ControllerContext controllerContext, ActionDescriptor actionDescriptor)
{
var filters = new List<Filter>();
// instantiate PermissionFilter action filter
filters.Add(new Filter(_permissionFilterFactory(), FilterScope.Action, 0));
return filters;
}
}
Your bindings would then be :
public class NinjectMappings : NinjectModule
{
public override void Load()
{
Bind<MyContext>().ToSelf().InRequestScope();
Bind<IUnitOfWork>().To<UnitOfWork>();
Bind<IFilterProvider>().To<PermissionFilterProvider>();
Bind<PermissionFilter>().ToSelf();
}
}
Note that you will need an Ninject Factory extension like Ninject.Extensions.Factory to achieve the Func<PermissionFilter> factory pattern in PermissionFilterProvider constructor.
Also, I am not sure of the scope of your IUnitOfWork. Shouldn't it be the same as your MyContext ?

How to use Ninject in a multi-threaded Windows service to get new instances of a dependency (DbContext) on every tick?

I have inherited a Windows service where all the dependencies are created when the service starts and are injected in the transient scope.
We are having a number of problems with this service, not least we have a DbContext which lives for the whole time the service is running, and different instances of it are injected each time.
I would like to refactor so that each worker thread gets it’s own DbContext injected which will live for just the duration of each tick.
I have looked at the custom scope. It looks fine for a single threaded app, but not multi-threaded. I also considered InThreadScope. Whilst that would give each thread it’s own instance, they are singletons as far as the thread is concerned so it does not fulfil the per tick requirement.
My current thinking is to use the named scope extension and to inject a scope factory which I can use to create a new scope on every tick.
Is this the way to go? Any suggestions, tips or alternatives would be appreciated.
UPDATE
Due to a time constraint we ended up using the named scope, but it wasn't as clean as #BatteryBackupUnit's solution. There were some dependencies further down the graph which needed a DbContext and we had to inject the scope factory again to get it. Using #BatteryBackupUnit's solution we could have reused the same instance from the ThreadLocal storage instead.
Regarding Named Scope: Consider that when you are creating a DbContext from the same thread but from an object (p.Ex. factory) which was created before the scope was created, it won't work. Either it will fail because there is no scope, or it will inject another instance of DbContext because there is a different scope.
If you don't do this, then a scope like named scope or call scope can work for you.
We are doing the following instead:
When a DbContext is requested, we check a ThreadLocal
(http://msdn.microsoft.com/de-de/library/dd642243%28v=vs.110%29.aspx) whether there is already one. In case there is, we use that one. Otherwise, we create a new one and assign it to the ThreadLocal<DbContext>.Value.
Once all operations are done, we release the DbContext and reset the ThreadLocal<DbContext>.Value.
See this (simplified, not perfect) code for an example:
public interface IUnitOfWork
{
IUnitOfWorkScope Start();
}
internal class UnitOfWork : IUnitOfWork
{
public static readonly ThreadLocal<IUnitOfWorkScope> LocalUnitOfWork = new ThreadLocal<IUnitOfWorkScope>();
private readonly IResolutionRoot resolutionRoot;
public UnitOfWork(IResolutionRoot resolutionRoot)
{
this.resolutionRoot = resolutionRoot;
}
public IUnitOfWorkScope Start()
{
if (LocalUnitOfWork.Value == null)
{
LocalUnitOfWork.Value = this.resolutionRoot.Get<IUnitOfWorkScope>();
}
return LocalUnitOfWork.Value;
}
}
public interface IUnitOfWorkScope : IDisposable
{
Guid Id { get; }
}
public class UnitOfWorkScope : IUnitOfWorkScope
{
public UnitOfWorkScope()
{
this.Id = Guid.NewGuid();
}
public Guid Id { get; private set; }
public void Dispose()
{
UnitOfWork.LocalUnitOfWork.Value = null;
}
}
public class UnitOfWorkIntegrationTest : IDisposable
{
private readonly IKernel kernel;
public UnitOfWorkIntegrationTest()
{
this.kernel = new StandardKernel();
this.kernel.Bind<IUnitOfWork>().To<UnitOfWork>();
this.kernel.Bind<IUnitOfWorkScope>().To<UnitOfWorkScope>();
}
[Fact]
public void MustCreateNewScopeWhenOldOneWasDisposed()
{
Guid scopeId1;
using (IUnitOfWorkScope scope = this.kernel.Get<IUnitOfWork>().Start())
{
scopeId1 = scope.Id;
}
Guid scopeId2;
using (IUnitOfWorkScope scope = this.kernel.Get<IUnitOfWork>().Start())
{
scopeId2 = scope.Id;
}
scopeId1.Should().NotBe(scopeId2);
}
[Fact]
public void NestedScope_MustReuseSameScope()
{
Guid scopeId1;
Guid scopeId2;
using (IUnitOfWorkScope scope1 = this.kernel.Get<IUnitOfWork>().Start())
{
scopeId1 = scope1.Id;
using (IUnitOfWorkScope scope2 = this.kernel.Get<IUnitOfWork>().Start())
{
scopeId2 = scope2.Id;
}
}
scopeId1.Should().Be(scopeId2);
}
[Fact]
public void MultipleThreads_MustCreateNewScopePerThread()
{
var unitOfWork = this.kernel.Get<IUnitOfWork>();
Guid scopeId1;
Guid scopeId2 = Guid.Empty;
using (IUnitOfWorkScope scope1 = unitOfWork.Start())
{
scopeId1 = scope1.Id;
Task otherThread = Task.Factory.StartNew(() =>
{
using (IUnitOfWorkScope scope2 = unitOfWork.Start())
{
scopeId2 = scope2.Id;
}
},
TaskCreationOptions.LongRunning);
if (!otherThread.Wait(TimeSpan.FromSeconds(5)))
{
throw new TimeoutException();
}
}
scopeId2.Should().NotBeEmpty();
scopeId1.Should().NotBe(scopeId2);
}
public void Dispose()
{
this.kernel.Dispose();
}
}
Note: i'm using nuget packages: ninject, xUnit.Net, Fluent Assertions
Also note, that you can replace the IUnitOfWork.Start with a ToProvider<IUnitOfWorkScope>() binding. Of course you need to implement the corresponding logic in the provider.
A proper unit-of-work scope, implemented in Ninject.Extensions.UnitOfWork, solves this problem.
Setup:
_kernel.Bind<IService>().To<Service>().InUnitOfWorkScope();
Usage:
using(UnitOfWorkScope.Create()){
// resolves, async/await, manual TPL ops, etc
}

Categories

Resources