Is it possible to filter dependencies when resolving IEnumerable in autofac?
I have multiple implementations of an interface (IHandler in the example below) which are defined & registered using an Autofac module in isolated projects. I would like to be able to filter the implementations when resolving in the parent type (Processor in the example below).
The IHandler implementations could be injected into the Processor and filtered in the ctor but this would require resolving all implementations regardless whether they are required which is wasteful.
public interface IHandler { }
public class Handler1 : IHandler { }
public class Handler2 : IHandler { }
public class Handler3 : IHandler { }
public class Processor {
public IEnumerable<IHandler> Handlers;
public Processor(IEnumerable<IHandler> handlers) {
Handlers = handlers;
}
}
static void Main(string[] args)
{
var builder = new ContainerBuilder();
builder.RegisterType<Handler1>().As<IHandler>();
builder.RegisterType<Handler2>().As<IHandler>();
builder.RegisterType<Handler3>().As<IHandler>();
builder.RegisterType<Processor>().AsSelf();
var container = builder.Build();
var processor = container.Resolve<Processor>();
}
As only 1 key can be resolved at a time, my attempt with keys didnt work:
[Flags]
public enum HandlerType
{
One = 1,
Two = 2,
Three = 4
}
builder.RegisterType<Handler1>().Keyed<IHandler>(HandlerType.One);
builder.RegisterType<Handler2>().Keyed<IHandler>(HandlerType.Two);
builder.RegisterType<Handler3>().Keyed<IHandler>(HandlerType.Three);
var enabledHandlers = HandlerType.One | HandlerType.Three;
builder.RegisterType<Processor>().AsSelf()
.WithParameter(ResolvedParameter.ForKeyed<IEnumerable<IHandler>>(enabledHandlers));
I would recommend using the Meta<T> and Lazy<T> implicit relationship types to allow the processor to read config and control all that at runtime. That would also allow you to filter differently in different conditions or turn filtering off entirely without having to change any keys.
Register the handlers with metadata instead of as keyed services...
builder.RegisterType<Handler1>()
.As<IHandler>()
.WithMetadata("type", HandlerType.One);
builder.RegisterType<Handler2>()
.As<IHandler>()
.WithMetadata("type", HandlerType.Two);
builder.RegisterType<Handler3>()
.As<IHandler>()
.WithMetadata("type", HandlerType.Three);
Update your processor to take IEnumerable<Meta<Lazy<IHandler>>> and filter during construction or at some later point when the handlers are needed, your call.
public class Processor
{
private readonly IHandler[] _handlers;
public Processor(IEnumerable<Meta<Lazy<IHandler>>> handlers)
{
this._handlers =
handlers
.Where(h => h.Metadata["type"] == HandlerType.One || h.Metadata["type"] == HandlerType.Three)
.Select(h => h.Value.Value)
.ToArray();
}
}
Each item coming in to the constructor will be a Meta<Lazy<IHandler>>:
Meta<T> has a Metadata dictionary to query and the Value will be the Lazy<IHandler>.
Lazy<T> will not resolve/construct the handler until you call the Value property, so it won't be expensive or cause resolutions you don't want.
So item.Value.Value will be the resolved IHandler (as you see in the LINQ above).
The stuff in the Where filter could be based on config or anything else. But the real win here is that if you still need to resolve all the handlers somewhere else...
public OtherHandlerConsumer(IEnumerable<IHandler> handlers)
...that will still work. You can't do that if they're all keyed. Plus you can add as much metadata as you want to the registrations or even define more robust strongly typed metadata so you can make smarter decisions about which handlers you want.
If you can provide proper filter during container set up phase (as you do in your sample code), you could change your Processor type registration to the following:
builder.RegisterType<Processor>().AsSelf()
.WithParameter((p, c) => p.Name == "handlers",
(p, c) => new[]
{
c.ResolveKeyed<IHandler>(HandlerType.One),
c.ResolveKeyed<IHandler>(HandlerType.Three)
});
Values you need to use could be taken from anywhere you want, from config file too.
Since the registered handlers are based on a configuration switch, it means that the selected handlers won't change at runtime. This is very different than selecting the handlers based on some runtime condition. I therefore propose something similar to this:
var handlerIds = ConfigurationManager.AppSettings["Handlers"].Split(',');
if (handlerIds.Contains("1")) builder.RegisterType<Handler1>().As<IHandler>();
if (handlerIds.Contains("2")) builder.RegisterType<Handler2>().As<IHandler>();
if (handlerIds.Contains("3")) builder.RegisterType<Handler3>().As<IHandler>();
if (handlerIds.Contains("4")) builder.RegisterType<Handler4>().As<IHandler>();
// etc
builder.RegisterType<Processor>().AsSelf();
Related
I'm looking for a way to implement the following.
I want to be able to register "ActionHandlers" as services in my DI Container, for this purpose I have made the following interfaces:
public interface IActionHandler {
Task HandleAsync(IAction action);
}
public interface IActionHandler<T> : IActionHandler where T : IAction, new() {
Task HandleAsync(T action);
}
My idea was then to create a derived type called ActionHandlerContainer:
public class ActionHandlerContainer : IActionHandler {
private readonly Dictionary<Type, IActionHandler> _handlers;
public ActionHandlerContainer(IEnumerable<IActionHandler<??T??>>) {
// What to do here?.
// As this ActionHandlerContainer class is registered as a service,
// I expect the DI container in return to inject all my ActionHandler services here.
}
public Task HandleAsync(IAction action) {
// Fetch appropriate handler from the map.
_handlers.TryGetValue(action.getType(), out var actionHandler);
if(actionHandler == null) {
throw new Exception($"No handler could be found for the Action of type: {action.GetType()}");
}
// Invoke the correct handler.
return actionHandler.HandleAsync(action);
}
}
Which would take in any action and delegate it to the correct handler, an example handler could look like:
public class SetColorActionHandler : IActionHandler<SetColorAction> {
public async Task HandleAsync(SetColorAction action) {
return await ComponentManager.SetComponentColor(action);
}
}
The DI container service registration would look like this (I suppose)
builder.Services.AddTransient<IActionHandler<SetColorAction>, SetColorActionHandler>();
builder.Services.AddSingleton<ActionHandlerContainer>();
Some open questions I have myself is:
Should multiple ActionHandlers be able to be registered to one action..
Is it possible to implement the decorator pattern on top of this, say I want a ConsoleDebugLoggingSetColorActionHandler which decorates the original SetColorActionHandler.
A problem I have right now is if IActionHandler implements IActionHandler, then any IActionHandler implementation has to implement the code async Task HandleAsync(IAction action) method which seems duplicative.
So my question is, given the code examples and explanations, how can I implement this properly?
Thanks in advance, any help is appreciated,
Nicky.
[EDIT1]:
I tried the following in ActionHandlerContainer::HandleAsync
public Task HandleAsync(IAction action) {
Type runtimeType = action.GetType();
var _handler = _serviceProvider.GetService(typeof(IActionHandler<runtimeType>));
}
But this does not seem to work.
[EDIT2]:
Providing some context for vendettamit:
public class MqttClientWrapper {
...<omitted>
private Task ClientOnApplicationMessageReceivedAsync(MqttApplicationMessageReceivedEventArgs arg) {
Console.WriteLine("The client received an application message.");
arg.DumpToConsole();
// Create the ActionPayload from the MQTT Application Message's Payload.
var actionPayload = ActionPayload.FromPayload(arg.ApplicationMessage.Payload);
// Grab the correct action type from the map according to the identifier in the payload.
var actionType = ActionMap.ActionIdentifierToActionType[actionPayload.ActionIdentifier];
// Now instruct the factory to instantiate that type of action.
var action = _actionFactory.CreateAction(actionPayload.ActionData, actionType);
// Finally, pass on the action to the correct handler.
_actionHandlerContainer.HandleAsync(action);
return Task.CompletedTask;
}
}
One suggestion: Use MediatR. In the past I've railed against it, but I've softened. It's not perfect, but it's a thorough implementation of what you're trying to solve.
Or, here's a detailed custom approach.
As you noted in your question, the issue is that if you're going to have a collection of IActionHandlers<T> but T is different for each one, then what is the type of the collection?
Any solution will involve some sort of reflection or type-checking. (That's inevitable. You're starting with an IAction, but you don't want an IActionHandler<IAction> - you want individual handlers for specific implementations of IAction.) Even though I don't usually use object, it's okay as long as my code ensures that the object will be the expected type. That is, given type T, you're going to get an object which can be cast as IActionHandler<T>.
Here's an approach. I use the terms "command" and "command handler" instead of "action" and "action handler." There's some reflection involved, but it does the job. Even if it's not exactly what you need, it might give you some ideas.
First, some interfaces:
public interface ICommand
{
}
public interface ICommandHandler
{
Task HandleAsync(ICommand command);
}
public interface ICommandHandler<TCommand> where TCommand : ICommand
{
Task HandleAsync(TCommand command);
}
ICommand marks a class which is used as a command.
ICommandHandler is the interface for a class that takes any ICommand and "routes" it to a specific command handler. It's the equivalent of IActionHandler in your question.
ICommandHandler<T> is the interface for the type-specific command handler.
Here's the implementation of ICommandHandler. This has to
receive a command
resolve an instance of the concrete handler for that command type
invoke the handler, passing the command to it.
public class CommandHandler : ICommandHandler
{
private readonly Func<Type, object> _getHandler;
public CommandHandler(Func<Type, object> getHandler)
{
_getHandler = getHandler;
}
public async Task HandleAsync(ICommand command)
{
var commandHandlerType = GetCommandHandlerType(command);
var handler = _getHandler(commandHandlerType);
await InvokeHandler(handler, command);
}
private Type GetCommandHandlerType(ICommand command)
{
return typeof(ICommandHandler<>).MakeGenericType(command.GetType());
}
// See the notes below. This reflection could be "cached"
// in a Dictionary<Type, MethodInfo> so that once you find the "handle"
// method for a specific type you don't have to repeat the reflection.
private async Task InvokeHandler(object handler, ICommand command)
{
var handlerMethod = handler.GetType().GetMethods()
.Single(method => IsHandleMethod(method, command.GetType()));
var task = (Task)handlerMethod.Invoke(handler, new object[] { command });
await task.ConfigureAwait(false);
}
private bool IsHandleMethod(MethodInfo method, Type commandType)
{
if (method.Name != nameof(ICommandHandler.HandleAsync)
|| method.ReturnType != typeof(Task))
{
return false;
}
var parameters = method.GetParameters();
return parameters.Length == 1 && parameters[0].ParameterType == commandType;
}
}
Here's what this does when public async Task HandleAsync(ICommand command) is called:
Determines the generic type of the handler for the command. If the command type is FooCommand then the generic command handler type is ICommandHandler<FooCommand>.
Calls Func<Type, object> _getHandler to get a concrete instance of the command handler. That function is injected. What is the implementation of that function? More on that later. But the point is that as far as this class is concerned, it can pass the handler type to this function and get back a handler.
Finds the "handle" method on the handler type.
Invokes the handle method on the concrete handler, passing the command.
There's room for improvement here. Once it finds the method for a type it could add it to a Dictionary<Type, MethodInfo> to avoid that reflection again. It could even create a function that performs the whole invocation and add it to a Dictionary<Type, Func<Object, Task>. Either of those would improve performance.
(If that sounds convoluted, then once again that's a reason to consider using MediatR. There are a few details about it that I don't like, but does all this work. It also handles more complex scenarios like handlers that return something or handlers that use a CancellationToken.)
That leaves the question - what is the Func<Type, object> that takes a command type and returns the correct command handler?
If you're using IServiceCollection/IServiceProvider, these extensions register everything and provide that. (The point is that injecting the function means that we're not tied to that specific IoC container.)
public static class CommandHandlerServiceCollectionExtensions
{
public static IServiceCollection AddCommandHandling(this IServiceCollection services)
{
services.AddSingleton<ICommandHandler>(provider => new CommandHandler(handlerType =>
{
return provider.GetRequiredService(handlerType);
}
));
return services;
}
public static IServiceCollection AddHandlersFromAssemblyContainingType<T>(this IServiceCollection services)
where T : class
{
var assembly = typeof(T).Assembly;
IEnumerable<Type> types = assembly.GetTypes().Where(type => !type.IsAbstract && !type.IsInterface);
foreach (Type type in types)
{
Type[] typeInterfaces = type.GetInterfaces();
foreach (Type typeInterface in typeInterfaces)
{
if (typeInterface.IsGenericType && typeInterface.GetGenericTypeDefinition() == typeof(ICommandHandler<>))
{
services.AddScoped(typeInterface, type);
}
}
}
return services;
}
}
The first method registers CommandHandler as the implementation of ICommandHandler. The implementation of Func<Type, object> is
handlerType =>
{
return provider.GetRequiredService(handlerType);
}
In other words, whatever the handler type is, resolve it from the IServiceProvider. If the type is ICommandHander<FooCommand> then it's going to resolve whatever implementation of that interface is registered.
This dependency on the IServiceProvider at runtime is not a service locator. (Everything ultimately depends on it at runtime.) CommandHandler depends on an abstraction - a function - not IServiceProvider. The use of the IoC container is all in the composition root.
You could manually register each one of those implementations:
serviceCollection.AddScoped<ICommandHander<FooCommand>, FooCommandHandler>();
...etc. The second extension does that for you. It discovers implementations of ICommandHandler<T> and registers them with the IServiceCollection.
I have used this in production code. If I wanted it to be more robust I'd add handling for cancellation tokens and maybe return types. (I could be lazy and argue that return types violate command/query separation.) It would require updating how InvokeHandler selects a method on the handler to invoke.
And because nothing is complete without tests, here's a test.
It's convoluted. It creates a command which contains both a list and a number. The command handler adds the number to the list. The point is that it's observable. The test only passes if the handler gets registered, resolved, and invoked so that the number gets added to the list.
[TestClass]
public class CommandHandlerTests
{
[TestMethod]
public async Task CommandHandler_Invokes_Correct_Handler()
{
var serviceCollection = new ServiceCollection();
serviceCollection
.AddCommandHandling()
.AddHandlersFromAssemblyContainingType<AddNumberToListCommand>();
var serviceProvider = serviceCollection.BuildServiceProvider();
var commandHandler = serviceProvider.GetRequiredService<ICommandHandler>();
var list = new List<int>();
var command = new AddNumberToListCommand(list, 1);
// This is the non-generic ICommandHandler interface
await commandHandler.HandleAsync(command);
Assert.IsTrue(list.Contains(1));
}
}
public class AddNumberToListCommand : ICommand
{
public AddNumberToListCommand(List<int> listOfNumbers, int numberToAdd)
{
ListOfNumbers = listOfNumbers;
NumberToAdd = numberToAdd;
}
public List<int> ListOfNumbers { get; }
public int NumberToAdd { get; }
}
public class AddNumberToListHandler : ICommandHandler<AddNumberToListCommand>
{
public Task HandleAsync(AddNumberToListCommand command)
{
command.ListOfNumbers.Add(command.NumberToAdd);
return Task.CompletedTask;
}
}
So what I like:
You're thinking "Open/Closed Principle". That's good.
What I don't like.
Your Dictionary has "Type" as a Key. Thus you're trying to store EVERY Type to its 1:N IActionHandler's in one place.
(By the way, you'll probably get a Key-Exists error (or it would just overwrite the single) if you tried to register 2:N IActionHandlers for a single Type.
I would move toward:
public class ActionHandlerContainer<T> : IActionHandler<T> {
private readonly IDictionary<int, IActionHandler<T>> _handlers;
and "inject" your specific to a single T 1:N concrete handlers.
Notice, I've removed the "Type", and changed to an int? Why an int? Because if you want to control the ORDER of the injected items. You can loop over the IDictionary (int) Keys (in order).
So how would this play out?
You don't register a single ActionHandlerContainer (with all the types)
You register something like
(ioc register the below)
ActionHandlerContainer<Employee>
and you constructor inject your 1:N EmployeeHandler(s) into the above.
then you register something like (a different "Type")
(ioc register the below)
ActionHandlerContainer<Candy>
You are not using Generics to be a "Type holder of everything". You use Generics to reduce copies of code. (so you don't have to write a "copy" for just Employee, and another copy for "Candy".....
Somewhere you need to inject the
ActionHandlerContainer<Employee> ahce
...
public EmployeeManager : IEmployeeManager
private readonly ActionHandlerContainer<Employee> theAhce;
public EmployeeManager(ActionHandlerContainer<Employee> ahce)
{
this.thheAhce = ahce; /* simple code, you should actually check for null on the input ahce to make sure its not null */
}
public void UpdateEmployee(Employee emp)
{
this.theAhce.Invoke(emp); /* << and this will of course run your 1:N EMPLOYEE handlers */
}
Something like that.
IMHO, get rid of the "holds ALL types" mentality.
I want to use Autofac to create a new instance of one or several WCF channels for a given unit of work. I'd like to use the command pattern to represent units of work, i.e. a given command class is injected with the channel(s) it needs and implements a bunch of related operations.
I tried the following:
interface IUnitOfWork
{
}
class FooCall : IUnitOfWork
{
readonly BarChannel _channel;
public FooCall(BarChannel channel)
{
Console.WriteLine($"FooCall({new {channel}})");
_channel = channel;
}
public string Foo()
{
return "FOO";
}
}
class BarChannel
{
public BarChannel()
{
Console.WriteLine("BarChannel()");
}
}
class FooService
{
Func<Owned<FooCall>> _helperFn;
public FooService(Func<Owned<FooCall>> helperFn)
{
_helperFn = helperFn;
}
public void CallFoo()
{
using (var helper = _helperFn())
{
Console.WriteLine($"CallFoo(), helper={helper}");
helper.Value.Foo();
}
}
}
class Program
{
static void Main(string[] args)
{
var builder = new ContainerBuilder();
builder.RegisterType<BarChannel>().InstancePerOwned<IUnitOfWork>();
builder.RegisterType<FooCall>().AsImplementedInterfaces().AsSelf();
builder.RegisterType<FooService>();
using (var scope = builder.Build().BeginLifetimeScope())
{
Console.WriteLine("call 1");
scope.Resolve<FooService>().CallFoo();
Console.WriteLine("call 2");
scope.Resolve<FooService>().CallFoo();
}
}
}
In short: a service method creates an owned unit of work; the unit of work is injected with a per-owned channel that it calls. The code sample should show two channel instances being created.
Except that it seems that the lifetime scope created for owned dependencies is only tagged with the type as which the dependency was resolved - i.e. as FooCall, not as IUnitOfWork. If I register BarChannel as InstancePerOwned<FooCall>, the code works; as is, registered as InstancePerOwned<IUnitOfWork>, it fails to resolve FooService since it can't find a matching lifetime scope. Am I missing something or is what I want to do not possible with Autofac? I'd rather not have to register all my WCF channels as instance-per-owned for every command class, that seems like it would get pretty verbose. Another workaround would be using instance-per-depedency and resolving a Func directly, but that won't let me say compose units of work while reusing channels and their dependencies between them.
The problem is that InstancePerOwned<T> is really just a special case of InstancePerMatchingLifetimeScope(params object[] lifetimeScopeTag), where the scope is tagged with something like typeof(T). As it stands, there needs to be a direct link between the tag provided there and the one attached to the scope when attempting to resolve, which is always set to the type of whatever's inside that specific Owned<> dependency. There's no additional logic to imply relations between types at that point, it's just a direct match on the tags.
However, InstancePerMatchingLifetimeScope does allow multiple tags to be specified, so it's possible to do something like:
builder.RegisterType<BarChannel>()
.InstancePerMatchingLifetimeScope(new TypedService(typeof(FooCall)),new TypedService(typeof(AnotherUnitOfWork)));
To wrap this up a bit more neatly you could use:
private static IEnumerable<Type> GetTypesImplementingInterface<TInterface>()
{
return AppDomain.CurrentDomain.GetAssemblies()
.SelectMany(s => s.GetTypes())
.Where(p => typeof(TInterface).IsAssignableFrom(p));
}
and then a new extension method:
public static class AutofacRegistrationBuilderExtensions
{
public static IRegistrationBuilder<TLimit, TActivatorData, TRegistrationStyle> InstancePerOwned<TLimit, TActivatorData, TRegistrationStyle>(
this IRegistrationBuilder<TLimit, TActivatorData, TRegistrationStyle> builder, IEnumerable<Type> serviceTypes)
{
return builder.InstancePerMatchingLifetimeScope(serviceTypes.Select(s => new TypedService(s)).ToArray());
}
}
The usage would then just be:
builder.RegisterType<BarChannel>().InstancePerOwned(GetTypesImplementingInterface<IUnitOfWork>());
I'm not sure if the last part there would be worth pulling into Autofac itself, but I guess if it did then it might be better to combine the two methods above together and retrieve the list of types applicable from existing registrations, e.g. something like
InstancePerOwnedImplementing<TInterface>();
Alternatively, it would probably be a bit messy to extend the matching scope logic to check the relationship between types at resolution time, since not all tags are of the type Type.
I wanna resolve different instances with the same interface. I read something about named registrations which should probably push me in the right direction except I can't seem to fit them in a hierarchy structure.
public interface IServiceType
{
}
public interface IServiceDependancy
{
}
public class main
{
var container = new UnityContainer();
container.RegisterType(typeof(IServiceType), typeof(ServiceType));
container.RegisterType(typeof(IServiceDependancy), typeof(ProductionServiceDependancy), "Production");
container.RegisterType(typeof(IServiceDependancy), typeof(TestServiceDependancy), "Test");
}
How can I resolve the IServiceType twice (or more)?
First time with my TestServiceDependancy.
Second time with my ProductionServiceDependancy
Kind regards
It seems to me that you don't need named registrations. Since you are talking about a ProductionServiceDependency and TestServiceDependency you would typically just want to register either one of them, and only use a different one when the application is restarted (because of a different configuration setting). In other words, you can simply do this:
if (ConfigurationManager.AppSettings["IsTest"] != string.Empty) {
container.RegisterType(typeof(IServiceDependency), typeof(TestServiceDependancy));
else
container.RegisterType(typeof(IServiceDependency), typeof(ProductionServiceDependency));
Or perhaps simply:
container.RegisterType(typeof(IServiceDependency),
ConfigurationManager.AppSettings["IsTest"] != string.Empty
? typeof(TestServiceDependency)
: typeof(ProductionServiceDependency));
In case you need to be able to swap the implementation based on some runtime condition (perhaps because you need to be able two change the configuration at runtime), you should hide the two implementations behind a proxy:
public sealed class ServiceDependencySelectionProxy : IServiceDependency {
private Func<bool> selectionPredicate;
private IServiceDependency trueService;
private IServiceDependency falseService;
public ServiceDependencySelectionProxy(Func<bool> selectionPredicate,
IServiceDependency trueService, IServiceDependency falseService) {
this.selectionPredicate = selectionPredicate;
this.trueService = trueService;
this.falseService = falseService;
}
object IServiceDependency.ItsMethod(object param) {
return this.selectionPredicate()
? this.trueService.ItsMethod(param)
: this.falseService.ItsMethod(param);
}
}
Now you can register the ServiceDependencySelectionProxy as IServiceDependency and this will hide the fact that there is a some runtime selection going on, while keeping your object graph itself completely static (as in: its structure wont change at runtime) and this keeps your object graph verifiable.
Here's an example of how to register this ServiceDependencySelectionProxy:
container.RegisterType<IServiceDependancy, ProductionServiceDependancy>("Production");
container.RegisterType<IServiceDependancy, TestServiceDependancy>("Test");
container.Register<IServiceDependency>(new InjectionFactory(c =>
new ServiceDependencySelectionProxy(
() => IsApplicationTestSwitchEnabled(),
container.Resolve<IServiceDependency>("Test"),
container.Resolve<IServiceDependency>("Production"))));
Can someone please explain the difference between SatisfyImportsOnce and ComposeParts and why one would work where the other doesn't?
Specifically I have a MVC Web application that I am using MEF in. Below is some code (from that application) that works when I use SatisfyImportsOnce but doesn't when I use ComposeParts. My understanding is that ComposeParts creates composable parts from an array of attributed objects and composes them in the specified composition container and that SatisfyImportsOnce composes the specified part by using the specified composition service. To my simple monkey brain even though the English is different they are semantically the same. Both use the CompositionContainer to spit exported types at import targets.
public class FormPartCustomatorFactory
{
[ImportMany(typeof(ICustomRenderer), AllowRecomposition = true)]
private readonly List<Lazy<ICustomRenderer, ICustomRendererMetaData>> _rendererImports = new List<Lazy<ICustomRenderer, ICustomRendererMetaData>>();
private readonly Dictionary<string, Lazy<ICustomRenderer, ICustomRendererMetaData>> _renderers;
public static readonly FormPartCustomatorFactory Instance = new FormPartCustomatorFactory();
static CompositionContainer _container;
private FormPartCustomatorFactory()
{
using (var catalog = new DirectoryCatalog(HttpRuntime.BinDirectory, "*.dll"))
{
_container = new CompositionContainer(catalog);
_container.SatisfyImportsOnce(this); // <- Works
// _container.ComposeParts(this); // DOESN'T Work
_renderers = _rendererImports.ToDictionary(q => q.Metadata.Name, q => q);
}
}
~FormPartCustomatorFactory()
{
_container.Dispose();
}
public static ICustomRenderer Find(string name)
{
return Instance._renderers[name].Value;
}
}
SatisyImportsOnce will compose a type without registering it for recomposition. So, if you intend to use a type without support for recomposition, you can use SatisfyImportsOnce and it will do the work as usual, but any changes in the container (new parts added, or parts removed), then your instance won't automatically be recomposed to offer up these new parts.
In your instance, you are using:
[ImportMany(typeof(ICustomRenderer), AllowRecomposition = true)]
...but through SatisfyImportsOnce, this import won't be recomposed.
If you are not worried about recomposition, you could change your code use constructor injection, so you could do:
[ImportingConstructor]
public FormPartCustomatorFactory(IEnumerable<Lazy<ICustomRenderer, ICustomRendererMetadata>> renderers)
{
if (renderers == null)
throw new ArgumentNullException("renderers");
_renderers = renderers.ToDictionary(r => r.Metadata.Name, r => r);
}
The reason I would suggest constructor injection, is that the set of Lazy<ICustomRenderer, ICustomRendererMetadata> instances are an explicit dependency your type requires, so it would be better to instantiate your type in a usable state, rather than instantiate and then require an additional step to get it ready for first time use.
This makes your FormPartCustomatorFactory type much more testable. To this end, if you were to change the constructor as such, then your method of making it a singleton wouldn't work. Instead, you could take advantage of the lifetime management functionality of MEF, so possibly redesign your type as:
public interface IFormPartCustomatorFactory
{
ICustomRenderer Find(string name);
}
[Export(typeof(IFormPartCustomerFactory)), PartCreationPolicy(CreationPolicy.Shared)]
public class FormPartCustomatorFactory : IFormPartCustomatorFactory
{
private IEnumerable<Lazy<ICustomRenderer, ICustomRendereMetadata>> _renderers;
[ImportingConstructor]
public FormPartCustomatorFactory(IEnumerable<Lazy<ICustomRenderer, ICustomRendererMetadata>> renderers)
{
if (renderers == null)
throw new ArgumentNullException("renderers");
_renderers = renderers;
}
public ICustomRenderer Find(string name)
{
return _renderers
.Where(r => r.Metadata.Name.Equals(name, StringComparison.InvariantCultureIgnoreCase)
.Select(r => r.Value)
.FirstOrDefault();
}
}
Doing it this way means that your type is not dependent on MEF, it can be used without it, its more testable, and the CompositionContainer will manage the lifetime of the part, in this case the CreationPolicy.Shared (which is the default for exported types), uses a singleton lifetime strategy. You can then import an instance of IFormPartCustomator, you import the same singleton instance.
I would also argue that calling it a Factory is possibly wrong, as a factory is designed to create new instances, whereas, your type will only create one instance of each ICustomRenderer. If this is the intended behaviour, maybe it would be better called an FormPartCustomatorService, that implements an IFormPartCusomatorService interface? If you want to spin up new instances each time, you could look at ExportFactory<ICustomRenderer, ICustomRendererMetadata>.
As Matthew mentions, SatisfyImportsOnce doesn't register the part for recomposition. This means the MEF container doesn't hold a reference to the part.
In addition, SatisfyImportsOnce only satisfies the imports of a part, but ignores any exports it has. ComposeParts would add the exports to the container too.
Is this a good pattern? It has a code smell to me with having a factory class aware of the IUnityContainer...
My basic need was to resolve an ICalculationRuleProcess at runtime depending on an Id of a class. It could be based on something other than the Id, I am aware of that... basically I have a known set of Ids that I need to deal with because I bootstrapped the records into the database manually and there is no way to edit the records. With each Id I have a related class. I also have a varying number of constructor parameters within each class that implements the ICalculationRuleProcess, so using an IoC container is extremely helpful versus some crazy switch statement and variable constructor aguments using Activator.CreateInstance
Here is what I did:
Registered the IUnityContainer instance within the container itself. I wasnt sure if this was even possible, but it worked.
Registered all of the ICalculationRuleProcess classes with a unique identifier within the registration (basically just the Id.ToString() of each possible DistributionRule)
Created a factory to determine the correct ICalculationRuleProcess, and had it use the IoC container to figure out the correct class to load.
Registered the factory class (ICalculationRuleProcessFactory) to the IoC container
Wherever the ICalculationRuleProcess needed to be used, I had the class take an ICalculationRuleProcessFactory in its constructor and have it call the Create method to figure out which ICalculationRuleProcess to use.
The code for the factory is here:
public interface ICalculationRuleProcessFactory
{
ICalculationRuleProcess Create( DistributionRule distributionRule );
}
public class CalculationRuleProcessFactory : ICalculationRuleProcessFactory
{
private readonly IBatchStatusWriter _batchStatusWriter;
private readonly IUnityContainer _iocContainer;
public CalculationRuleProcessFactory(
IUnityContainer iocContainer,
IBatchStatusWriter batchStatusWriter )
{
_batchStatusWriter = batchStatusWriter;
_iocContainer = iocContainer;
}
public ICalculationRuleProcess Create( DistributionRule distributionRule )
{
_batchStatusWriter.WriteBatchStatusMessage(
string.Format( "Applying {0} Rule", distributionRule.Descr ) );
return _iocContainer.Resolve<ICalculationRuleProcess>(
distributionRule.Id.ToString() );
}
}
This seems okay to me, given the constraints you described. The most important thing is that all of your rules implement ICalculationRuleProcess and that all consumers of those rules only know about that interface.
It isn't inherently bad that your factory takes the container dependency, especially as an interface. Consider that if you ever had to change container implementations, you could create an IUnityContainer implementation that doesn't use Unity at all (just forward all the members of the interface to their corresponding methods in the replacement container).
If it really bothers you, you can add yet another layer of indirection by creating an agnostic IoC interface with the requisite Register, Resolve, etc. methods and create an implementation that forwards these to Unity.
There is another way you can achieve this without factory taking dependency on IUnityContainer, which is not inherently bad in and of itself. This is just a different way to think about the problem.
The flow is as follows:
Register all different instances of ICalculationRuleProcess.
Get all registered ICalculationRuleProcess and create a creation lambda for each one.
Register ICalculationRuleProcessFactory with a list of ICalculationRuleProcess creation lambdas.
In ICalculationRuleProcessFactory.Create return the right process.
Now the tricky part of this is to preserve the Ids that the registrations were made under. Once solution is to simply keep the Id on the ICalculationProcess interface, but it might not semantically belong there. This is where this solution slips into ugly (which is more of a case of missing functionality in Unity). But, with an extension method and a small extra type, it looks nice when it's run.
So what we do here is create an extension method that returns all registrations with their names.
public class Registration<T> where T : class {
public string Name { get; set; }
public Func<T> CreateLambda { get; set; }
public override bool Equals(object obj) {
var other = obj as Registration<T>;
if(other == null) {
return false;
}
return this.Name == other.Name && this.CreateLambda == other.CreateLambda;
}
public override int GetHashCode() {
int hash = 17;
hash = hash * 23 + (Name != null ? Name.GetHashCode() : string.Empty.GetHashCode());
hash = hash * 23 + (CreateLambda != null ? CreateLambda.GetHashCode() : 0);
return hash;
}
}
public static class UnityExtensions {
public static IEnumerable<Registration<T>> ResolveWithName<T>(this UnityContainer container) where T : class {
return container.Registrations
.Where(r => r.RegisteredType == typeof(T))
.Select(r => new Registration<T> { Name = r.Name, CreateLambda = ()=>container.Resolve<T>(r.Name) });
}
}
public class CalculationRuleProcessFactory : ICalculationRuleProcessFactory
{
private readonly IBatchStatusWriter _batchStatusWriter;
private readonly IEnumerable<Registration<ICalculationRuleProcess>> _Registrations;
public CalculationRuleProcessFactory(
IEnumerable<Registration<ICalculationRuleProcess>> registrations,
IBatchStatusWriter batchStatusWriter )
{
_batchStatusWriter = batchStatusWriter;
_Registrations= registrations;
}
public ICalculationRuleProcess Create( DistributionRule distributionRule )
{
_batchStatusWriter.WriteBatchStatusMessage(
string.Format( "Applying {0} Rule", distributionRule.Descr ) );
//will crash if registration is not present
return _Registrations
.FirstOrDefault(r=>r.Name == distributionRule.Id.ToString())
.CreateLambda();
}
}
//Registrations
var registrations = container.ResolveWithName<ICalculationRuleProcess>(container);
container.RegisterInstance<IEnumerable<Registration<ICalculationRuleProcess>>>(registrations);
After I wrote this I realised that this is more creative lambda douchebaggery than a architecturally pretty solution. But in any case, feel free to get ideas out of it.
Hey Rob, I'm intending to use essentially the same pattern. I've got multiple types of shopping cart item that need to be associated with their own specific set of validator instances of varying class.
I think there is a smell about this pattern and its not that the factory has a reference to the IoC container, its that typically, an IoC container is configured in the application root which is typically the UI layer. If a crazy custom factory was created just to handle these associations then possibly it should be in the domain.
In short, these associations are possibly not part of the overall program structure that's set up before the application runs and so shouldn't be defined in the application root.