I am trying to optimize my code for the injection of a list of classes, that implement an interface of
IEventHandler<TEvent>.
I have the following structure:
public interface IEventHandlerMarker { }
public interface IEventHandler<in TEvent> : IEventHandlerMarker where TEvent : IEvent
{
Task Handle(TEvent eventItem);
}
public interface IEvent
{
public DateTime Timestamp { get; set; }
}
I register the marker interface IEventHandlerMarker in DI and when accessing the handlers, I currently do the following:
public EventPublisherService(IEnumerable<IEventHandlerMarker> eventHandlers)
{
// Check and and all event handlers
foreach (IEventHandlerMarker item in eventHandlers)
{
AddEventHandler(item);
}
}
In my AddEventHandler method, I filter those to IEventHandler<> like this:
Type handlerType = eventHandlerMarker.GetType().GetInterfaces()
.FirstOrDefault(i => i.IsGenericType && i.GetGenericTypeDefinition() == typeof(IEventHandler<>));
So far everything works, but I'd like to get rid of the marker interface and the filter logic. So I changed the registration of handlers to the following method and this seems to work as expected:
public static IServiceCollection AddEventHandlers(this IServiceCollection serviceDescriptors, params Assembly[] handlerAssemblies)
{
Type genericHandlerType = typeof(IEventHandler<>);
foreach (var implementationType in genericHandlerType.GetTypesWithGenericInterfacesInAssemblies(handlerAssemblies))
{
Type interfaceType = implementationType.GetGenericInterfaceType(genericHandlerType);
serviceDescriptors.AddSingleton(interfaceType, implementationType);
}
return serviceDescriptors;
}
public static List<Type> GetTypesWithGenericInterfacesInAssemblies(this Type source, params Assembly[] assemblies)
{
return assemblies
.SelectMany(currentAssembly => currentAssembly.GetTypes()
.Where(type => type.GetInterfaces().Any(
interfaceItem => interfaceItem.IsGenericType
&& interfaceItem.GetGenericTypeDefinition().Equals(source))))
.ToList();
}
I changed the constructor of EventPublisherService to the following:
public EventPublisherService(IServiceProvider serviceProvider)
{
Type ienumerableOfIEventHandlerType = typeof(IEnumerable<>).MakeGenericType(typeof(IEventHandler<>));
object result = serviceProvider.GetService(ienumerableOfIEventHandlerType);
}
But result always turns out to be null.
I googled and checked some articles on Stackoverflow and came across the following article:
https://stackoverflow.com/a/51504151/1099519
I am not sure if this is the same case, as I am not using a factory.
Versions used: .NET Core 3.1 and Autofac 4.9.4 for the Dependency Injection management.
Register all handlers automatically as shown in this question/answer:
builder.RegisterAssemblyTypes(AppDomain.CurrentDomain.GetAssemblies())
.AsClosedTypesOf(typeof (IEventHandler<>)).AsImplementedInterfaces();
When you have TEvent and want to find all handlers, get them by constructing the concrete interface type as follows:
Type generic = typeof(IEnumerable<IEventHandler<>>);
Type[] typeArgs = { typeof(TEvent) }; // you might get the Type of TEvent in a different way
Type constructed = generic.MakeGenericType(typeArgs);
You should cache this in an dictionary to avoid doing reflection at every event dispatch.
Once you have the constructed concrete interface type, you can ask Autofac for all implementations of that interface:
var handlers = container.Resolve(constructed);
Now, the problem is that with the handler instances you can only call the Handle method using Invoke (reflection). This is a performance issue, but it's unrelated to how you register and resolve the handlers. It's related to the fact that you need to call a concrete method from an object. To avoid using reflection you need compiled code that calls the concrete method (note that using Generics also creates concrete compiled code for each Type).
I can think of two ways of getting compiled code to do this calls:
Manually writing a delegate which casts your object handler instance into a concrete type for every TEvent type that you have. Then store all these delegates in a dictionary so you can find them at runtime based on TEvent type and call it passing the handler instance and the event instance. With this approach, for every new TEvent that you create, you need to create a matching delegate.
Doing a similar thing as before but by emitting the code at startup. So, same thing, but the whole creation of the delegates is automatic.
Update
Based on the repository shared by the OP, I created a working version. The main code, to resolve the handlers and call them is in the EventPublisherService class
public class EventPublisherService : IEventPublisherService
{
private readonly ILifetimeScope _lifetimeScope;
public EventPublisherService(ILifetimeScope lifetimeScope)
{
_lifetimeScope = lifetimeScope;
}
public async Task Emit(IEvent eventItem)
{
Type[] typeArgs = { eventItem.GetType() };
Type handlerType = typeof(IEventHandler<>).MakeGenericType(typeArgs);
Type handlerCollectionType = typeof(IEnumerable<>).MakeGenericType(handlerType);
var handlers = (IEnumerable<object>)_lifetimeScope.Resolve(handlerCollectionType);
var handleMethod = handlerType.GetMethod("Handle");
foreach (object handler in handlers)
{
await ((Task)handleMethod.Invoke(handler, new object[] { eventItem }));
}
}
}
Note that as specified in the original answer, this solution does not include the very necessary performance optimisations. The minimum that should be done is to cache all the types and MethodInfos so they don't need to be constructed every time. The second optimisation would be, as explained, to avoid using Invoke, but it's more complicated to achieve and IMO it requires a separate question.
With autofac you can inject an IEnumerable<IEventHandler<TEvent>> and Autofac should resolve a List of all implementations of it.
https://autofaccn.readthedocs.io/en/latest/resolve/relationships.html
Related
So I'm currently looking at some code and I'm trying to figure out how this line manages to resolve the "factory" which apparently is nothing but a delegate that takes a "Type" and returns an object. It's hard for me to form this question because I don't fully understand what's going on. Could someone break it down?
It all starts in the App.cs
public App()
{
IServiceCollection _services = new ServiceCollection();
_services.AddSingleton<MainViewModel>();
_services.AddSingleton<HomeViewModel>();
/* This is the part I don't understand */
_services.AddSingleton<INavigationService, NavService>(sp =>
{
return new NavService(type => sp.GetRequiredService(type));
});
...
_serviceProvider = _services.BuildServiceProvider();
}
This essentially builds the singleton instance that we're registering
_services.AddSingleton<INavigationService, NavService>(sp =>
{
return new NavService(type => sp.GetRequiredService(type));
});
And we're passing in whatever sp.GetRequiredService(type) returns as a parameter to the NavService constructor.
Which seems to be a Func<Type, object>? Why?
And what is type that we're using when we're using the lambda statement type => sp.GetRequiredService(type)
How do we resolve a Func<Type, object> from type ?
Inside the NavService we're utilizing that delegate by invoking it with a type, which I believe resolves the singleton instance of whatever type we're using when calling NavigateTo<T>
public class NavService : ObservableObject, INavigationService
{
private readonly Func<Type, object> factory;
private object _currentView;
public NavService(Func<Type, object> factory)
{
this.factory = factory;
}
public object CurrentView
{
get => _currentView;
private set
{
_currentView = value;
OnPropertyChanged();
}
}
public void NavigateTo<T>() where T : ViewModel
{
object viewModel = factory.Invoke(typeof(T)) ?? throw new InvalidOperationException("Could not locate VM.");
CurrentView = viewModel;
}
}
So my best guess is that, what we pass in through the constructor is the actual "factory" behind the Microsoft.Extensions.DependencyInjection package that I'm using which is responsible for newing up instances of dependencies that we're registering.
But that still doesn't answer my question of how we resolve a Func<Type, object> from type which is just of type Type?
You are creating an inline lambda as delegate. The delegate is the used as a factory to create instances dynamically.
When you have the following constructor...
class NavigationService : INavigationService
{
public NavigatioService(Func<Type, object> factory)
{}
}
...then you must register a related factory delegate in order to be able to construct it with a DI container. The factory delegate in the above example takes a parameter of type Type and returns an instance of type object.
The factory delegate translates to the following lambda expression:
typeParameter => factory_implementation_that_returns_object;
Instead of instantiating the type manually you can use the service provider to instantiate it for you. This will automatically create all required dependencies:
// Create a delegate that takes a Type as parameter and returns an object using the ServiceProvider
type => sp.GetRequiredService(type)
Now for some reason you have decided to create the NavigationService instance explicitly (new NavigationService()). As a drawback you also have to explicitly build all the constructor dependencies, which is the Funcy<Type, object> delegate:
// Register the INavigationService and tell the IoC container how to build this type
_services.AddSingleton<INavigationService, NavService>(sp =>
{
// Imagine NavService had more constructor dependencies!
// Imagine even this single dependency had 10 dependencies itself,
// where each has n dependencies, where each has...
// You would find yourself to take care to satisfy all of them explicitly at this point...
return new NavService(type => sp.GetRequiredService(type));
});
Instead of registering the Func<Type, object> as a regular dependency, you decided to create this delegate manually inline. This is not a good decision. You always want he IoC container to wire up the dependencies for you.
I don't recommend to do it this way (inline). It only works when the constructor has a single parameter and this parameter doesn't requests its own dependencies. Otherwise you would have to construct all constructor dependencies manually (inline) - which is definitely not what you want.
Additionally, it's also better (more robust) to return an explicit type instance from the factory instead of object.
Because you have defined the Navigate method as generic with a type constraint that T must be of type ViewModel...
// The type of T is used as the parameter for the factory delegate
public void NavigateTo<T>() where T : ViewModel
...you should use ViewModel as the explicit return type of your factory.
To improve your code, the goal is to let the IoC container do all the work. That's what it is for. As a bonus, the code becomes simpler and the configuration feels more intuitive.
The key is to design your code that you don't have to create the NavService instance manually. For this reason you should try to use a parameterless factory delegate. See this answer (solution #2) to get an example on how to design the Navigate method. There are good design reasons to not allow every page to navigate to any page. The idea is to let the caller pass in the reference instead of the Type (and instantiate this Type in the NavService). Just do it like the Frame does it.
However, to fix and improve your example you simply have to register the factory delegate as a service. This way you don't have to create it inline and you don't have to create the receiving type manually too:
class NavigationService : INavigationService
{
private Func<Type, ViewModel> Factory { get; }
public ViewModel CurrentView { get; private set; }
// Improve the robustness and use a strongly typed result (of type ViewModel).
// The Type parameter of the delegate is later provided by the caller, which is the Navigate method.
public NavigatioService(Func<Type, ViewModel> viewModelFactory)
{
this.Factory = factory;
}
// The type of generic type parameter 'TViewModel'
// is the parameter for the factory delegate
public void NavigateTo<TViewModel>() where TViewModel : ViewModel
{
ViewModel viewModel = this.Factory.Invoke(typeof(TViewModel));
this.CurrentView = viewModel;
}
}
public App()
{
IServiceCollection _services = new ServiceCollection();
_services.AddSingleton<MainViewModel>()
.AddSingleton<HomeViewModel>()
// Let the IoC contaiiner construct the NavigatioService
// and all its dependencies for you
.AddSingleton<INavigationService, NavigatioService>()
// Register the factory delegate as normal dependency,
// so that the IoC container can resolve it
.AddSingleton<Func<Type, ViewModel>(serviceProvider => viewModelType => serviceProvider.GetRequiredService(viewModelType));
_serviceProvider = _services.BuildServiceProvider();
}
And we're passing in whatever sp.GetRequiredService(type) returns as a parameter to the NavService constructor.
No you aren't.
You are passing in a lambda type => sp.GetRequiredService(type) to the constructor. This lambda is the factory method.
The dotnet runtime doesn't have any direct support for lambda's. Instead the C# compiler will translate your code into IL that is equivalent to;
public class Captures{
private IServiceProvider sp;
public Captures(IServiceProvider sp){
this.sp = sp;
}
public object Factory(Type type){
return sp.GetRequiredService(type);
}
}
_services.AddSingleton<INavigationService, NavService>(sp =>
{
var captures = new Captures(sp);
return new NavService(new Func<Type,object>(captures.Factory));
});
So when NavService executes factory.Invoke, the generated method Captures.Factory will be called, which will in turn call the extension method sp.GetRequiredService to obtain the instance of the requested Type.
I use a MediatR library in my Asp .Net core 6 app. And I have a the same logic for a group of requests, so I want to use the same handler for all of them. The problem is not new, but the solutions that I found did not help me. I have my own solution to solve this problem, but I do not like it and hope somebody knows a better way to solve this problem.
The example is shown here:
public class HandlerRequest<T> : IRequest
{
public T Data { get; set; }
}
public class Handler<T> : IRequestHandler<HandlerRequest<T>>
{
public Task<Unit> Handle(HandlerRequest<T> request, CancellationToken cancellationToken)
{
// the logic is here
return Task.FromResult(new Unit());
}
}
The registration of MediatR is as follows:
builder.Services.AddMediatR(typeof(BusinessLayer));
When I try to call my mediatr for example:
await _mediator.Send(new HandlerRequest<int>{Data = 5});
await _mediator.Send(new HandlerRequest<string>{Data = "TEST"});
I get an exception:
Error constructing handler for request of type
MediatR.IRequestHandler2[AT.Messenger.Credentials.Business.Requests.V1.Modeles.HandlerRequest1[System.Int32],MediatR.Unit].
Register your handlers with the container. See the samples in GitHub
for examples.
The problem happens because MediatR can not register generic handler. I also tried to register handler as scoped or singleton service as I've seen that advice on the internet, but it does not help.
The only solution that I found - is inherit a new class from my handler:
public class HandlerInt : Handler<int>
{
}
public class HandlerString : Handler<string>
{
}
If use this approach, all works, but I don't like this solution. If anybody know better way to solve this problem give me an advice please.
You have the following options, first, register what you will need explicitly like this.
services.AddTransient<IRequestHandler<HandlerRequest<int>, Unit>>, Handler<int>>();
//so on and so forth
This way you have registered the handlers for known types.
If you have open-bound generic, you can look into my PR that gives you a
services.RegisterGenericMediatRHandlers(typeof(GenericHandlerBase).Assembly);
to automatically register classes inheriting from the constrained interface by using the method provided above.
Lastly, you can opt to use Autofac and register all your handlers like this:
var mediatrOpenTypes = new[]
{
typeof(IRequestHandler<,>),
typeof(IRequestExceptionHandler<,,>),
typeof(IRequestExceptionAction<,>),
typeof(INotificationHandler<>),
};
foreach (var mediatrOpenType in mediatrOpenTypes)
{
builder
.RegisterAssemblyTypes(_assemblies.ToArray())
.AsClosedTypesOf(mediatrOpenType)
.AsImplementedInterfaces();
}
//also by simply
//builder.RegisterGeneric(typeof(Handler<>)).AsImplementedInterfaces();
This will also register all the generic handlers and you won't even have to register it explicitly inside the DI.
btw
The method you used to handle generic registration is the way described in the docs, to quote
If you have an open generic not listed above, you'll need to register it explicitly. For example, if you have an open generic request handler, register the open generic types explicitly:
services.AddTransient(typeof(IRequestHandler<,>), typeof(GenericHandlerBase<,>));
This won't work with generic constraints, so you're better off creating an abstract base class and concrete closed generic classes that fill in the right types.
Source: docs link
I have colleted a lot of information and figured out a solution to register any kind of generic Mediator Handlers.
I was stuck trying to register one generic implementation with another generic class inside INotificationHandler, like this:
public class DomainEventsDispatcher<TEvent> : INotificationHandler<DomainEventDispatch<TEvent>> where TEvent : DomainEvent
PS: I'll use the example above to explain below.
Obviously, your cannot simply use "services.AddMediatr(typeof(AppAssembly))" because using Mediator with generic types, Handlers are not loaded into DI on startup.
So, I decided to register each implementation of each type of TEvent, however, I did it by looping the assemblies that implemented TEvent type and building each part to be used on services.AddTransient.
Looking for assemblies that implemented TEvent type;
First variable: Build the generic used inside INotificationHandler;
Second variable: Build the INotificationHandler with first variable;
Third variable: Build the generic implementation with TEvent type;
Returing the list ready to be injected;
Here is an extension I did to loop and build necessary types to register on DI:
public static class AssemblyExtensions
{
public static List<(Type notificationHandler, Type implementation)> GetGenericNotificationHandlerForTypesOf(this Assembly assembly,
Type AbstractClassToFilter, Type GenericUsedWithNotificationHandler, Type ImplementationType, Type NotificationHandlerGeneric)
{
List<(Type, Type)> list = new List<(Type, Type)>();
foreach (Type item in from t in assembly.GetTypes()
where !t.IsAbstract && !t.IsInterface && t.BaseType == AbstractClassToFilter
select t)
{
var genericForNotificationHandler = GenericUsedWithNotificationHandler.MakeGenericType(item);
var notificationHandler = NotificationHandlerGeneric.MakeGenericType(genericForNotificationHandler);
var implementation = ImplementationType.MakeGenericType(item);
list.Add((notificationHandler, implementation));
}
return list;
}
}
Here is how to use (please take a look in the first example to understand the code below):
var registerPairs = typeof(DomainEvent).Assembly.GetGenericNotificationHandlerForTypesOf(typeof(DomainEvent), typeof(DomainEventDispatch<>), typeof(DomainEventsDispatcher<>), typeof(INotificationHandler<>));
registerPairs.ForEach(pair => services.AddTransient(pair.notificationHandler, pair.implementation));
I've tried to explain my admittedly complex problem to the best of my abilities. Let me know if there is anything I can add to clarify.
A brief background
I have a DbWrapperCollection I use to store DbWrapper<TInput. TOutput> (since TInput and TOutput will vary, the collection is really just a list of non-generic “containers” containing the generic as an object as well as the input and out as System.Types – see my implementation below)
On the other hand, I have a variable number of services, all with their own IDbWrapperCollection that I want to inject with autofac at startup.
Essentially what I want to do is this:
builder.RegisterType<SaveApplDbWrapper>().As<DbWrapper<AppleDto, SavedAppleDbEntity>>()
.Named<string>("fruitService");
builder.RegisterType<SaveOrangeDbWrapper>().As<IUcHandler<OrangeDto, OrangeDbEntity>>()
.Named<string>("fruitService");
builder.RegisterType<SaveMelon>().As<IUcHandler<MelonDto, MelonDbEntity>>()
.Named<string>("appleService");
builder.Register(c => new FruitService(c.ResolveNamed("appleService")))
.As<IDbMapperService>();
My problem
As you can see above, I specifically left out the expected type parameters when calling ResolveNamed(). That’s because I, being new to autofac (and to some extent, generics), I specifically don’t know if there are any strategies to inject a list of open generic DbWrappers and defer closing of my generic type.
I will try to explain which strategies i've researched for dealing with this below, as well as my implementation so far
My own research
The way I see it, I could either create a non-generic baseclass for my wrappers and save them as that baseclass, delegating the responsibility of resolving the original generic type to that baseclass, or ditch my wrapper collection idea in favor of specific parameters on my service constructor (boring – and not compatible with my composite-inspired implementation).
With the popularity of composite pattern, I’d imagine I’m not the first person with a composite-pattern-like solution with “generic leafs” wanting to use DI and an IoC.
I’m planning to use my fruitService like this:
myFruitService.GetDbMapper<MyFruitDto, DbEntityForThatSaidFruit(myOrange);
The service looks in it’s DbMapperCollection, finds the mapper with the provided type arguments, and call its implementation of Save();
Implementation so far
For those curious, here is my implementations:
DbWrappers:
class SaveApplebWrapper : DbWrapper<TInput, TOutput>
// and plenty more wrapppers for any fruit imaginable
Service:
public abstract class DbMapperService : IDbMapperService
{
public IWrapperCollection Wrappers { get; set; }
protected BestandService(IWrapperCollection wrappers)
{
Wrappers = wrappers;
}
public DbWrapper<TInput, TResult> GetWrapper<TInput, TResult>()
{
return Wrappers.GetWrapper<TInput, TResult>();
}
}
My WrapperCollection helper classes:
public struct WrapperKey
{
public static WrapperKey NewWrapperKey <TInput, TResult>()
{
return new WrapperKey { InputType = typeof(TInput), ResultType = typeof(TResult) };
}
public Type InputType { get; set; }
public Type ResultType { get; set; }
}
public struct WrapperContainer
{
public WrapperContainer(object wrapper) : this()
{
Wrapper= wrapper;
}
public object Wrapper{ get; set; }
public DbWrapper<TInput, TResult> GetWrapper<TInput, TResult>()
{
return Wrapper as DbWrapper<TInput, TResult>;
}
}
And my WrapperCollection:
public class UcWrapperCollection : Dictionary<WrapperKey, WrapperContainer>,
IDbWrapperCollection
{
public void AddWrapper<TInput, TResult>(UcHandler<TInput, TResult> handler)
{
Add(WrapperKey.NewWrapperKey<TInput, TResult>(), new WrapperContainer(handler));
}
public DbWrapper<TInput, TResult> GetWrapper<TInput, TResult>()
{
var key = WrapperKey.NewWrapperKey<TInput, TResult>();
return this[key].GetWrapper<TInput, TResult>();
}
}
Questions I've looked at without luck
Some questions I've looked at, none of which seemed relevant to my case (although my problem could potentially be solved with a generic delegate, I don't think it's a very optimal solution for my problem.
Injecting Generic type parameters with Autofac
Autofac. How to inject a open Generic Delegate in constructor
How to inject a factory of generic types with Autofac
Autofac with nested open generics
I don't think you're going to be able to do what you want. Sorry, probably not the answer you'd like. I'll show you why, and maybe some workarounds, but having an arbitrary collection of closed generics that don't get closed until resolution isn't really a thing.
Let's ignore DI for a second and just consider FruitService, which I don't see in the question, but which we see in a usage here:
builder.Register(c => new FruitService(c.ResolveNamed("appleService")))
.As<IDbMapperService>();
Note we can see that FruitService implements IDbMapperService because it's registered as that interface.
Further, we can see FruitService looks like it should take some sort of collection of things, since there are two things named the same in the registration example.
builder.RegisterType<SaveApplDbWrapper>().As<DbWrapper<AppleDto, SavedAppleDbEntity>>()
.Named<string>("fruitService");
builder.RegisterType<SaveOrangeDbWrapper>().As<IUcHandler<OrangeDto, OrangeDbEntity>>()
.Named<string>("fruitService");
I noticed that these both implement different generic types. I have to assume based on the rest of the question that these have no common base class.
To make it more concrete and get past the Autofac part, which I don't think is really relevant to the larger issue, let's consider it like this:
var wrapper = new[] { CreateWrapper("appleService"), CreateHandler("appleService") };
var service = new FruitService(wrapper);
Let's assume CreateWrapper and CreateHandler both take a string and, magically, creates the appropriate wrapper/handler types. Doesn't matter how it happens.
There are two things to consider here that relate closely:
What is the type of the parameter in the FruitService constructor?
What do you expect CreateWrapper("appleService") and CreateHandler("appleService") to return?
There are basically only two options here I can see.
Option 1: Use object.
If there's no common base class, then everything has to be object.
public class FruitService : IDBMapperService
{
private readonly IEnumerable<object> _wrappers;
public FruitService(IEnumerable<object>wrapper)
{
this._wrapper = wrapper;
}
public object GetWrapper<TInput, TResult>()
{
object foundWrapper = null;
// Search through the collection using a lot of reflection
// to find the right wrapper, then
return foundWrapper;
}
}
It's not clear that DbWrapper<TInput, TResult> can be cast to IUcHandler<TInput, TResult> so you can't even rely on that. There's no commonality.
But let's say there is common base class.
Option 2: Use the common base class
It seems there's already a notion of DbWrapper<TInput, TResult>. It's important to note that even if you have that generic defined, once you close it, they're two different types. DbWrapper<AppleDto, SavedAppleDbEntity> is not castable to DbWrapper<OrangeDto, SavedOrangeDbEntity>. Generics are more like "class templates" than base classes. They're not the same thing.
You can't, for example, do:
var collection = new DbWrapper<,>[]
{
new DbWrapper<AppleDto, SavedAppleDbEntity>(),
new DbWrapper<OrangeDto, SavedOrangeDbEntity>()
};
However, if you have a common interface or base class, you can do...
var collection = new IDbWrapper[]
{
new DbWrapper<AppleDto, SavedAppleDbEntity>(),
new DbWrapper<OrangeDto, SavedOrangeDbEntity>()
};
But that'd mean you can switch to that and, ostensibly, use the common interface.
public class FruitService : IDBMapperService
{
private readonly IEnumerable<object> _wrappers;
public FruitService(IEnumerable<object>wrapper)
{
this._wrapper = wrapper;
}
public IDbWrapper GetWrapper<TInput, TResult>()
{
IDbWrapper foundWrapper = null;
// Search through the collection using a lot of reflection
// to find the right wrapper, then
return foundWrapper;
// IDbWrapper could expose those `TInput` and `TResult`
// types as properties on the interface, so the reflection
// could be super simple and way more straight LINQ.
}
}
Your consuming code could just take IDbWrapper and call non-generic methods to get things done.
Bringing it back to Autofac...
Remember I mentioned the key was in figuring out what the Create methods should return; or what the FruitService constructor expects? That. That in spades.
You could register everything as keyed objects.
builder.RegisterType<SaveApplDbWrapper>()
.Named<object>("fruitService");
builder.RegisterType<SaveOrangeDbWrapper>()
.Named<object>("fruitService");
builder.RegisterType<SaveMelon>()
.Named<object>("appleService");
builder
.Register(c => new FruitService(c.ResolveNamed<IEnumerable<object>>("appleService")))
.As<IDbMapperService>();
The Resolve operations in Autofac are the create methods from my example. There's no magic there; it's just creating objects. You still have to know what type you want it to provide.
Or you could use a common base class.
builder.RegisterType<SaveApplDbWrapper>()
.Named<IDbWrapper>("fruitService");
builder.RegisterType<SaveOrangeDbWrapper>()
.Named<IDbWrapper>("fruitService");
builder.RegisterType<SaveMelon>()
.Named<IDbWrapper>("appleService");
builder
.Register(c => new FruitService(c.ResolveNamed<IEnumerable<IDbWrapper>>("appleService")))
.As<IDbMapperService>();
If you don't mind mixing the DI system into the FruitService you can do something like this:
public class FruitService
{
private readonly ILifetimeScope _scope;
public FruitService(ILifetimeScope scope)
{
this._scope = scope;
}
public DbWrapper<TInput, TResult> GetWrapper<TInput, TResult>()
{
var type = typeof(DbWrapper<TInput, TResult>);
var wrapper = this._lifetimeScope.Resolve(type);
return wrapper;
}
}
You'd have to register things without them being named and As a DbWrapper, but it'd work if everything is based on that.
builder.RegisterType<SaveApplDbWrapper>()
.As<DbWrapper<AppleDto, SavedAppleDbEntity>>();
// Must be DbWrapper, can also be other things...
builder.RegisterType<SaveOrangeDbWrapper>()
.As<IUcHandler<OrangeDto, OrangeDbEntity>>()
.As<DbWrapper<OrangeDto, OrangeDbEntity>>();
builder.RegisterType<SaveMelon>()
.As<DbWrapper<MelonDto, MelonDbEntity>>()
.As<IUcHandler<MelonDto, MelonDbEntity>>();
builder.RegisterType<FruitService>()
.As<IDbMapperService>();
When you resolve IDbMapperService the FruitService constructor will get a reference to the lifetime scope from which it was resolved. All of the wrappers will be resolved from that same scope.
Folks generally don't like mixing IoC references into their code like this, but it's the only way I can see you'd get away from having to mess with reflection or casting up and down all over.
Good luck!
I have a project that is using a decorator convention to wrap command handlers with logging decorators via interception of open generic types in StructureMap 2.6. However, I'm having difficulty figuring out the best way to implement the equivalent functionality in StructureMap 3 so that I can complete the upgrade.
Here's the code from StructureMap 2.6. First, in my IoC class I have a scanning policy set up to resolve the command handlers:
scan.ConnectImplementationsToTypesClosing(typeof(ICommandHandler<>));
Next, I have a decorator convention, which is added to the IoC's scanning conventions, that wires up the decorator interception:
public class CommandLoggingDecoratorConvention : IRegistrationConvention
{
public void Process(Type type, Registry registry)
{
var interfaceTypes = type.GetInterfaces();
foreach (var interfaceType in interfaceTypes)
{
if (interfaceType.IsGenericType
&& interfaceType.GetGenericTypeDefinition() == typeof(ICommandHandler<>))
{
var arguments = interfaceType.GetGenericArguments();
var closedType = typeof(CommandHandlerLoggingDecorator<>)
.MakeGenericType(arguments);
registry.For(interfaceType)
.EnrichWith((c, p) => Activator.CreateInstance(
closedType,
p,
c.GetInstance<IMessageLoggingHelper>(),
c.GetInstance<ILog>()));
}
}
}
}
Then, we have a command bus which maps a specific command to a command handler and calls the Execute method on the logging decorator (which is wrapping the command handler) which in turns calls the Execute method on the command inside of the decorator:
public class CommandBus : ICommandBus
{
public static IContainer Container;
public void Execute(ICommand command)
{
var handlerType = typeof (ICommandHandler<>)
.MakeGenericType(command.GetType());
dynamic handler = Container
.GetAllInstances(handlerType)
.Cast<dynamic>()
.Single();
handler.Execute((dynamic) command);
}
}
I have been able to make this work in StructureMap 3 by replacing my decorator convention with an interceptor policy and adding the interceptor policy in the IoC class.
Here's the interceptor policy:
public class CommandLoggingDecoratorPolicy : IInterceptorPolicy
{
public string Description { get; private set; }
public IEnumerable<IInterceptor> DetermineInterceptors(Type pluginType, Instance instance)
{
if (pluginType == typeof (ICommandHandler<>))
yield return new DecoratorInterceptor(
typeof(ICommandHandler<>),
typeof(CommandHandlerLoggingDecorator<>));
}
And here's the code that adds it to the IoC's interceptor policies:
x.Policies.Interceptors(new CommandLoggingDecoratorPolicy());
However, when I call Container.GetInstance (in my CommandBus) it returns the matching Command Handler implementation instead of the Command Logging decorator. If I call Container.GetAllInstances, it returns both the implementation (first) and the decorator (second).
So, right now, the only way I am able to make this work is if I either explicitly choose the second item returned from Container.GetAllInstances or filter the results and choose the decorator using reflection. Here's an example:
public class CommandBus : ICommandBus
{
public static IContainer Container;
public void Execute(ICommand command)
{
var handlerType = typeof (ICommandHandler<>)
.MakeGenericType(command.GetType());
var handlers = Container
.GetAllInstances(handlerType)
.Cast<dynamic>();
var handler = handlers.ToList()[1];
handler.Execute((dynamic) command);
}
}
However, this seems like a pretty ugly solution. There clearly must be something that I'm missing. First, why is Container.GetInstance returning the implementation rather than the decorator when I've explicitly added a decorator interception policy? Second, is there a better way that I should be doing this altogether?
Any ideas or suggestions would be greatly appreciated!
See this remarkably similar sample (that I just wrote) in the StructureMap codebase for an example of using decorators with generic types: https://github.com/structuremap/structuremap/blob/b405d8f752b45ac250f057d9e3de8554f2a7f40f/src/StructureMap.Testing/Bugs/OpenGenericDecorator_question.cs
I put a question here: Raising Domain Events For Multiple Subscribers and the answer led me to the following pattern where I can have an IEventPublisher like so:
public interface IEventPublisher<T>
{
void Publish(T data);
}
and an IEventSubscriber like so:
public interface IEventSubscriber<T>
{
void Handle(T data);
}
The problem with this is that I need to pass an instance of each publisher to a constructor like so:
public Service(IEventPublisher<ThingyChangedEvent> publisherThingyChanged)
{
// Set publisher to local variable
}
// then call this in a method
_publisherThingyChanged.Publish(new ThingyChangedEvent { ThingyId = model.Id});
What I would ideally like to be able to do is have a generic publisher which contains any IEventPublishers so I can call somthing like:
_genericPublisher.Publish(new ThingyChangedEvent { ThingyId = model.Id});
I can't figure out how to do this though as I can't pass a collection of IEventPublisher without defining T as in this example as ThingyChangedEvent whereas what I want is to determine the publisher based on the type that is passed to the generic publisher.
Any suggestions much appreciated.
EDIT:
OK using the answer below and some info from here: http://www.udidahan.com/2009/06/14/domain-events-salvation/ I came up with the following but it's not quite there:
public interface IEventManager
{
void Publish<T>(T args) where T : IEvent;
}
public class EventManager : IEventManager
{
Autofac.ILifetimeScope _container;
public EventManager(Autofac.ILifetimeScope container)
{
_container = container;
}
//Registers a callback for the given domain event
public void Publish<T>(T args) where T : IEvent
{
var subscribersProvider = _container.Resolve<IEventSubscribersProvider<T>>();
foreach (var item in subscribersProvider.GetSubscribersForEvent())
{
item.Handle(args);
}
}
}
I can now take an instance of IEventManager eventManager in a constructor resolved by autofac and call it as follows:
_eventManager.Publish<ThingyChangedEvent>(new ThingyChangedEvent() { ThingyId = Guid.NewGuid() });
Here is what I don't like about this solution:
I don't want to take an instance of ILifetimeScope in the constructor, I want to be able to take a collection of IEventSubscribersProvider but autofac won't resolve this if I ask for say:
IEnumerable<IEventSubscribersProvider<IEvent>>
I can only resolve it if I pass the type to the Publish and call:
Resolve<IEventSubscribersProvider<T>>.
The second issue is not a huge deal but would be nice to be able to call publish without having to pass the type as well like so:
_eventManager.Publish(new ThingyChangedEvent() { ThingyId = Guid.NewGuid() });
I think if anyone has any suggestions of how to solve these two issues, particularly issue 1 as I don't like putting a dependency on Autofac in different projects. The only thing I can come up with is a manager class of some kind which explicitly takes what I need as follows:
public SomeConstructor(
IEventSubscribersProvider<ThingyChangedEvent> thingChangedSubscribeProviders,
IEventSubscribersProvider<SomeOtherEvent> someOtherSubscribeProviders,
etc....)
{
// Maybe take the EventManager as well and add them to it somehow but would be
// far easier to take a collection of these objects somehow?
}
Many thanks for any suggestions.
EDIT 2
After a lot of research and looking at this Autofac Generic Service resolution at runtime I am not sure I can achieve what I want to. The best solution I can come up with is this:
public interface IEventSubscribersProviderFactory : Amico.IDependency
{
IEventSubscribersProvider<T> Resolve<T>() where T : IEvent;
}
public class EventSubscribersProviderFactory : IEventSubscribersProviderFactory
{
Autofac.ILifetimeScope _container;
public EventSubscribersProviderFactory(Autofac.ILifetimeScope container)
{
_container = container;
}
public IEventSubscribersProvider<T> Resolve<T>() where T : IEvent
{
return _container.Resolve<IEventSubscribersProvider<T>>();
}
}
And then have the EventManager take IEventSubscribersProviderFactory in the constructor to remove the dependency on Autofac from that project.
I'll go with this for now but hopefully will find a better solution int the long term.
It can get a bit complex when you have to deal with multiple types of events. As you've probably noticed you can't just use a derived generic type and expect to use it like a base generic--.NET variance doesn't support that where you'd want to use it.
You need a "base" type that would be the minimum (or most narrow) type that you'd accept as an "event". I generally use a marker interface like public interface IEvent{}. You could, of course, derive from Object; but I find it useful to have marker interfaces to make the fact that you're subscribing or publishing an "event" explicit (and means you can't just publish any type of object, just "events").
From the handling of multiple type aspect, you need to write a class to do the narrowing (taking a derived type and "publish" the same object cast to the derived type). Even with that you need to route your events through an appropriate instance of a narrower (to "get around" the variance limitations). Then, of course, you could have multiple subscribers to the same event type; so you need something to route an event to the multiple subscribers. This is generally called a Multiplexor, which would be a specialization of IEventPublisher. You'll need one multiplexor per event type--which would use the narrower. Which multiplexor to use for a given event depends on type, so that collection of multiplexors would be managed by a dictionary so you can look them up by type. Then, to publish an event to multiple subscribers, by type, you simple look up the multiplexor and call its IEventPublisher.Publish method. And something that manages the multiplexors is a type of IEventPublisher and is generally called a Dispatcher (some might call it a router).
For example:
public class NarrowingSubscriber<TBase, TDerived> : IEventSubscriber<TBase>
where TDerived : TBase
where TBase : IEvent
{
private IEventSubscriber<TDerived> inner;
public NarrowingSubscriber(IEventSubscriber<TDerived> inner)
{
if (inner == null) throw new ArgumentNullException("inner");
this.inner = inner;
}
public void AttachSubscriber(IEventSubscriber<TDerived> subscriber)
{
inner = subscriber;
}
public void Handle(TBase data)
{
inner.Handle((TDerived)data);
}
}
public class Multiplexor<T> : IEventSubscriber<T> where T : IEvent
{
private readonly List<IEventSubscriber<T>> subscribers =
new List<IEventSubscriber<T>>();
public void AttachSubscriber(IEventSubscriber<T> subscriber)
{
subscribers.Add(subscriber);
}
public void RemoveSubscriber(IEventSubscriber<T> subscriber)
{
subscribers.Remove(subscriber);
}
public void Handle(T data)
{
subscribers.ForEach(x => x.Handle(data));
}
}
public class Dispatcher<TBase> : IEventPublisher<TBase> where TBase : IEvent
{
private readonly Dictionary<Type, Multiplexor<TBase>> subscriptions =
new Dictionary<Type, Multiplexor<TBase>>();
public void Publish(TBase data)
{
Multiplexor<TBase> multiplexor;
if (subscriptions.TryGetValue(data.GetType(), out multiplexor))
{
multiplexor.Handle(data);
}
}
public void Subscribe<TEvent>(IEventSubscriber<TEvent> handler)
where TEvent : TBase
{
Multiplexor<TBase> multiplexor;
if (!subscriptions.TryGetValue(typeof(TEvent), out multiplexor))
{
multiplexor = new Multiplexor<TBase>();
subscriptions.Add(typeof(TEvent), multiplexor);
}
multiplexor.AttachSubscriber(new NarrowingSubscriber<TBase, TEvent>(handler));
}
}
So, you're basically publishing 4 times. Once to the dispatcher, once to the multiplexor, once to the narrower, and once to the non-infrastructure subscriber. If you had two subscribers (EventOneEventSubscriber and EventTwoEventSubscriber) that subscribed to two types of events (EventOne and EventTwo) then you might create a dispatcher and publish events like this:
var d = new Dispatcher<IEvent>();
var eventTwoSubscriber = new EventTwoEventSubscriber();
d.Subscribe(eventTwoSubscriber);
var eventOneSubscriber = new EventOneEventSubscriber();
d.Subscribe(eventOneSubscriber);
d.Publish(new EventOne());
d.Publish(new EventTwo());
Of course, the events would derive from IEvent:
public class EventOne : IEvent
{
}
public class EventTwo : IEvent
{
}
This particular limitation does not take into account dispatching events multiple times. For example, I could have on subscriber to EventOne and one subscriber for IEvent. This implementation just publishes to the EventOne subscriber if an EventOne object is published through the dispatcher--it wouldn't publish to the IEvent subscriber. I'll leave that as an exercise for the reader :)
Update:
If what you're hoping to do is to auto-wire the subscribers without having to construct them (I don't see much value in this, consider a Composition Root) then you can add a fairly simple method to the Dispatcher (or elsewhere, if needed) to subscribe all compatible subscribers:
public void InitializeSubscribers()
{
foreach (object subscriber in
from assembly in AppDomain.CurrentDomain.GetAssemblies()
from type in assembly.GetTypes()
where !type.IsAbstract && type.IsClass && !type.ContainsGenericParameters &&
type.GetInterfaces().Any(t => t.IsGenericType &&
t.GetGenericTypeDefinition() == typeof (IEventSubscriber<>))
select type.GetConstructor(new Type[0])
into constructorInfo
where constructorInfo != null
select constructorInfo.Invoke(new object[0]))
{
Subscribe((dynamic) subscriber);
}
}
in which you'd use as follows:
var d = new Dispatcher<IEvent>();
d.InitializeSubscribers();
...using a container to resolve the Dispatcher<T> object, if you want.