We have components registrations in Castle Windsor container like so
void RegisterComponent<TInterface, TImplementation>() {
var component = Component.For<TInterface>().ImplementedBy<TImplementation>();
component.Interceptors<SomeInterceptor>();
container.Register(component);
}
However we got to the problem that when we do a method call from within the class it does not get intercepted. For example we have component like
ServiceA : IService {
public void MethodA1() {
// do some stuff
}
public void MethodA2() {
MethodA1();
}
}
And if we call MethodA2 or MethodA1 methods from some other class it is intercepted, but MethodA1 apparently not intercepted when called from MethodA2 since the call is from within the class.
We have found similar case with the solution Castle Dynamic Proxy not intercepting method calls when invoked from within the class
However the solution features component and proxy creation using new operator which is not suitable in our case since we are using container. Can we use this solution with component registration like above? Or are there other approaches to solve the problem?
For interception to work on MethodA1 when invoked from MethodA2 you need to be using inheritance based interception (it's because you are using this reference to make the invocation).
To make inheritance based interception possible first you need to make MethodA1 and MethodA2 virtual.
Then you can make container registration like this:
container.Register(Component.For<ServiceA>().Interceptors<SomeInterceptor>());
container.Register(Component.For<IService>().UsingFactoryMethod(c => c.Resolve<ServiceA>()));
First register your service as itself applying interceptors (this will add inheritance based interception over the service). Then you can register the interface which will use service registered earlier.
Change your registration to the following and Windsor should switch to class proxies - i.e. using inheritance for interception, instead of composition.
void RegisterComponent<TInterface, TImplementation>() {
container.Register(Component.For<TInterface,TImplementation>().ImplementedBy<TImplementation>().Interceptors<SomeInterceptor>());
}
We use CreateClassProxy method to create the proxy for the service as it was proposed in an answer to the question Castle Dynamic Proxy not intercepting method calls when invoked from within the class.
Then we register the obtained proxy as an implementation for the interface.
So our custom RegisterComponent method looks like this
private void RegisterComponent<TInterface, TImplementation>()
where TInterface : class
where TImplementation : class, TInterface
{
var proxyType = new ProxyGenerator().CreateClassProxy<TImplementation>().GetType();
Container.Register(Component.For<TInterface>().ImplementedBy(proxyType));
}
The full component registration is
Container = new WindsorContainer();
Container.Kernel.Resolver.AddSubResolver(new CollectionResolver(Container.Kernel));
// Interceptor
Container.Register(Component.For<IInterceptor>().ImplementedBy<SomeInterceptor>().LifestyleTransient());
// Component registrations
RegisterComponent<ISomeService, SomeService>();
And, of course, all methods you need to intercept should be virtual since inheritance based proxy is used.
However a drawback of this solution is that you could not use constructor injection when creating a proxy object.
Notice that you are creating "dummy" proxy object with new operator only to get a type of the proxy. Therefore you are unable to use constructor injection only when constructing a dummy proxy, but when you resolve your service via container, injection would work just fine. So this drawback is critical only for components with construction logic being more complex than just assigment of dependencies. If you need only dependency assigments you can try to resolve all dependencies from container manually before creating dummy proxy
private object[] ResolveConstructorParameters<TType>()
{
return typeof(TType).GetConstructors()
.Single(c => c.IsPublic)
.GetParameters()
.Select(p => _container.Resolve(p.ParameterType))
.ToArray();
}
and then RegisterComponent would become
private void RegisterComponent<TInterface, TImplementation>()
where TInterface : class
where TImplementation : class, TInterface
{
var constructorParameters = ResolveConstructorParameters<TImplementation>();
var proxyType = new ProxyGenerator().CreateClassProxy(typeof(TImplementation), constructorParameters).GetType();
_container.Register(Component.For<TInterface>().ImplementedBy(proxyType));
}
You can also just fill arguments with null.
#NikolayKondratyev I've looked into https://github.com/castleproject/Windsor/blob/master/src/Castle.Windsor/Windsor/Proxy/DefaultProxyFactory.cs#L110
and I've done the registration the easy way:
container.Register(Classes.FromThisAssembly().BasedOn(typeof(IRepositoryBase<,>))
.WithServiceAllInterfaces().WithServiceSelf()
.LifestyleTransient());
Note .WithServiceSelf() call, this actually switches class-based proxying
I know this is an old thread, but I just came across it while getting Castle interceptors working in Blazor WASM (which they actually do, but beware...Mono can't seem to support proxying any class that has any generic methods...).
Anyway, to get around this issue in my case, I simply injected the container into my class, and in the method that needed to call a "sibling method" via this I simply resolved a fresh instance of my interface and called the method on that. It won't work for scenarios with shared context/transient states, but the interceptor indeed does its thing.
In Blazor's client WASM app's Program.cs:
public static async Task Main(string[] args)
{
WebAssemblyHostBuilder builder = WebAssemblyHostBuilder.CreateDefault(args);
...
builder.ConfigureContainer<IWindsorContainer>(new WindsorServiceProviderFactory(), container =>
{
container.Register(Component.For<IInterceptor>()
.ImplementedBy<BlazorInterceptor>()
.Named("BlazorInterceptor").LifestyleTransient());
});
...
builder.Services.AddScoped<IService, Service>();
...
await builder.Build().RunAsync();
}
Example service and interface implementation:
public Interface IService
{
MethodA(int arg);
MethodB(int arg);
}
[Interceptor("BlazorInterceptor")]
public class Service : IService
{
private readonly IServiceProvider _container;
public Service(IServiceProvider container)
{
this._container = container;
}
public MethodA(int arg)
{
IService service = this._container.GetRequiredService<IService>();
service.MethodB(arg);
}
public MethodB(int arg)
{
//should be intercepted...just in a different instance of the service unless you're using singletons...
}
}
Pros: Doesn't require virtualizing methods or complicating your DI configuration.
Cons: Kind of gross (useful for stateless repositories, but would probably give something like EF a heart attack).
Related
I'm building an application that performs actions initiated by a user and one particular class has dependencies on things I can wire up in DI such as an ILogger instance as well as an HttpClient in addition to runtime arguments that identify the user and the instance of the action (mostly to be used while logging to help with debugging).
The trouble I have is that I'm not entirely sure how to inject this class into the other classes that need it as a result of the runtime dependencies.
Here's a simplified example of one of my classes:
public class Dependency : IDependency
{
private readonly HttpClient httpClient;
private readonly ILogger<Dependency> logger;
private readonly RuntimeDeps runtimeDeps
public Dependency(
ILogger<Dependency> logger,
HttpClient httpClient,
RuntimeDeps runtimeDeps)
{
// set private fields
}
public Result DoStuff()
{
// use Http client to talk to external API
// something fails so log the failure and some helpful info
logger.log($"{runtimeDeps.InstanceId} failed. " +
"Initiated by {runtimeDeps.UserName}");
}
}
This feels like it requires a factory to create but then is it best to request the HttpClient and Logger in the factory method or declare it as a dependency of the factory? If the latter, I presume the factory would have to be registered as a transient or as a scoped resource since registering it as a singleton would result in a captive dependency (I think).
Any suggestions on redesigns are also welcome if this is a symptom of a poor design. I'd love to implement Mark Seeman's Pure DI to get some more assistance from the compiler but I don't know if that's possible in Azure functions.
A transient factory with the transient dependencies injected into the constructor and the runtime dependencies as parameters of the Create method will work fine.
DI is baked into the Azure Functions library in the sense that parameters are injected into the trigger methods, but beyond these you should be able to use Pure DI to manage your own dependencies by calling into some composition root helper class from the trigger function which knows how to build your dependency graph in a pure manner.
Instead of requiring runtime data during the construction of a component, it's better to let runtime data flow through method calls on an initialized object graph by either:
passing runtime data through method calls of the API or
retrieving runtime data from specific abstractions that allow resolving runtime data.
I formalized this in 2015 in this blog post, which I referred to in the comments.
After reading your additional comments, I came to the conclusion that in your case option 2 is most suited, as the data you are sending is likely an implementation detail to the component, and should not be part of the public API.
In that case, you can redesign your component as follows:
public class Dependency : IDependency
{
public Dependency(
ILogger<Dependency> logger,
HttpClient httpClient,
IRuntimeDepsProvider provider) ...
public Result DoStuff()
{
// use Http client to talk to external API
// something fails so log the failure and some helpful info
logger.log($"{provider.InstanceId} failed. " +
$"Initiated by {provider.UserName}");
}
}
IRuntimeDepsProvider is an abstraction that hides the retrieval and storage of runtime data. This gives you the ability to postpone the decision to either use a Closure Composition Model or an Ambient Composition Model until the Last Responsible Moment.
Using the IRuntimeDepsProvider abstraction, you can chose to set the incoming runtime values after the object graph is constructed. For instance:
public class MyFunction
{
// Notice the different abstraction here
public MyFunction(
IRuntimeDepsInitializer initializer,
IHandler<Something> handler) ...
public void TheFunction(Guid instanceId, string userName, Something cmd)
{
// Setting the runtime data *after* the object graph is constructed,
initializer.SetData(instanceId, userName);
// but before the graph's public methods are invoked.
handler.Handle(cmd);
}
}
Here, a second abstraction is introduced, namely IRuntimeDepsInitializer. Now you can have one class implementing both interfaces:
public class RuntimeDepsStorage : IRuntimeDepsInitializer, IRuntimeDepsProvider
{
public Guid InstanceId { get; private set; }
public string UserName { get; private set; }
public void SetData(Guid id, string name)
{
InstanceId = id;
UserName = name;
}
}
TIP: Instead of using two interfaces, you can also use only IRuntimeDepsProvider and let MyFunction depend on the concrete RuntimeDepsStorage. Which solution is best depends on the context.
Now the main trick here is to make sure that RuntimeDepsStorage becomes a Scoped dependency, because you want to reuse it throughout a request, but not shared by multiple requests.
When applying Pure DI, this would look like this:
var storage = new RuntimeDepsStorage();
new MyFuncion(
initializer: storage,
handler: new SomethingHandler(
stuffDoer: new Dependency(
httpClient: client, // Did you notice this is a runtime dep as well?
logger: new Logger<Dependency>(),
provider: storage)))
If, on the other hand, you would be using MS.DI as your DI Container, registration would be similar to the following:
services.AddScoped(_ => new RuntimeDepsStorage());
services.AddScoped<IRuntimeDepsProvider>(
c => c.GetRequiredService<RuntimeDepsStorage>());
services.AddScoped<IRuntimeDepsInitializer>(
c => c.GetRequiredService<RuntimeDepsStorage>());
// etc, your usual registrations here
I'm looking for some way to enforce the checking (runtime, of course) of the proper lifetime registration of dependency-injection services, in .Net Core or higher.
Let's say I have a stateful service like this one:
public class MyStatefulService
{
private object _state;
}
However, by mistake, I could register it with the wrong lifetime:
services.AddTransient<MyStatefulService>();
So, I won't be alerted, but the actual behavior is not what I'd expect: the service is created at every request, and the state won't be preserved.
I wonder if there is a way to reinforce this pattern. For instance, it would be nice if I could decorate the class with an attribute like this:
[Singleton]
public class MyStatefulService
{
private object _state;
}
at this point, possibily at startup or at the very first request, the framework should throw if the registration is different than AddSingleton (along its overloads).
Similarly, the subject could apply for transient-only services, which shouldn't registered as singletons.
The only solution came in my mind is rather naive, and I don't like so much:
//line of principle code
public static class MySingletonChecker
{
private static HashSet<Type> _set = new HashSet<Type>();
public static void Validate(Type type)
{
if (_set.Contains(type))
{
throw new Exception();
}
else
{
_set.Add(type);
}
}
}
public class MyStatefulService
{
public MyStatefulService()
{
MySingletonChecker.Validate(this.GetType());
}
private object _state;
}
Is there any better solution, hack or anything that helps to prevent errors?
If you want to idiot-proof your code, you can provide an extension method to IServiceCollection that registers your service exactly the way it should be.
public static void AddMyStatefulService(this IServiceCollection services)
{
services.AddSingleton<MyStatefulService>();
}
Then in your services configuration section, the developer would type:
services.AddMyStatefulService();
Here's a way like I was pointing out in the comments
Let's have some empty types:
public class ScopedService {}
public class TransientService {}
Let's have a real service that derives from one of the empty types:
public class RealService: ScopedService, IRealService {
//impl
}
And a generic registration method helper:
static void MyAddScoped<TService, TImplementation>(IServiceCollection services)
where TService : class
where TImplementation : ScopedService, TService
{
services.AddScoped<TService, TImplementation>();
}
Let's register our realservice using the helper:
public void ConfigureServices(IServiceCollection services)
{
services.AddControllersWithViews();
MyAddScoped<IRealService, RealService>(services);
}
RealService is a ScopedService - think of this as "how you decorate a service to insist it be added as scoped"
Suppose the developer changes the service to be a transient:
class RealService: TransientService, IRealService {
Now you get a compiler error from the helper method:
The type 'YourApplication.RealService' cannot be used as type parameter 'TImplementation' in the generic type or method 'Startup.MyAddScoped<TService, TImplementation>(IServiceCollection)'. There is no implicit reference conversion from 'WebApplication1.RealService' to 'WebApplication1.ScopedService'.
Your "one person who looks after registration" can know that the developer is indicating the service is no longer registerable as Scoped and can change it (and the build will be broken until it is changed, which is a good way of preventing accidental release of incorrect code)
Another way to validate lifetimes, is by inspecting the entire DI container in the ConfigureServices clause.
Each member of a IServiceCollection has a LifeTime property which gives you the information you're looking for: https://learn.microsoft.com/en-us/dotnet/api/microsoft.extensions.dependencyinjection.servicedescriptor.lifetime?view=dotnet-plat-ext-5.0#Microsoft_Extensions_DependencyInjection_ServiceDescriptor_Lifetime
To move DI composition to the declaration of a class you could work with some self-made marker interfaces like IRegisterTransientServiceAs<T>and add it to your class like this:
public class MyStatefulService : IMyStatefulService, IRegisterSingletonServiceAs<IMyStatefulService>
Within your composition you have your own extension method that iterates through all loaded types within the application domain, searches for the given generic interface and register them with the declarated lifetime from the given interface.
Maybe this is not real DI, but as you already mentioned, mostly the lifetime of a service is baked into the code of the service itself and it happens very rarely that a specific service will be used in different project with different lifetimes. So IMHO it is okay to bake the desired lifetime into the class itself, instead of making the decision outside.
In ASP.NET Core MVC all classes that implement Controller will be automatically resolved and added to the MVC pipeline. These controllers can also be injected into the DI container using services.AddMvc().AddControllersAsServices();
I also have a controller that also implements a specific interface, which I can also add to the DI container: services.AddSingleton<IMyInterface, MyImpl>();
public class MyImpl : Controller, IMyInterface { }
However, becase this controller also implements Controller it has already been added in AddControllersAsServices() so adding it to the DI container one more time causes there to be two instances of this class.
The reason for this design is that I will have multiple implementations of IMyInterface and later need to decide which one to use, but each implementation will also need to be a controller in order to provide certain API endpoints (each controller will provide different endpoints, so there will be no conflicts there).
How can I ensure that only one instance of my class is instantiated, and how can I then get all implementations of IMyInterface?
As much as Im concerned Controller class is instantiated on each request, so even if you specify something like this (Ninject style):
services.Bind<IMyInterface, MyController>().To<MyController>().InSingletonScope();
It will be very bad. I mean, Controller is statefull, and you just mix everything up and breaking it's internal context.
What you might do is decorate through controller, instead of managing its lifetime yourself:
public class MyImpl : IMyInterface
{
}
public class MyController : Controller
{
private readonly IMyInterface _inner; //delegate implementation to this one.
public MyController(IMyInterface inner)
{
_inner = inner;
}
}
And injection:
services.Bind<IMyInterface>().To<MyImpl>().InSingletonScope();//this is your logic.
sercices.Bind<MyController>().ToSomethingWhatever();//this line is managed by ASP .NET, mentioned this only to show the idea
You might need remove the MyImpl inheriting from Controller class. Also you need to consider MyImpl as sevice rather than Controller.
Another option is that this can be achieved with IoC container like Autofac or Ninject or Castle Windsor. When using with Autofac it will be something like the below
Add the Autofac, Autofac ASP.Net MVC4 Integration using NuGet Package
Open GLobal.asax.cs
Make following changes in the Application_Start().
3a. Comment out the below code as
//WebApiConfig.Register(GlobalConfiguration.Configuration);
3b. Create a new method RegisterAutofac(), call this as the first method call inside Application_Start()
3c. Below with the sample implementation for RegisterAutofac() method
private void RegisterAutofac()
{
var builder = new Autofac.ContainerBuilder();
builder.RegisterControllers(Assembly.GetExecutingAssembly());
builder.RegisterSource(new ViewRegistrationSource());
// The object to be injected in constructor etc.
builder.RegisterType<MyImpl>().As<IMyInterface>().SingleInstance();
var container = builder.Build();
DependencyResolver.SetResolver(new AutofacDependencyResolver(container));
}
I'm registering a service as a singleton in .NET Core. Yet I'm seeing the constructor for the singleton called multiple times.
services.AddSingleton<DbAuthorizationOptions, ContextAuthorizationOptions>();
My context authorization options is just Dictionary of Entity Types to IValidators, The context authorization options are passed into the DBContext, to automatically run validations.
During the registration of my services, I also register dynamic Validators with my container registered in DI.
var useDynamicValidator = serviceOption.ValidatorOptions != null;
if(useDynamicValidator)
{
//TODO: Extract this to before the register service no sense in building the provider each time
//TODO: Make this cleaner don't be dependent on Authorization options
var provider = services.BuildServiceProvider();
var authOptions = provider.GetService<DbAuthorizationOptions>();
var validator = BuildDynamicValidatorFactory(serviceOption).Invoke(provider, null);
authOptions.ValidatorOptions.AddValidatorForSet(validator);
}
I notice that when I call GetService on the provider I receive a new singleton instead of the existing one. Does building the provider create a new container so all of the services get re-registered?
If so, How can I call a method to register my dynamic validators in the singleton container with the existing IServiceProvider, is there a way to invoke some registration once after the service container is built?
Does building the provider create a new container so all of the services get reregistered?
Yes. See the source code.
If so, How can I call a method to register my dynamic validators in the singleton container with the existing IServiceProvider, is there a way to invoke some registration once after the servicecontainer is built?
I'm not really understanding why this is a problem. You should be registering all of your services one time at application startup in the Composition Root.
The DI container is then responsible for resolving the object graphs of the application. The application itself shouldn't have a dependency on it, nor be required to update it.
You should be injecting DbAuthorizationOptions in the place where you need to use it.
public class Foo : IFoo
{
private readonly DbAuthorizationOptions authOptions;
public Foo(DbAuthorizationOptions authOptions) // <-- Inject parameters
{
this.authOptions = authOptions ??
throw new ArgumentNullException(nameof(authOptions));
}
public void DoSomething()
{
// TODO: Inject the type that has the BuildDynamicValidatorFactory
// method and the serviceOption (whatever type that is) here
// either as a method parameter of this method, or a constructor
// parameter of this class.
var validator = BuildDynamicValidatorFactory(serviceOption).Invoke(provider, null);
// Now we have an instance of authOptions that can be used
authOptions.ValidatorOptions.AddValidatorForSet(validator);
}
}
Note that the DI container automatically provides the DbAuthorizationOptions if injected into another type that is also resolved through DI (such as a controller or filter).
NOTE: It isn't very clear from your question where you need to do this. You mention that you want it to happen once, which usually means to put it at application startup. But users cannot interact with code that runs at startup. So, maybe you could use a filter. It really all depends on where in the lifecycle of the application it has to happen.
You can declare a dependency on IServiceProvider -- don't build it, inject it.
public class SomeController
{
DbAuthorizationOptions authOptions;
public SomeController(IServiceProvider provider)
{
authOptions = provider.GetSerivce<DbAuthorizationOptions>();
}
}
But this is the service locator anti-pattern. As I commented on NightOwl888's post after you gave more details, a factory is probably a better approach.
I am trying to rewrite my app from a service pattern to a command and query pattern (before I move to CQRS). Currently I'm stuck on this blog.
It shows where he moved unit of work commit from the base command into a PostCommitCommandHandlerDecorator, then use Simple Injector to bind them up. The writer also stated that not all commands will require the use of unit of work, which is true in my case because not every command talks to a database but some send emails, etc.
How do I architect my commands and bindings in such a way that only those commands that are required to be wrapped in a unit of work commit will be bound as such by the IoC container?
How do I architect my commands and bindings in such a way that only those commands that are required to be wrapped in a unit of work commit will be bound as such by the IoC container?
First of all, does that really matter that not all handlers use the unit of work? Is it a problem when a unit of work is created, while it isn’t used? Because when there are no performance problems, there’s no need to make your code more complicated.
But let’s assume that it does matter. In that case, the trick is to query the container whether the unit of work is injected somewhere. You can make use of Lazy<T> to get this working. Take a look at the following registration:
Func<IUnitOfWork> uowFactory =
() => new MyUnitOfWork(connectionString);
// Register the factory as Lazy<IUnitOfWork>
container.Register<Lazy<IUnitOfWork>>(
() => new Lazy<IUnitOfWork>(uowFactory),
Lifestyle.Scoped);
// Create a registration that redirects to Lazy<IUnitOfWork>
container.Register<IUnitOfWork>(
() => container.GetInstance<Lazy<IUnitOfWork>>().Value,
Lifestyle.Scoped);
For the rest of the article I assume you're building a web application, but the idea will be the same.
With this registration, when the container resolves an object graph with a component that depends on IUnitOfWork, under the covers it will resolve the Lazy<IUnitOfWork> and get its value. We cache the Lazy<IUnitOfWork> per request, so this allows us to have another component that depends on Lazy<IUnitOfWork> and check its IsValueCreated property to see if the IUnitOfWork was injected anywhere.
Now your decorator could look like this:
public class TransactionCommandHandlerDecorator<TCommand>
: ICommandHandler<TCommand>
{
private readonly ICommandHandler<TCommand> decorated;
private readonly Lazy<IUnitOfWork> lazyUnitOfWork;
public TransactionCommandHandlerDecorator(
ICommandHandler<TCommand> decorated,
Lazy<IUnitOfWork> lazyUnitOfWork)
{
this.decorated = decorated;
this.lazyUnitOfWork = lazyUnitOfWork;
}
public void Handle(TCommand command)
{
this.decorated.Handle(command);
if (this.lazyUnitOfWork.IsValueCreated)
{
this.lazyUnitOfWork.Value.SubmitChanges();
}
}
}
Note however that you still don’t know whether the unit of work is actually used or not, but I think it’s safe to assume that the unit of work will be used when it gets injected. You don’t want to inject an unused dependency.
If that doesn’t cut it, and you want to check whether it is created, you will have to inject a proxy unit of work that allows you to check this. For instance:
public class DelayedUnitOfWorkProxy : IUnitOfWork
{
private Lazy<IUnitOfWork> uow;
public DelayedUnitOfWorkProxy(Lazy<IUnitOfWork> uow)
{
this.uow = uow;
}
void IUnitOfwork.SubmitChanges()
{
this.uow.Value.SubmitChanges();
}
// TODO: Implement All other IUnitOfWork methods
}
Your configuration will now look like this:
Func<IUnitOfWork> uowFactory =
() => new MyUnitOfWork(connectionString);
// Register the factory as Lazy<IUnitOfWork>
container.Register<Lazy<IUnitOfWork>>(
() => new Lazy<IUnitOfWork>(uowFactory),
Lifestyle.Scoped);
// Register the proxy that delays the creation of the UoW
container.Register<IUnitOfWork, DelayedUnitOfWorkProxy>(
Lifestyle.Scoped);
When a command or any other dependency needs an IUnitOfWork, they will get the DelayedUnitOfWorkProxy, and it is injected with a Lazy<IUnitOfWork>. So after the object graph is created, the unit of work itself will not be created yet. Only when one of the DelayedUnitOfWorkProxy method is called, such instance is created. The decorator will stay the same.
But even this might not be good enough. It is possible that your MVC controller (assuming you are building an ASP.NET MVC application) depends on a query that uses the unit of work, but the command handler does not. In that case you probably still wouldn't want to commit the unit of work, because the command handler (or one of its dependencies) still doesn't use the unit of work.
In that case what you’re actually trying to do is to isolate the execution of command handlers in their own scope. As if they are running in a different App Domain. You want them to be independent of the web request in which they execute.
In that case you need an hybrid lifestyle. With Simple Injector you can leave all your code and configuration in tact, but switch to an hybrid lifestyle like this:
container.Options.DefaultScopedLifestyle = Lifestyle.CreateHybrid(
() => container.GetCurrentLifetimeScope() != null,
new LifetimeScopeLifestyle(),
new WebRequestLifestyle());
Func<IUnitOfWork> uowFactory =
() => new MyUnitOfWork(connectionString);
// Register the factory as Lazy<IUnitOfWork>
container.Register<Lazy<IUnitOfWork>>(
() => new Lazy<IUnitOfWork>(uowFactory),
Lifestyle.Scoped);
// Register a proxy that depends on Lazy<IUnitOfWork>
container.Register<IUnitOfWork, DelayedUnitOfWorkProxy>(
Lifestyle.Scoped);
An hybrid lifestyle is a composite of two (or more) lifestyles and it contains a predicate delegate that the container will call to check which lifestyle should be applied.
With just this configuration nothing will happen, because the LifetimeScopeLifestyle requires you to explicitly start and stop a new scope. Without a scope the container.GetCurrentLifetimeScope() method will always return null, which means that the hybrid lifestyle will always pick the WebRequestLifestyle.
What you need is to start a new lifetime scope just before you resolve a new command handler. As always, this can be done by defining a decorator:
private sealed class LifetimeScopeCommandHandlerDecorator<T>
: ICommandHandler<T>
{
private readonly Container container;
private readonly Func<ICommandHandler<T>> decorateeFactory;
public LifetimeScopeCommandHandlerDecorator(Container container,
Func<ICommandHandler<T>> decorateeFactory)
{
this.decorateeFactory = decorateeFactory;
this.container = container;
}
public void Handle(T command)
{
using (this.container.BeginLifetimeScope())
{
var decoratee = this.decorateeFactory.Invoke();
decoratee.Handle(command);
}
}
}
You should register this decorator as last decorator (outer most decorator). Instead of depending on an ICommandHandler<T> this decorator depends on an Func<ICommandHandler<T>>. This makes sure that the decorated command handler will only get resolved when the Func<T> delegate is invoked. This postpones the creation and and allows the creation of a lifetime scope first.
Since this decorator depends on two singletons (both the container and the Func<T> are singletons), the decorator itself can also be registered as singleton. This is what your configuration might look like:
// Batch register all command handlers
container.Register(
typeof(ICommandHandler<>),
typeof(ICommandHandler<>).Assembly);
// Register one or more decorators
container.RegisterDecorator(
typeof(ICommandHandler<>),
typeof(TransactionCommandHandlerDecorator<>));
// The the lifetime scope decorator last (as singleton).
container.RegisterDecorator(
typeof(ICommandHandler<>),
typeof(LifetimeScopeCommandHandlerDecorator<>),
Lifestyle.Singleton);
This will effectively isolate the unit of work used by commands from any unit of work that is created outside the context of a command handler within the rest of the request.
There is a simple way to achieve what you are asking. There are overloaded versions of the RegisterDecorator extension method that accept a Predicate which, in combination with a marker interface, can be used to selectively apply a decorator.
Here's an example in code:
public interface ICommandHandler<T> where T : class { }
public interface IDontUseUnitOfWork { }
public class MyCommand { }
public class MyCommandHandler :
ICommandHandler<MyCommand>, IDontUseUnitOfWork { }
public sealed class UnitOfWorkCommandDecorator<T> :
ICommandHandler<T> where T : class
{
public UnitOfWorkCommandDecorator(ICommandHandler<T> decorated) { }
}
And the registration to apply the UnitOfWorkCommandDecorator to command handlers except those that are tagged with the IDontUseUnitOfWork interface:
container.RegisterDecorator(
typeof(ICommandHandler<>),
typeof(UnitOfWorkCommandDecorator<>),
x => !typeof(IDontUseUnitOfWork).IsAssignableFrom(x.ImplementationType));
This predicate feature is very useful and well worth getting to grips with.