I am using Autofac to resolve objects and I dont want to use constructor injection everytime in classes. Therefore I defined a base class but property injection didn't solve my problem. Everytime when I tried to reach this property on my base class from derived class, It is null.
For an example
public abstract class Service
{
public static IUnitOfWork _unitOfWork;
}
I have a base class which name is service.
builder.RegisterType<UnitOfWork>().As<IUnitOfWork>().InstancePerLifetimeScope();
builder.Register(c => Service.UnitOfWork = c.Resolve<IUnitOfWork>());
And my registration like on above.
I have two question about it,
Can defining UnitOfWork property as static be dangerous?
How can I resolve IUnitOfWork easily?
You definitely should consider the costructor injection pattern again and folow the advice of Mark. However to make your approach work you can do something like this:
public static void Main(string[] args)
{
var builder = new ContainerBuilder();
builder.RegisterType<UnitOfWork>().As<IUnitOfWork>().InstancePerLifetimeScope();
builder.RegisterType<ServiceImpl>().As<Service>()
.OnActivated(e => Service.UnitOfWork = e.Context.Resolve<IUnitOfWork>());
var container = builder.Build();
var service = container.Resolve<Service>();
Console.WriteLine(Service.UnitOfWork);
Console.ReadKey();
}
Here ServiceImpl is a derived type from Service. As for your first question, public static fields are global variables, it is not a good idea(at all) to store UnitOfWork in this way. Moreover the whole idea of UnitOfWork contradicts with that. At least it would be better to make UnitOfWork instance property, protected it of assigning more then once and dispose it explicitlyin ServiceImpl.Dispose.
UPD: Additional example for instance property injection approach:
public class Program
{
public static void Main(string[] args)
{
var builder = new ContainerBuilder();
builder.RegisterType<UnitOfWork>().As<IUnitOfWork>().InstancePerLifetimeScope();
builder.RegisterType<ServiceImpl>().As<Service>()
.OnActivated(e => e.Instance.UnitOfWork = e.Context.Resolve<IUnitOfWork>());
var container = builder.Build();
var service = container.Resolve<Service>();
Console.WriteLine(service.IsUnitOfWorkInjected);
Console.ReadKey();
}
}
public abstract class Service : IDisposable
{
private IUnitOfWork _unitOfWork;
private static readonly object padlock = new object();
public IUnitOfWork UnitOfWork
{
protected get => _unitOfWork;
set
{
if (_unitOfWork == null)
{
lock (padlock)
{
if (_unitOfWork == null)
{
_unitOfWork = value;
}
}
}
}
}
public bool IsUnitOfWorkInjected => UnitOfWork != null;
public void Dispose()
{
_unitOfWork?.Dispose();
}
}
Hope it helps.
Related
I have a factory to create a Generic service:
public static class AdPersisterFactory<TEntity>
where TEntity : AdBase
{
public static AdPersister<TEntity> Create(ApplicationDbContext dbContext)
{
AdRepository<TEntity> adRepository = new AdRepository<TEntity>(dbContext);
IAdImagePersister s3AdImagePersister = new S3AdImagePersister();
AdPersister<TEntity> adPersister = new AdPersister<TEntity>(adRepository, s3AdImagePersister);
return adPersister;
}
}
I want to use ninject (version 3), how can I bind IAdPersister to an instance that the above factory creates... This is my DI Code:
private static void RegisterServices(IKernel kernel)
{
kernel.Bind<ApplicationDbContext>().ToSelf().InRequestScope();
// I have tried the following which does not compile
// kernel.Bind(typeof(IAdPersister<>)).ToMethod(ctx => AdPersisterFactory<>.Create(new ApplicationDbContext()));
}
This is for an ASp.NET MVC application, so ideally I don't want to use new ApplicationDbContext but use the same ApplicationDbContext which exists in RequestScope.
I have also seen Ninject.Extensions.Factory but I am not sure how/if I can use it in this scenario.
If you are willing to refactor to a more SOLID approach and AdRepository<TEntity> has a backing interface like
public class AdRepository<TEntity> : IAdRepository<TEntity>
where TEntity : AdBase {
public AdRepository(ApplicationDbContext dbContext) {
//...
}
}
And assuming...
public class AdPersister<TEntity> : IAdPersister<TEntity>
where TEntity : AdBase {
public AdPersister(IAdRepository<TEntity> adRepository, IAdImagePersister imagePersister) {
//...
}
//...
}
Then a way to create your open generic dependency would look like
private static void RegisterServices(IKernel kernel) {
kernel.Bind<ApplicationDbContext>().ToSelf().InRequestScope();
kernel.Bind<IAdImagePersister>().To<S3AdImagePersister>();
//Open generic bind for repository and ad persister
kernel.Bind(typeof(IAdRepository<>)).To(typeof(AdRepository<>));
kernel.Bind(typeof(IAdPersister<>)).To(typeof(AdPersister<>));
}
Now where ever the persister is needed you simple inject the closed type as
ctor(IAdPersister<Foo> fooPersister)
And the necessary dependencies will be resolved and injected by the container.
There really is no need for that static factory.
UPDATE
Based on comment I still advise to not have the static factory.
If you want to keep implementation details internal to your library then make the factory an instance class
public class AdPersisterFactory<TEntity> : IAdPersisterFactory<TEntity>
where TEntity : AdBase {
private readonly ApplicationDbContext dbContext;
public AdPersisterFactory(ApplicationDbContext dbContext) {
this.dbContext = dbContext;
}
public IAdPersister<TEntity> Create() {
AdRepository<TEntity> adRepository = new AdRepository<TEntity>(dbContext);
IAdImagePersister s3AdImagePersister = new S3AdImagePersister();
AdPersister<TEntity> adPersister = new AdPersister<TEntity>(adRepository, s3AdImagePersister);
return adPersister;
}
}
That can be registered as an open generic in your composition root.
private static void RegisterServices(IKernel kernel) {
kernel.Bind<ApplicationDbContext>().ToSelf().InRequestScope();
kernel.Bind(typeof(IAdPersisterFactory<>)).To(typeof(AdPersisterFactory<>));
}
and used
ctor(IAdPersisterFactory<Foo> fooPersisterFactory) {
IAdPersister<Foo> fooPersister = fooPersisterFactory.Create();
//...
}
I have to write a Complex calculator logic which has 4 different components to be calculated brokerage, stockprice, admin charges & other charges. Each having a different logic and formulas.
So I decided to use Unity DI. I have a ContainerFactoryClass which resolves all classes which implements IChargeCalculator interface as shown below in the TotalAnnualCostCalculator constructor.
public class TotalAnnualCostCalculator
{
private readonly IUnityContainer container;
//Constructor
public TotalAnnualCostCalculator()
{
container = ContainerFactory.InitializeContainer();
ContainerFactory.SetupContainer(container);
}
public AnnualCostCharges CalculateTotalAnnualCost(Parameters product)
{
var calculators = container.ResolveAll<ICalculator>().ToList();
// Invoke calcualtion method
Parallel.ForEach(calculators, c =>
{
return c.CalculateAnnualCost(product);
});
}
}
Container Factory class:-
public static class ContainerFactory
{
public static IUnityContainer Container { get; private set; }
public static IUnityContainer InitializeContainer()
{
var container = new UnityContainer();
RegisterDependencies(container);
return container;
}
private static void RegisterDependencies(UnityContainer container)
{
container.RegisterType<ICalculatorStrategyFactory, CalculatorStrategyFactory>("Factory");
container.RegisterType<IEffectiveAnnualCostCalculator, InvestmentManagementChargeCalculator>("IMCChargeCalculator",
new InjectionConstructor(new ResolvedParameter<ICalculatorStrategyFactory>("Factory")));
//container.RegisterType<IEffectiveAnnualCostCalculator, AdministrationChargeCalculator>("AdministrationChargeCalculator");
container.RegisterType<IEffectiveAnnualCostCalculator, AdviceChargeCalculator>("AdviceChargeCalculator");
container.RegisterType<IEffectiveAnnualCostCalculator, OtherChargeCalculator>("OtherChargeCalculator");
container.RegisterType<IInvestmentManagementChargeCalculator, LumpSumIMCCalculator>("LumpSumIMCCalculator");
container.RegisterType<IInvestmentManagementChargeCalculator, DebitOrderIMCCalculator>("DebitOrderIMCCalculator");
}
public static void SetupContainer(IUnityContainer container)
{
Container = container;
}
}
Then any API consumes my Calculator.dll by just creating an instance of TotalAnnualCostCalculator and call a method like this.
var totalCharges = calc.CalculateTotalAnnualCost(prod);
My code reviewer says its better to use Factory Pattern ,as this tightly coupled to Unity Framework.
Please advise
Indeed, don't use a DI Container at all. As Steven suggests in the comments, this seems a great fit for a Composite:
public class TotalAnnualCostCalculator : ICalculator
{
private readonly ICalculator[] calculators;
public TotalAnnualCostCalculator(params ICalculator[] calculators)
{
this.calculators = calculators;
}
public AnnualCostCharges CalculateTotalAnnualCost(Parameters product)
{
Parallel.ForEach(this.calculators, c => c.CalculateAnnualCost(product));
}
}
In the Composition Root, then, you simply new up all the ICalculator objects you'd like to use, and pass them to the constructor of TotalAnnualCostCalculator.
Register all IEffectiveAnnualCostCalculator (or what ever interface).
You just need to map the enumerable to an array of the same type.
container.RegisterType<IEnumerable<IEffectiveAnnualCostCalculator>, IEffectiveAnnualCostCalculator[]>();
Resolve with dependency injection:
private IEnumerable<IEffectiveAnnualCostCalculator> calculators;
public TotalAnnualCostCalculator(IEnumerable<IEffectiveAnnualCostCalculator> calculators)
{
this.calculators = calculators;
}
public AnnualCostCharges CalculateTotalAnnualCost(Parameters product)
{
Parallel.ForEach(this.calculators, c => c.CalculateAnnualCost(product));
}
I am humbling with a problem related to AutoFac and the the abstract factory pattern. My Example is a a service to use an IRepositoryFactory to create a Repository based on JSON or InMemory related to the user input.
// Abstract Factory
public interface IRepositoryFactory{
IRepository Create(string databaseIdentifier);
}
// JSON
public class JsonRepositoryFactory{
public IRepository Create(string databaseIdentifier){
return new JsonRepository(databaseIdentifier);
}
}
// InMemory
public class MemoryRepository{
public IRepository Create(string databaseIdentifier){
return new MemoryRepository(databaseIdentifier);
}
}
The Service should pull the Factory by Constructor Injection.
public interface IShopService{
public string Name {get;}
}
public class BeerShop : IShopService {
public string Name {get; private set;}
private readonly IRepository _repository;
public BeerShop(IRepositoryFactory repositoryFactory){
Name = "beershop";
_repository = repositoryFactory.Create(Name);
}
}
So far I am good with this. But the initialization is not my favorite.
var builder = new ContainerBuilder();
var userInput = ReadInput();
if(userInput = "json")
builder.RegisterType<IRepositoryFactory>().As<JsonRepositoryFactory>();
else
builder.RegisterType<IRepositoryFactory>().As<MemoryRepositoryFactory>();
builder.RegisterType<IShopService>.As<BeerShop>();
var container = builder.build();
[...]
var service = container.Resolve<IShoptService>();
// and so on ...
Is this the right approach to solve it? I am not convinced by my own design because it forces the user input before the initialization of the container. What if the user has to change the Repository while runtime? Is the abstract factory pattern the right tool to solve this problem?
Since the type of repository is known at the time the container is configured, you should register the specific repository directly. There is no need to introduce a factory, as there hardly ever is a reason to introduce a factory abstraction.
Example:
var builder = new ContainerBuilder();
var userInput = ReadInput();
if(userInput = "json")
builder.Register<IRepository>(c => new JsonRepository("dbidentifier"));
else
builder.Register<IRepository>(c => new MemoryRepository());
builder.RegisterType<BeerShop>.As<IShopService>();
var container = builder.build();
[...]
var service = container.Resolve<IShopService>();
This code allows the BeerShop to be simplified, because its constructor would be simple and it now it only depends on IRepository instead of IRepositoryFactory and IRepository. This simplifies testing and makes it easier to reason about this class. Furthermore, it removes the unneeded abstraction.
If you want to change the behaviour of the factory during runtime, then you have to move the logic of deciding the type of IRepository being created to the factory itself. You can adapt the pattern and tweak it to fit your requirements rather than conforming to the specific way of doing it.
The following is a way to do it, if you think about it, you can find different ways of adapting it.
public interface IRepository
{
//repository contracts
}
public interface IRepositoryFactory
{
IRepository Create(string arguments);
}
public interface IRepositoryBuilder
{
RepositoryType Type { get; }
IRepository Create(string args);
}
public class ApplicationSettings
{
public RepositoryType RepositoryType { get; set; }
}
public enum RepositoryType { Json, Text }
// Default implementation of repository factory based on applicationsettings.
public class ConfigurableRepositoryBuilder:IRepositoryFactory
{
private readonly ApplicationSettings _settings;
private readonly IEnumerable<IRepositoryBuilder> _repositoryBuilders;
public ConfigurableRepositoryBuilder(ApplicationSettings settings, IEnumerable<IRepositoryBuilder> repositoryBuilders)
{
_settings = settings;
_repositoryBuilders = repositoryBuilders;
}
public IRepository Create(string arguments)
{
var builder = _repositoryBuilders.First(x => x.Type == _settings.RepositoryType);
//configure builder settings and then call create
return builder.Create(arguments);
}
}
Now you can change the global settings anytime and you will get new type of repository from the next call onwards. Instead of a global singleton, you can read from app.config or other settings file also.
You now want to implement the IRepositoryBuilder for each type of supported IRepository Type
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.
Warning, long post ahead.
I've been thinking a lot about this lately and I'm struggling to find a satisfying solution here. I will be using C# and autofac for the examples.
The problem
IoC is great for constructing large trees of stateless services. I resolve services and pass the data only to the method calls. Great.
Sometimes, I want to pass a data parameter into the constructor of a service. That's what factories are for. Instead of resolving the service I resolve its factory and call create method with the parameter to get my service. Little more work but OK.
From time to time, I want my services to resolve to the same instance within a certain scope. Autofac provides InstancePerLifeTimeScope() which is very handy. It allows me to always resolve to the same instance within an execution sub-tree. Good.
And there are times when I want to combine both approaches. I want data parameter in constructor and have have the instances scoped. I have not found a satisfying way to accomplish this.
Solutions
1. Initialize method
Instead of passing data into the constructor, just pass it to Initialize method.
Interface:
interface IMyService
{
void Initialize(Data data);
void DoStuff();
}
Class:
class MyService : IMyService
{
private Data mData;
public void Initialize(Data data)
{
mData = data;
}
public void DoStuff()
{
//...
}
}
Registration:
builder.RegisterType<MyService>().As<IMyService>().InstancePerLifetimeScope();
Usage:
var myService = context.Resolve<IMyService>();
myService.Init(data);
// somewhere else
var myService = context.Resolve<IMyService>();
After resolving the service for the first time and calling Initialize I can happily resolve within the same context and get the same initialized instance. I don't like the fact that before calling Initialize I have an unusable object. There is a danger that the instance will be resolved and used somewhere else before I call Initialize().
2. Holder pattern
This is a pattern that holds a reference to the data object and instead of injecting the data object itself I inject the holder object.
Interface:
interface IMyService
{
void DoStuff();
}
Class:
class MyService : IMyService
{
private Data mData;
public MyService(IDataHolder dataHolder)
{
mData = dataHolder.Data;
}
public void DoStuff()
{
//...
}
}
Registration:
builder.RegisterType<MyService>().As<IMyService>();
builder.RegisterType<DataHolder>().As<IDataHolder>().InstancePerLifetimeScope();
Usage:
var holder = context.Resolve<IDataHolder>();
holder.Data = data;
// somewhere else
var myService = context.Resolve<IMyService>();
This is a little bit better as I moved the responsibility of holding an instance to a different class. I can now use the holder in other services too. Other advantage is that I can hot swap data in holder if necessary. I don't like the fact that it obfuscates the code and adds another interface I have to mock during testing.
3. Let container hold the instance
Interface:
interface IMyService
{
void DoStuff();
}
Class:
class MyService : IMyService
{
private Data mData;
public MyService(Data data)
{
mData = dataHolder.Data;
}
public void DoStuff()
{
//...
}
}
Registration:
builder.RegisterType<MyService>().As<IMyService>().InstancePerLifetimeScope();
Usage:
var myServiceFactory = context.Resolve<Func<Data, IMyService>>();
myServiceFactory(data);
// somewhere else
var myService = context.Resolve<IMyService>();
That's right. I don't store the result of a factory call anywhere, because autofac stores it for me. This is pretty surprising to anybody who will read the code. I'm not sure if autofac was even meant to be used like this. Nice thing about this is that I need neither an extra initialize method nor extra class for holding instance.
Question
What is your take on this? How do you handle a situation with run-time data parameters and lifetime scoping? Am I missing a better approach?
Autofac now supports this out of the box with an extension to the lifetime scopes. The BeginLifetimeScope() method has an overload that takes an Action<ContainerBuilder> that allows for adding new registrations specific to only that lifetime scope. So for the given example it would look something like:
var builder = new ContainerBuilder();
builder.RegisterType<MyService>().As<IMyService>().InstancePerLifetimeScope();
var container = builder.Build();
using(var scope = container.BeginLifetimeScope(
builder =>
{
builder.RegisterInstance(new Data(....));
}))
{
// References to 'IMyService' will always be resolved to the same instance within this lifetime scop
// References to 'Data' will be resolved to the instance registered just for this lifetime scope.
var svc = scope.Resolve<IMyService>();
}
Most of the time, runtime data is the non static info you need to pass in any process, like x in a math function, so the easiest way to deal with it is using a parameter in the function:
class MyService : IMyService
{
public MyService(){}
public void DoStuff(Data mData)
{
//...
}
}
var myService = context.Resolve<IMyService>();
myService.DoStuff(data);
But, assuming your example is just a example and you are asking because your class need to keep runtime data to run more processes and you don't wanna to pass the same argument in every function:
1.- If you don't loose the scope of the runtime data in every Resolve you can resolve with TypedParameter:
Ej:
//initilization
var builder = new ContainerBuilder();
builder.RegisterType<MyService>().As<IMyService>().InstancePerLifetimeScope();
var container = builder.Build();
//any point of your app
Data mData = new Data("runtimeData"); // must to be accesible in every place you Resolve
using(var scope = container.BeginLifetimeScope())
{
var service = scope.Resolve<IMyService>(new TypedParameter(typeof(Data), mData));
service.DoStuff();
}
using(var scope = container.BeginLifetimeScope())
{
var service2 = scope.Resolve<IMyService>(new TypedParameter(typeof(Data), mData));
service2.DoStuff();
}
2.- If you don't have a reference to runtime data in every place you are resolving you can RegisterInstance when and where you create runtime data. Autofac should inyect mData instance thanks to Direct Depency Policy
//initilization
var builder = new ContainerBuilder();
builder.RegisterType<MyService>().As<IMyService>().InstancePerLifetimeScope();
var container = builder.Build();
//where you create or modify runtime data. When runtime data changes you have to update the container again.
var mData = new Data("runtimeData");
updatedBuilder= new ContainerBuilder();
updatedBuilder.RegisterInstance(mData).As<Data>
updatedBuilder.Update(builder);
//in any point of your app
using(var scope = updatedBuilder.BeginLifetimeScope())
{
var service = scope.Resolve<IMyService>();
service.DoStuff();
}
//in any other point of your app
using(var scope = updatedBuilder.BeginLifetimeScope())
{
var service2 = scope.Resolve<IMyService>();
service2.DoStuff();
}
My take on this is that you've done about as good as you can do. The only niggle that I have about it is that Autofac doesn't really do a great job of helping you manage those lifetime scopes, so you're stuck calling their BeginLifetimeScope somewhere. And they can be nested.
Ninject, on the other hand, does some really cool stuff that doesn't require turning your brain inside-out. Their named scope extension makes it possible for you to create a (gasp) named scope and bind the lifetime of objects within that scope. If you are using factories (clearly you are, judging from the question) you'll also want to use the context preservation extension, so that stuff activated out of factories gets the lifetime management from the named scope that the factory was activated within. Bindings wind up looking something like this:
var scopeName = "Your Name Here";
Bind<TopLevelObject>().ToSelf().DefinesNamedScope(ScopeName);
Bind<ISomeScopedService>().To<SomeScopedService>().InNamedScope(ScopeName);
// A minor bit of gymnastics here for factory-activated types to use
// the context-preservation extension.
Bind<FactoryActivatedType>().ToSelf().InNamedScope(ScopeName);
Bind<IFactoryActivatedType>().ToMethod(x => x.ContextPreservingGet<FactoryActivatedType>());
The nice part about this is that the scope of those bindings is specifically tied to the named scope rather than just being tied to whatever the nearest lifetime scope up the chain is. IMHO, it makes the lifetimes of those objects much more predictable.
Many IoC frameworks support registration of a factory function (or lambda expression), that takes as one of its arguments an instance of the container / scope / resolution context itself.
This allows using additional levels of indirection, as well as the use of information that uniquely identifies the context or scope. Additionally many provide hooks, like event handlers or the option to derive from a life cycle scope class, to interact with a scope being started or ended.
Principle
For AutoFac and your specific example, the following principle would work, using additional levels of indirection in registration.
// Inject `Data` instance resolved from current scope.
builder.Register<IMyService>(ctx => new MyService(ctx.Resolve<Data>()));
// Extra level of indirection, get a "factory" for a 'Data' instance.
builder.Register<Data>(ctx => ctx.Resolve<Func<Data>>()()).InstancePerLifetimeScope();
// The indirection resolves to a map of scopes to "factory" functions.
builder.Register<Func<Data>>(ScopedDataExtensions.GetFactory);
We can use any available unique property on a context / scope to construct this mapping.
// Maps scopes to data "factories".
public static class ScopedDataExtensions
{
private static readonly ConcurrentDictionary<object, Func<Data>> _factories = new ConcurrentDictionary<object, Fund<Data>>();
public static Func<Data> GetFactory(this IComponentContext ctx)
{
var factory = default(Func<Data>);
return _factories.TryGetValue(ctx.ComponentRegistry, out factory) ? factory : () => null;
}
public static void SetFactory(this ILifetimeScope scope, Func<Data> factory)
{
_factories[scope.ComponentRegistry] = factory;
}
}
We can use it like this to supply "local" data instances to be injected into our scoped service instances.
var myData = new Data("nested");
nestedScope.SetFactory(() => myData);
// ...
var myService = nestedScope.Resolve<IMyService>();
A more complete and generic example for AutoFac follows below.
Generic extension class for this pattern
public static class AutofacScopeExtensions
{
// Map from context => factories per type
public static readonly ConcurrentDictionary<object, ConcurrentDictionary<Type, object>> _factories =
new ConcurrentDictionary<object, ConcurrentDictionary<Type, object>>();
private static class ScopedFactoryFor<T>
{
public static Func<T> DefaultFactory = () => default(T);
public static Func<T> GetFactory(ConcurrentDictionary<Type, object> fromContext)
{
object factory;
return (fromContext.TryGetValue(typeof(T), out factory)) ? (Func<T>)factory : DefaultFactory;
}
}
public static IRegistrationBuilder<T, SimpleActivatorData, SingleRegistrationStyle>
WithContextFactoryFor<T>(this ContainerBuilder builder, Func<T> defaultFactory = null)
{
if (defaultFactory != null)
ScopedFactoryFor<T>.DefaultFactory = defaultFactory;
builder.Register<Func<T>>(AutofacScopeExtensions.GetFactory<T>);
return builder.Register<T>(ctx => ctx.Resolve<Func<T>>()());
}
public static IContainer BuildContainer(this ContainerBuilder builder)
{
var container = builder.Build();
container.ChildLifetimeScopeBeginning += OnScopeStarting;
return container;
}
public static ILifetimeScope SetScopeFactory<T>(this ILifetimeScope scope, Func<T> factory)
{
ScopeMapFor(scope)[typeof(T)] = factory;
return scope;
}
public static ILifetimeScope SetScopeValue<T>(this ILifetimeScope scope, T instance)
{
return SetScopeFactory(scope, () => instance);
}
public static Func<T> GetFactory<T>(IComponentContext ctx)
{
return ScopedFactoryFor<T>.GetFactory(ScopeMapFor(ctx));
}
private static ConcurrentDictionary<Type, object> ScopeMapFor(IComponentContext ctx)
{
return _factories.GetOrAdd(ctx.ComponentRegistry, x => new ConcurrentDictionary<Type, object>());
}
private static void OnScopeStarting(object sender, LifetimeScopeBeginningEventArgs evt)
{
evt.LifetimeScope.ChildLifetimeScopeBeginning += OnScopeStarting;
evt.LifetimeScope.CurrentScopeEnding += OnScopeEnding; // so we can do clean up.
}
private static void OnScopeEnding(object sender, LifetimeScopeEndingEventArgs evt)
{
var map = default(ConcurrentDictionary<Type, object>);
if (_factories.TryRemove(evt.LifetimeScope.ComponentRegistry, out map))
map.Clear();
}
}
Allowing the following syntax for registration:
builder.WithContextFactoryFor<Data>(() => new Data("Default")).InstancePerLifetimeScope();
builder.Register<IMyService>(ctx => new MyService(ctx.Resolve<Data>()));
And resolve like:
// ...
var myData = new Data("Some scope");
// ...
context.SetScopeFactory(() => myData);
// ...
// Will inject 'myData' instance.
var myService = context.Resolve<IMyService>();
Simpler Alternative
If you explicitly start nested scopes and at the time you do, you know how the scoped Data instance is to be created, you can skip the extension class and register the "factory" delegate with the nested scope when you create it:
var nestedScope = container.BeginLifetimeScope(
"L2",
x => x.RegisterInstance<Func<Data>>(() => new Data("nested")));
If I understand you correctly you want to use factories by delegating object creation to container while passing some parameters to its constructor.
This is implemented in Castle Windsor with typed factory facility.
Example classes we want to resolve:
public interface IMyService
{
void Do();
}
public class MyService : IMyService
{
private readonly Data _data;
private readonly IDependency _dependency;
public MyService(Data data, IDependency dependency)
{
_data = data;
_dependency = dependency;
}
public void Do()
{
throw new System.NotImplementedException();
}
}
public class Data
{
}
public interface IDependency
{
}
public class Dependency : IDependency
{
}
We create a factory interface:
public interface IMyServiceFactory
{
IMyService Create(Data data);
void Release(IMyService service);
}
We won't be implementing this interface because Castle Windsor will be generating an implementation with Dynamic Proxy. There's an important detail here: parameter name(data) in factory method and the one in the constructor should match.
Then we do the registration and try to resolve the values.
[Test]
public void ResolveByFactory()
{
WindsorContainer container = new WindsorContainer();
container.AddFacility<TypedFactoryFacility>();
container.Register(Component.For<IMyServiceFactory>().AsFactory());
container.Register(Component.For<IMyService>().ImplementedBy<MyService>().LifestyleScoped());
container.Register(Component.For<IDependency>().ImplementedBy<Dependency>().LifestyleScoped());
IMyServiceFactory factory = container.Resolve<IMyServiceFactory>();
IMyService myService1;
IMyService myService2;
using (container.BeginScope())
{
myService1 = factory.Create(new Data());
myService2 = factory.Create(new Data());
myService1.Should().BeSameAs(myService2);
}
using (container.BeginScope())
{
IMyService myService3 = factory.Create(new Data());
myService3.Should().NotBeSameAs(myService1);
myService3.Should().NotBeSameAs(myService2);
}
}
You will see that the object created in the same scope are the same references. Let me know if this is the behaviour you want.