I am using ASP.Net MVC 4, EF and Unity for DI. Also uses UnitOfWork pattern. Trying to figure out the best way to implement this. I have the code like below.
The problem I am having is the Dispose() in Business and Repository layer never get called now, only the Destructor in both get called, so the objects seem to be never disposed.
Please answer the following
Do I really need the IDisposable implementation in Business and Repository layer (if Unity is already taking care of it)
What should I do to get the Dispose() called(should I add it to the Controller too and Dispose all other objects or use some specific LifeTime manager)
Whether I should use the Singleton Instance of each or dispose it in each request as it is in the web environment.
Global.asax.cs:
private static IUnityContainer _unityContainer;
protected void Application_Start()
{
_unityContainer = UnityBootstrapper.SetupUnity();
_unityContainer.RegisterType<IController, ProductController>("Product");
DependencyResolver.SetResolver(new Microsoft.Practices.Unity.Mvc.UnityDependencyResolver(_unityContainer));
}
UnityBootstrapper.cs:
public class UnityBootstrapper
{
public static IUnityContainer SetupUnity()
{
UnityContainer container = new UnityContainer();
container.RegisterType<IProductDbContext, ProductDbContext>()
.RegisterType<IUnitOfWork, UnitofWork>(new InjectionConstructor(new ResolvedParameter(typeof(IProductDbContext))))
.RegisterType<IProductRepository, ProductRepository>()
.RegisterType<IProductBusiness, ProductBusiness>();
}
}
ProductController.cs:
public class ProductController : ControllerBase
{
private readonly IProductBusiness _productBusiness;
public ProductController(IProductBusiness productBusiness)
{
_productBusiness = productBusiness;
}
//No Dispose for this
}
ProductBusiness.cs:
public class ProductBusiness : IProductBusiness, IDisposable
{
private readonly IUnitOfWork _unitOfWork;
private readonly IProductRepository _productRepository;
public ProductBusiness(IUnitOfWork unitOfWork)
{
_unitOfWork = unitOfWork;
_productRepository = _unitOfWork.ProductRepository;
}
public override void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
protected override void Dispose(bool disposing)
{
if (!_isDisposed)
{
if (disposing)
{
if (_productRepository != null) _productRepository.Dispose();
if (_unitOfWork != null) _unitOfWork.Dispose();
}
_isDisposed = true;
}
}
~ProductBusiness()
{
Dispose(false);
}
}
ProductRepository.cs:
public class ProductRepository : IProductRepository, IDisposable
{
private readonly IProductDbContext _context;
public ProductRepository(IProductDbContext context)
{
if (context == null)
throw new ArgumentNullException("context");
_context = context;
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool disposing)
{
if (!_isDisposed)
{
if (disposing)
{
if (_context != null) _context.Dispose();
}
_isDisposed = true;
}
}
~ProductRepository()
{
Dispose(false);
}
}
You don't really need to dispose objects, unless you do something specific during disposing process. DI containers take care of object lifetime for you.
Sometimes UoW implementation involves saving the changes on disposal. Try avoiding this. But if this is unavoidable, you can implement factory for that:
public interface IUnitOfWorkFactory
{
IUnitOfWork Create();
}
public class UnitOfWorkFactory : IUnitOfWorkFactory
{
public IUnitOfWork Create()
{
return new UnitOfWork();
}
}
public class UnitOfWork : IUnitOfWork, IDisposable
{
// other implementation
public void Dispose()
{
context.SaveChanges();
}
}
and then consumer will do something like this:
public MyController(IUnitOfWorkFactory workFactory)
{
this.workFactory = workFactory;
}
public ActionResult DoSomething()
{
using(var uow = workFactory.Create())
{
//do work
}
}
This DI book chapter talks about disposable objects.
While Unity will manage disposing of your registered types, you still have to call dispose on your IOC container so that it does it for them.
Do it from Application_End and it should be fine.
protected void Application_End()
{
_unityContainer .Dispose();
}
I believe if you set the correct LifetimeManager then no, you do not need to implement IDisposable as unity will handle disposing of your objects. This explains the different types of lifetime manager http://msdn.microsoft.com/en-us/library/ff660872(v=pandp.20).aspx.
Personally I have not used singletons, but just let the objects be created and then disposed of within each request.
You don't really need IDisposable on those classes since the main point of IDisposable is to clean up unmanaged resources. Take a look at these:
http://msdn.microsoft.com/en-us/library/system.idisposable(v=vs.110).aspx
Proper use of the IDisposable interface
Using the singleton pattern for your container can be helpful if you're using your container in a service location fashion. However, there are other (and arguably better) ways to use Unity or other DI/IoC containers. There are a few bootstrappers out there. For example:
https://www.nuget.org/packages/Unity.Mvc/
Related
I have the following method in the aspx file (.NET Framework 4.6.2 project):
public static string SetAvgPeriodDays(int userId)
{
var service = new AveragePeriodDaysService(EfHelper.GetContext());
try
{
return service.SetAveragePeriodDays(userId);
}
catch (Exception e)
{
return e.Message;
}
}
AveragePeriodDaysService class has a constructor that accepts DbContext instance:
public class AveragePeriodDaysService
{
private readonly MyDbContext _ctx;
public AveragePeriodDaysService(MyDbContext ctx)
{
_ctx = ctx;
}
public string SetAveragePeriodDays(int userId)
{
// main logic goes here...
}
}
And here EfHelper class:
public class EfHelper
{
public static MyDbContext GetContext()
{
var options = new DbContextOptionsBuilder<MyDbContext>();
var connectionString = ...
options.UseSqlServer(connectionString);
options.UseQueryTrackingBehavior(QueryTrackingBehavior.NoTracking);
return new MyDbContext(options.Options);
}
}
Question. Should I dispose MyDbContext? If yes, how should I do it properly?
As a rule you should never dispose dependencies that you got from outside because you never know who else uses same instance of this dependency. It means AveragePeriodDaysService can't dispose MyDbContext. But SetAvgPeriodDays knows exactly who will consume MyDbContext because it requested the creation of MyDbContext, hence it can and should dispose it after usage. Use using keyword:
public static string SetAvgPeriodDays(int userId)
{
using(var ctx = EfHelper.GetContext())
{
var service = new AveragePeriodDaysService(ctx);
try
{
return service.SetAveragePeriodDays(userId);
}
catch (Exception e)
{
return e.Message;
}
}
}
I'm actually not so sure what the correct patterns for this are, but I normally go with the following approach (something like the .NET Stream or SafeHandle classes do):
Your AveragePeriodDaysService really seems to take control of the context (it stores it in a private readonly field). So actually this class should implement IDisposable and dispose of the context itself.
On the other hand, you might want to use a single context for different "service" classes without always creating a new one. So it would be annoying if these classes always dispose the context.
So my way of implementing it would be something like this:
public class AveragePeriodDaysService : IDisposable
{
private readonly MyDbContext _ctx;
private readonly bool _ownContext;
public AveragePeriodDaysService(MyDbContext ctx, bool ownContext)
{
_ctx = ctx;
_ownContext = ownContext;
}
protected virtual void Dispose(bool disposing)
{
if (disposing) GC.SuppressFinalize(this);
if (_ownContext) _ctx.Dispose();
}
public void Dispose()
{
Dispose(true);
}
Then you can decide if the created instance should be responsible for disposing the context or if the creator needs to keep control.
Of course, if the created instance should take control, you need to properly dispose of this instance.
We are in the middle of attempting a drop-in replacement of Autofac for Ninject in our windows service (before potentially making more enhancement to take care of Autofac features), but are running into a memory issue.
Here's a contrived example that doesn't reproduce our issue, but demonstrates the current layout of the app:
class Program
{
static void Main(string[] args)
{
ContainerBuilder builder = new ContainerBuilder();
var ms = new MemoryStream(new byte[10000000]);
var ms2 = new MemoryStream(new byte[10000000]);
builder.RegisterType<BaseRepo>()
.WithParameter("ms", ms)
.As<IBaseRepo>();
builder.RegisterType<DerivedRepo>()
.WithParameter("ms", ms2)
.As<IDerivedRepo>();
builder.RegisterType<BaseFactory>().As<IBaseFactory>();
builder.RegisterType<Derived>().AsSelf();
builder.RegisterType<Derived>().Keyed<Base>(BaseEnum.Derived).As<Base>();
var container = builder.Build();
var factory = container.Resolve<IBaseFactory>();
while (true)
{
var instance = factory.Create(BaseEnum.Derived);
instance.DoSomething();
instance.Dispose();
Thread.Sleep(5000);
}
}
}
public interface IDerivedRepo : IDisposable {}
public class DerivedRepo : IDerivedRepo
{
private readonly MemoryStream _ms;
public DerivedRepo(MemoryStream ms)
{
_ms = ms;
}
public void Dispose()
{
_ms.Dispose();
}
}
public interface IBaseRepo : IDisposable {}
public class BaseRepo : IBaseRepo
{
private readonly MemoryStream _ms;
public BaseRepo(MemoryStream ms)
{
_ms = ms;
}
public void Dispose()
{
_ms.Dispose();
}
}
public enum BaseEnum
{
Derived = 1
}
public interface IBaseFactory
{
Base Create(BaseEnum baseEnum);
}
public class BaseFactory : IBaseFactory
{
private readonly IComponentContext _componentContext;
public BaseFactory(IComponentContext componentContext)
{
_componentContext = componentContext;
}
public Base Create(BaseEnum baseEnum)
{
return _componentContext.ResolveOptionalKeyed<Base>(baseEnum);
}
}
public interface IDisposableThing : IDisposable
{
void DoSomething();
}
public abstract class Base : IDisposableThing
{
protected readonly IBaseRepo BaseRepo;
protected Base(IBaseRepo baseRepo)
{
BaseRepo = baseRepo;
}
public void Dispose()
{
Console.WriteLine("Disposing base");
BaseRepo.Dispose();
}
public abstract void DisposeChildren();
public void DoSomething()
{
Console.WriteLine("Doing something");
}
}
public class Derived : Base
{
private readonly IDerivedRepo _derivedRepo;
public Derived(IBaseRepo baseRepo, IDerivedRepo derivedRepo) : base(baseRepo)
{
_derivedRepo = derivedRepo;
}
public override void DisposeChildren()
{
Console.WriteLine("Disposing derived");
_derivedRepo.Dispose();
}
}
Basically, we--at regular intervals--use a factory to instantiate an instance of an abstract class based on an enum value, do some work with that instance, then dispose of it. The problem is that those instances are not getting cleaned up by the garbage collector and the memory usage of the app increases steadily, with DebugDiag2 reporting that it is holding onto instances of the equivalent of our MemoryStream members in our repos (in our real app, these are wrappers over Entity Framework DBContext), with no other references to our code reported in its analysis so I have nothing else to go on.
I know there probably isn't enough here to give a definitive answer, what I'm more looking for is suggestions on where we are obviously doing something wrong (the whole team is new to Autofac and I know we are using the service locator anti-pattern, but I assume that isn't causing the problems we are seeing).
The behavior you experience is normal as Autofac keeps track, within a lifetime scope, of objects it resolves. These will be disposed when the associated lifetime scope is itself disposed. In your case, you only have one lifetime scope, the one created when you build the container from the builder.
I suggest that you have a good read of this documentation page which explains more in detail how lifetime scopes work.
A starting point would be to create an inner lifetime scope every time you start new work within the regular interval. It could look something like this:
var container = builder.Build();
while (true)
{
// Create an inner lifetime scope that will keep track of every
// object it creates
using (var lifetimeScope = container.BeginLifetimeScope())
{
// resolve objects from `lifetimeScope`
// do work with them
}
// At the end of the using directive, lifetimeScope will be disposed
// and will dispose with it any objects it kept track of
Thread.Sleep(5000);
}
Plain and simple as the title suggests, is this a possible thing using Autofac dependency injection? I have been trying and searching everywhere.. I'm losing hope here.
My class has to be singleton - that can't change. I want it to take a factory of unit of works - for database transactions.
Please help me figure this one out, I'm deseperate.
Tried Func<> and registering my unit of work in every possible way (all sorts of lifetimes, externally owned or not) but failed because the DbContext within the unit of work is disposed and not created again after the first request
Edit:
Added code that will hopefully help understanding my problem:
public class SingletonDataService : IDataService
{
private _uowFactory;
public SingletonDataService(Func<IEFUnitOfWork> uowFactory)
{
_uowFactory = uowFactory
}
public List<Folder> GetAllFolders ()
{
using (uow = uowFactory())
{
return uow.FoldersRepository.GetAll();
}
}
}
public MyDbContext : DbContext
{
public DbSet<Folder> Folders {get; set;}
public DbSet<Letter> Letters {get; set;}
public MyDbContext() : base("myContext...")
}
public EFUnitOfWork : IEFUnitOfWork, IDisposable
{
public IRepository<Folder> FoldersRepository;
public IRepository<Letter> LettersRepository;
private DbContext _context;
public EFUnitOfWork(IRepository<Folder> folders, IRepository<Letter> letters, DbContext context)
{
_folders = folders;
_letters = letters;
_context = context;
}
private bool disposed = false;
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool disposing)
{
if (!disposed)
{
if (disposing)
{
_context.Dispose();
}
disposed = true;
}
}
}
public Repository<T> : IRepository<T> where T: BaseEntity
{
private DbContext _context;
private DbSet<T> _set
public Repository(DbContext context)
{
_context = context;
_set = _context.Set<T>();
}
}
public LettersController : ApiController
{
private IDataService _dataService;
public LettersController(IDataService dataService)
{
_dataService = dataService;
}
[HttpGet]
public IHttpActionResult GetAllLetters()
{
return Ok(_dataService.GetAllLetters());
}
}
// Must be singleton
builder.Register<SingletonDataService>().As(IDataService).SingleInstance();
builder.RegisterGeneric(typeof(Repository<>))
.As(typeof(IRepository<>))
.InstancePerLifetimeScope();
builder.Register<EFUnitOfWork>().As(IEFUnitOfWork).InstancePerLifetimeScope();
builder.Register<DbContext>().As(AppDbContext).InstancePerLifetimeScope();
In the first request everything works fine, in the second third and so on I get this exception :
system.ObjectDisposedException: The ObjectContext instance has been disposed and can no longer be used for operations that require a connection.
I clearly see it happens because the context in my repository is now null, but I don't how to to change that with the DI.
What I want to achieve is so easy without DI :
How can I achieve the following with Autofac??
public class UowFactory
{
public UowFactory()
{
}
public IEFUnitOfWork Create()
{
var context = new AppDbContext()
var uow = new EFUnitOfWork(new Repository<Folder>(context), new Repository<Letter>(context), context);
return uow;
}
}
Issue
You are registering the critial components with InstancePerLifetimeScope()
When the autofac container is built it also creates a root ILifetimeScope which lives until IContainer.Dispose() is called. Now unless you create nested ILifetimeScope somewhere in the chain to the SingletonDataService, the ILifetimeScope which is used your components is the root ILifetimeScope and InstancePerLifetimeScope() effectly becomes equivalent to SingleInstance().
Solution
One of the possible solutions is to create an ILifetimeScope per IEFUnitOfWork and its children. Autofac facilitates this by providing the Owned<T> type. We can use it in conjunction with a Func<> factory (also see documentation):
public class SingletonDataService : IDataService
{
private Func<Owned<IEFUnitOfWork>> _uowFactory;
public SingletonDataService(Func<Owned<IEFUnitOfWork>> uowFactory)
{
_uowFactory = uowFactory
}
public List<Folder> GetAllFolders ()
{
using (var uow = _uowFactory())
{
return uow.Value.FoldersRepository.GetAll();
}
}
}
This should play nicely with the following registrations:
// Must be singleton
builder.Register<SingletonDataService>().As(IDataService).SingleInstance();
builder.RegisterGeneric(typeof(Repository<>))
.As(typeof(IRepository<>))
.InstancePerLifetimeScope();
builder.Register<EFUnitOfWork>().As(IEFUnitOfWork).InstancePerLifetimeScope();
builder.Register<DbContext>().As(AppDbContext).InstancePerLifetimeScope();
However, note, that DbContext being bound with InstancePerLifetimeScope basically makes the manual disposal in EFUnitOfWork redundant.
Sidenote on proper Disposal
Since IDisposable types should support graceful multi-disposal , one should be able to simplify EFUnitOfWork.Dispose() to
public void Dispose()
{
_context.Dispose();
}
Also note, that i left out the call GC.SuppressFinalize(this);. This call is only relevant in case the class implements a custom finalizer (~EFUnitOfWork method) - or a deriving class could do so, otherwise the object is not put on the finalizer queue anyway.
Your problem is that you have a singleton (SingletonDataService) depend on a service that has a shorter lifetime (EFUnitOfWork). When the SingletonDataService instance is created by autofac, it gets an instance of EFUnitOfWork, but this instance will always stay the same (its actual lifetime will be longer than you expect) and thus gets disposed and used again, giving errors.
You have two possible solutions:
One is to create a UowFactory class like the one you defined at the bottom (but with dependencies on IRepository<Folder>, IRepository<Letter>, DbContext), register that as anything (for example singleton, but it won't matter) and make the SingletonDataService depend on it. This will likely not be a viable solution to you though, since it will also extend the lifetime of the IRepository<Folder>, IRepository<Letter>, DbContext instances and create problems there.
The proper solution is to remove the reason why you would want the SingletonDataService to be a singleton, probably some cache. And move it to a new service (CacheService?) on which the SingletonDataService depends and make that new service a singleton.
I'm trying to implement IoC in my windows form application. My choice fell on Simple Injector, because it's fast and lightweight. I also implement unit of work and repository pattern in my apps. Here is the structure:
DbContext:
public class MemberContext : DbContext
{
public MemberContext()
: base("Name=MemberContext")
{ }
public DbSet<Member> Members { get; set; }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
modelBuilder.Conventions.Remove<PluralizingTableNameConvention>();\
}
}
Model:
public class Member
{
public int MemberID { get; set; }
public string Name { get; set; }
}
GenericRepository:
public abstract class GenericRepository<TEntity> : IGenericRepository<TEntity>
where TEntity : class
{
internal DbContext context;
internal DbSet<TEntity> dbSet;
public GenericRepository(DbContext context)
{
this.context = context;
this.dbSet = context.Set<TEntity>();
}
public virtual void Insert(TEntity entity)
{
dbSet.Add(entity);
}
}
MemberRepository:
public class MemberRepository : GenericRepository<Member>, IMemberRepository
{
public MemberRepository(DbContext context)
: base(context)
{ }
}
UnitOfWork:
public class UnitOfWork : IUnitOfWork
{
public DbContext context;
public UnitOfWork(DbContext context)
{
this.context = context;
}
public void SaveChanges()
{
context.SaveChanges();
}
private bool disposed = false;
protected virtual void Dispose(bool disposing)
{
if (!this.disposed)
{
if (disposing)
{
context.Dispose();
}
}
this.disposed = true;
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
}
MemberService:
public class MemberService : IMemberService
{
private readonly IUnitOfWork unitOfWork;
private readonly IMemberRepository memberRepository;
public MemberService(IUnitOfWork unitOfWork, IMemberRepository memberRepository)
{
this.unitOfWork = unitOfWork;
this.memberRepository = memberRepository;
}
public void Save(Member member)
{
Save(new List<Member> { member });
}
public void Save(List<Member> members)
{
members.ForEach(m =>
{
if (m.MemberID == default(int))
{
memberRepository.Insert(m);
}
});
unitOfWork.SaveChanges();
}
}
In Member Form I only add a textbox to input member name and a button to save to database. This is the code in member form:
frmMember:
public partial class frmMember : Form
{
private readonly IMemberService memberService;
public frmMember(IMemberService memberService)
{
InitializeComponent();
this.memberService = memberService;
}
private void btnSave_Click(object sender, EventArgs e)
{
Member member = new Member();
member.Name = txtName.Text;
memberService.Save(member);
}
}
I implement the SimpleInjector (refer to http://simpleinjector.readthedocs.org/en/latest/windowsformsintegration.html) in Program.cs as seen in the code below:
static class Program
{
private static Container container;
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Bootstrap();
Application.Run(new frmMember((MemberService)container.GetInstance(typeof(IMemberService))));
}
private static void Bootstrap()
{
container = new Container();
container.RegisterSingle<IMemberRepository, MemberRepository>();
container.Register<IMemberService, MemberService>();
container.Register<DbContext, MemberContext>();
container.Register<IUnitOfWork, UnitOfWork>();
container.Verify();
}
}
When I run the program and add a member, it doesn't save to database. If I changed container.Register to container.RegisterSingle, it will save to database. From the documentation, RegisterSingle will make my class to be a Singleton. I can't using RegisterLifeTimeScope because it will generate an error
"The registered delegate for type IMemberService threw an exception. The IUnitOfWork is registered as 'Lifetime Scope' lifestyle, but the instance is requested outside the context of a Lifetime Scope"
1) How to use SimpleInjector in Windows Form with UnitOfWork & Repository pattern?
2) Do I implement the patterns correctly?
The problem you have is the difference in lifestyles between your service, repository, unitofwork and dbcontext.
Because the MemberRepository has a Singleton lifestyle, Simple Injector will create one instance which will be reused for the duration of the application, which could be days, even weeks or months with a WinForms application. The direct consequence from registering the MemberRepository as Singleton is that all dependencies of this class will become Singletons as well, no matter what lifestyle is used in the registration. This is a common problem called Captive Dependency.
As a side note: The diagnostic services of Simple Injector are able to spot this configuration mistake and will show/throw a Potential Lifestyle Mismatch warning.
So the MemberRepository is Singleton and has one and the same DbContext throughout the application lifetime. But the UnitOfWork, which has a dependency also on DbContext will receive a different instance of the DbContext, because the registration for DbContext is Transient. This context will, in your example, never save the newly created Member because this DbContext does not have any newly created Member, the member is created in a different DbContext.
When you change the registration of DbContext to RegisterSingleton it will start working, because now every service, class or whatever depending on DbContext will get the same instance.
But this is certainly not the solution because having one DbContext for the lifetime of the application will get you into trouble, as you probably already know. This is explained in great detail in this post.
The solution you need is using a Scoped instance of the DbContext, which you already tried. You are missing some information on how to use the lifetime scope feature of Simple Injector (and most of the other containers out there). When using a Scoped lifestyle there must be an active scope as the exception message clearly states. Starting a lifetime scope is pretty simple:
using (ThreadScopedLifestyle.BeginScope(container))
{
// all instances resolved within this scope
// with a ThreadScopedLifestyleLifestyle
// will be the same instance
}
You can read in detail here.
Changing the registrations to:
var container = new Container();
container.Options.DefaultScopedLifestyle = new ThreadScopedLifestyle();
container.Register<IMemberRepository, MemberRepository>(Lifestyle.Scoped);
container.Register<IMemberService, MemberService>(Lifestyle.Scoped);
container.Register<DbContext, MemberContext>(Lifestyle.Scoped);
container.Register<IUnitOfWork, UnitOfWork>(Lifestyle.Scoped);
and changing the code from btnSaveClick() to:
private void btnSave_Click(object sender, EventArgs e)
{
Member member = new Member();
member.Name = txtName.Text;
using (ThreadScopedLifestyle.BeginScope(container))
{
var memberService = container.GetInstance<IMemberService>();
memberService.Save(member);
}
}
is basically what you need.
But we have now introduced a new problem. We are now using the Service Locator anti pattern to get a Scoped instance of the IMemberService implementation. Therefore we need some infrastructural object which will handle this for us as a Cross-Cutting Concern in the application. A Decorator is a perfect way to implement this. See also here. This will look like:
public class ThreadScopedMemberServiceDecorator : IMemberService
{
private readonly Func<IMemberService> decorateeFactory;
private readonly Container container;
public ThreadScopedMemberServiceDecorator(Func<IMemberService> decorateeFactory,
Container container)
{
this.decorateeFactory = decorateeFactory;
this.container = container;
}
public void Save(List<Member> members)
{
using (ThreadScopedLifestyle.BeginScope(container))
{
IMemberService service = this.decorateeFactory.Invoke();
service.Save(members);
}
}
}
You now register this as a (Singleton) Decorator in the Simple Injector Container like this:
container.RegisterDecorator(
typeof(IMemberService),
typeof(ThreadScopedMemberServiceDecorator),
Lifestyle.Singleton);
The container will provide a class which depends on IMemberService with this ThreadScopedMemberServiceDecorator. In this the container will inject a Func<IMemberService> which, when invoked, will return an instance from the container using the configured lifestyle.
Adding this Decorator (and its registration) and changing the lifestyles will fix the issue from your example.
I expect however that your application will in the end have an IMemberService, IUserService, ICustomerService, etc... So you need a decorator for each and every IXXXService, not very DRY if you ask me. If all services will implement Save(List<T> items) you could consider creating an open generic interface:
public interface IService<T>
{
void Save(List<T> items);
}
public class MemberService : IService<Member>
{
// same code as before
}
You register all implementations in one line using Batch-Registration:
container.Register(typeof(IService<>),
new[] { Assembly.GetExecutingAssembly() },
Lifestyle.Scoped);
And you can wrap all these instances into a single open generic implementation of the above mentioned ThreadScopedServiceDecorator.
It would IMO even be better to use the command / handler pattern (you should really read the link!) for this type of work. In very short: In this pattern every use case is translated to a message object (a command) which is handled by a single command handler, which can be decorated by e.g. a SaveChangesCommandHandlerDecorator and a ThreadScopedCommandHandlerDecorator and LoggingDecorator and so on.
Your example would then look like:
public interface ICommandHandler<TCommand>
{
void Handle(TCommand command);
}
public class CreateMemberCommand
{
public string MemberName { get; set; }
}
With the following handlers:
public class CreateMemberCommandHandler : ICommandHandler<CreateMemberCommand>
{
//notice that the need for MemberRepository is zero IMO
private readonly IGenericRepository<Member> memberRepository;
public CreateMemberCommandHandler(IGenericRepository<Member> memberRepository)
{
this.memberRepository = memberRepository;
}
public void Handle(CreateMemberCommand command)
{
var member = new Member { Name = command.MemberName };
this.memberRepository.Insert(member);
}
}
public class SaveChangesCommandHandlerDecorator<TCommand>
: ICommandHandler<TCommand>
{
private ICommandHandler<TCommand> decoratee;
private DbContext db;
public SaveChangesCommandHandlerDecorator(
ICommandHandler<TCommand> decoratee, DbContext db)
{
this.decoratee = decoratee;
this.db = db;
}
public void Handle(TCommand command)
{
this.decoratee.Handle(command);
this.db.SaveChanges();
}
}
And the form can now depend on ICommandHandler<T>:
public partial class frmMember : Form
{
private readonly ICommandHandler<CreateMemberCommand> commandHandler;
public frmMember(ICommandHandler<CreateMemberCommand> commandHandler)
{
InitializeComponent();
this.commandHandler = commandHandler;
}
private void btnSave_Click(object sender, EventArgs e)
{
this.commandHandler.Handle(
new CreateMemberCommand { MemberName = txtName.Text });
}
}
This can all be registered as follows:
container.Register(typeof(IGenericRepository<>),
typeof(GenericRepository<>));
container.Register(typeof(ICommandHandler<>),
new[] { Assembly.GetExecutingAssembly() });
container.RegisterDecorator(typeof(ICommandHandler<>),
typeof(SaveChangesCommandHandlerDecorator<>));
container.RegisterDecorator(typeof(ICommandHandler<>),
typeof(ThreadScopedCommandHandlerDecorator<>),
Lifestyle.Singleton);
This design will remove the need for UnitOfWork and a (specific) service completely.
I have this class:
public class AutofacEventContainer : IEventContainer
{
private readonly IComponentContext _context;
public AutofacEventContainer(IComponentContext context)
{
_context = context;
}
public IEnumerable<IDomainEventHandler<T>> Handlers<T>(T domainEvent)
where T : IDomainEvent
{
return _context.Resolve<IEnumerable<IDomainEventHandler<T>>>();
}
}
The IEventContainer look like this:
public interface IEventContainer
{
IEnumerable<IDomainEventHandler<T>> Handlers<T>(T domainEvent)
where T : IDomainEvent;
}
Now this IEventContainer is used in a class DomainEvents like this:
public static class DomainEvents
{
....................................
....................................
public static IEventContainer Container;
public static void Raise<T>(T domainEvent) where T : IDomainEvent
{
if (Container != null)
foreach (var handler in Container.Handlers(domainEvent))
handler.Handle(domainEvent);
// registered actions, typically used for unit tests.
if (_actions != null)
foreach (var action in _actions)
if (action is Action<T>)
((Action<T>)action)(domainEvent);
}
}
My aim is to have the DomainEvents.Container registered so that all handlers are resolved.
public class SomeModule : Module
{
protected override void Load(ContainerBuilder builder)
{
base.Load(builder);
//Wrong way in Autofac
//Because the following line is Ninject-like
DomainEvents.Container = new AutofacContainer(componentContext);
//What is the correct way to register it to achieve the above intent?
}
}
What is the way to do this in Autofac?
You are going to have a memory leak if you resolve out of the root scope. (See this post for a good overview of lifetime scopes in Autofac.) A better way to do it would be like this:
interface IEventRaiser
{
void Raise<TEvent>(TEvent #event) where TEvent : IDomainEvent;
}
class AutofacEventRaiser : IEventRaiser
{
private readonly ILifetimeScope context;
public AutofaceEventRaiser(ILifetimeScope context)
{
this.context = context;
}
public void Raise<TEvent>(TEvent #event) where TEvent : IDomainEvent
{
using(var scope = context.BeginLifetimeScope("eventRaiser"))
{
foreach(var handler in scope.Resolve<IEnumerable<IDomainEventHandler<TEvent>>>())
{
handler.Handle(#event);
}
} // scope is disposed - no memory leak
}
}
// then, in the composition root:
IContainer theContainer = BuildTheAutofacContainer();
DomainEvents.EventRaiser = new AutofacEventRaiser(theContainer);
This is the simple answer, but there is one more caveat you should be aware of...
The question is whether you really want to use a static IEventRaiser. DI purists will generally say, "no - you should inject an instance of your IEventRaiser into every class that needs one", but others have argued that a static event raiser is OK.
Be sure you are aware of how Autofac's lifetime scopes work before you make this decsion, because it could affect component sharing. For example, say SomeClass has an instance of SomeDependency and it raises SomeEvent. Let us also assume that SomeDependency is InstancePerLifetimeScope.
If SomeClass gets the IEventRaiser injected, then the handlers will be invoked on the same lifetime scope, and will be injected with the same instance of SomeDependency.
If SomeClass uses a static IEventRaiser, then the handlers will be invoked on a different lifetime scope, and will be injected with a different instance of SomeDependency.
You can see why this matters if you imagine that SomeDependency is something like a DB transaction.