HI
I have a dotnet core generic host.
There i have DbContexts (EF Core) registered as InstancePerDependency.
There is a factory creating them:
builder.Register(c=> new AutofacDbFactory(c.Resolve
That has:
c#
public TContext Create<TContext>() where TContext : IDisposable
{
return _resolve.Resolve<TContext>();
}
The issue is, i seam to have a memory leak. If i do tests where i new a "real" DbContext, no issues., Buit when Autofac is resulving, it is like autofac is not releasing. Even though i dispose.
I have tried registering the DbContexts as with "ExternallyOwned" but this does not help.
It seams like the container is not releaseing the object.
Is the only why to release it to use scopes?
If the container is not "tracking" (castle windsor language) the transient object, can i not release manually?
You should read through the docs on disposal.
The short version:
IDisposable from Autofac, Autofac tracks and disposes of it, not you.Owned<T> during resolve or ExternallyOwned() in registrations.IDisposable will for those things... will then happen in the root container.This is going to stretch into things that are in the TContext resolve chain, too. If you have MyDbContext and it needs a MyDependency that is _also_ disposable, both the MyDbContext _and_ the MyDependency will be held in the root container for disposal unless you opt them both out.
Yes, I thought it was the container not releasing the DbContext underlying objects. but it appears to be something different.
Sorry for wasting your time.
Either way, i know you have the scopes and other methods of disposing, but i still think the option to a manual "Release" is s good idea.
c=> new AutofacDbFacto
Sorry i know the issue closed, but i have having issues setting up a generic dbcontext with autofac? Could you share how you have coded it please?
I have more than 1 dbcontext (efcore) in my webapi (aspnetcore) and then generic repo patterns that feeds off that. I have been strugglign to set something up for a few days now and would love a steer if possible?
@iby-dev I had to ad externally owned to the Context registration, and manually dispose the context.
There was some other stuff too, but i don't think this was related.
Any chance you could share some code on how you are creating your dbcontext and registering it?
I am stuck like crazy on this issue, as i have said above i need a steer on how best register and setup a generic dbcontext in EFCORE with Autofac. I have a feeling from the above code snippet you may have solved this issue previously? Any chance you could help me out?
@iby-dev I would love to help.
But it might not be so sime.
I have based my efcore implemenation on https://github.com/generik0/Smooth.IoC.Dapper.Repository.UnitOfWork
The ISession is just a IDbContext. And i use a factory pattern (that autofac is not so good at):
```c#
public static void LoadEfCore2Factory(this ContainerBuilder builder)
{
builder.Register(c=> new AutofacDbFactory(c.Resolve
builder.RegisterType
builder.RegisterType
builder.RegisterGeneric(typeof(DbContextMigrator<>)).As(typeof(IDbContextMigrator<>)).SingleInstance();
var assemblies = AssemblyHelper.GetProjectAssemblies().ToArray();
builder.RegisterAssemblyTypes(assemblies)
.Where(type => type.GetInterfaces().Any(x=>x==typeof(IDbContext)))
.AsImplementedInterfaces()
.InstancePerDependency()
.ExternallyOwned()
.PreserveExistingDefaults();
}
[NoDefault]
private sealed class AutofacDbFactory : IDbFactory
{
private readonly IComponentContext _resolve;
internal AutofacDbFactory(IComponentContext resolve)
{
_resolve = resolve;
}
public TContext Create<TContext>() where TContext : IDisposable
{
if (_resolve.IsRegistered(typeof(TContext)))
{
return _resolve.Resolve<TContext>();
}
throw new ArgumentException($"The type is not registered: {typeof(TContext).Name}");
}
public TTransaction Create<TTransaction>(IDbFactory dbFactory, IDbContext dbContext,
IsolationLevel isolationLevel = IsolationLevel.RepeatableRead) where TTransaction : class, IDbTransaction
{
return _resolve.Resolve<TTransaction>(new NamedParameter("dbFactory", dbFactory),
new NamedParameter("db", dbContext), new NamedParameter("isolationLevel", isolationLevel));
}
public TUnitOfWork Create<TUnitOfWork>(IDbFactory dbFactory, IDbContext dbContext, bool sharedContext,
IsolationLevel isolationLevel = IsolationLevel.RepeatableRead) where TUnitOfWork : class, IUnitOfWork
{
return _resolve.Resolve<TUnitOfWork>(new NamedParameter("dbFactory", dbFactory),
new NamedParameter("db", dbContext), new NamedParameter("shareContext", sharedContext),
new NamedParameter("isolationLevel", isolationLevel));
}
public TUnitOfWork Create<TContext, TUnitOfWork>(IsolationLevel isolationLevel = IsolationLevel.RepeatableRead) where TContext : class, IDbContext where TUnitOfWork : class, IUnitOfWork
{
return Create<TUnitOfWork>( _resolve.Resolve<IDbFactory>(), _resolve.Resolve<TContext>(), false, isolationLevel);
}
public void Release(IDisposable instance)
{
;
}
}
```
@generik0 - ty - that looks interesting.
I managed to solve all of my autofac, generic db context problems now but i will take a look at that package.
Cheers.