Autofac keyed registrations - c#

Is there a way I can acheieve the following in a shorter way than explicitly register those types one by one:
builder.RegisterType<Repo1>().Keyed<IRepository>(typeof(Repo1));
builder.RegisterType<Repo2>().Keyed<IRepository>(typeof(Repo2));
builder.RegisterType<Repo3>().Keyed<IRepository>(typeof(Repo3));
..
Registering each repository as IRepository interface with it's type as key, so that I can use IIndex<Type, IRepository>
Thanks in advance

You could register a function that will return a repository for a given type, to use in your Unit of Work. Func<Type, IRepository> can be registered in Autofac and injected into your Unit of Work.
// register your services as per Nico's answer
builder.Register...
// register a factory with Autofac
builder.Register<Func<Type, IRepository>>(x => {
var context = x.Resolve<IComponentContext>();
return y => {
return (IRepository) context.Resolve(y);
};
});
// use the factory in your Unit of Work
class UnitOfWork
{
readonly Func<Type, IRepository> _factory;
public void SomeMethod(object o)
{
var repository = _factory(o.GetType());
repository.DoSomething(o);
}
}

Taking a little inspiration from MEF , I have created a similar "Export Attribute" to achieve this in autofac.
You can create an Export attribute and use it on each implementation of IRepository as
[Export(typeof(IRepository))]
.
e.g. [Export(typeof(IRepository))]
class Repo1:IRepository
{}
At the time of registration, simply extract the type and using RegisterGeneric(), register your components.
/// <summary>
/// Export attribute to allow registering components using autofac.
/// This attribute must be used for all pluggable components that require to be discovered dynamically.
/// </summary>
[AttributeUsage(AttributeTargets.Class)]
public class ExportAttribute:Attribute
{
private Type type;
public ExportAttribute(Type type)
{
this.type = type;
}
/// <summary>
/// Provides the type (any interface) of Export
/// </summary>
public Type Type { get { return this.type; } }
}
/// <summary>
/// Registers components based on Export attribute containing their type information
/// </summary>
private void BuildContainer()
{
var allAssemblies = AssemblyInitializer.GetLoadedPlugins();
allAssemblies.ForEach(assembly =>
{
var allTypes = assembly.GetTypes().Where(a => a.GetCustomAttribute(typeof(ExportAttribute)) != null).ToList<Type>();
allTypes.ForEach(y =>
{
var classType = ((ExportAttribute)(y.GetCustomAttribute(typeof(ExportAttribute)))).Type;
if (!classType.IsInterface || !classType.IsAbstract || !classType.IsPublic) return;
if (classType.Equals(typeof(IRepository<>)))
{
builder.RegisterGeneric(y.GetTypeInfo()).Named(y.GetTypeInfo().Name, typeof(IRepository<>));
}
// Handle code for any other specific Interfaces
});
});
this.Container = builder.Build();
}

Not really sure if I am following the question correctly howevery typically IRepository points to a data repository with generic functions (insert, update, delete etc). However autofac keyed services are used to register the service with key names (or any key type). If this is the case you will have to come up with a solution that can locate all your Repo types and register them individually in a loop. This could be achieved using Reflection. However each object Repo1, Repo2 etc, will need a common derivative.
For example lets say each Repo object derrives from the interface IRepo then we can use reflection to find all instances of the IRepo interface where the type is a class then loop through each instance registering it to your container. Something like.
var iRepoType = typeof(IRepo);
var repoTypes = Assembly.GetExecutingAssembly().GetTypes()
.Where(type => type.IsClass && iRepoType.IsAssignableFrom(type))
.ToList();
foreach(var repoType in repoTypes)
{
builder.RegisterType(repoType).Keyed<IRepository>(repoType);
}
Now personally this doesn't make any sense as when you look at this keyed service you are saying when I pass in the key typeof(Repo1) I want Repo1. Therefore isn't this the same as registering each type of Repository differently without using Keyed services?
I have posted an answer in code review talking about Repository patterns and classes that may also be some interest.

Related

Dependency Injection of IEnumerable of Open Generic

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

Decorator Interception with Open Generics in StructureMap 3

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

Factory pattern without service locator

I am currently stuck at trying to write a factory class that doesn't rely on service location.
The only other alternative I can think of is to use constructor injection to inject all possible instances, but that may lead to surprises as classes are passed via reference.
It is also possibly going to be costly and messy once the number of possible providers grow.
The providers themselves are full complex classes that have their own dependencies so manual construction is out of the picture.
Updated service location example:
public class ProviderFactory : IProviderFactory
{
private readonly IProviderConfigurationService _providerConfigurationService;
public enum SearchType
{
Foo,
Bar
}
public ProviderFactory(IProviderConfigurationService providerConfigurationService)
{
_providerConfigurationService = providerConfigurationService;
}
public Collection<IProvider> GetProviderInstances(SearchType searchType)
{
// Provider configuration service will read a XML/DB store to retrieve list of search providers applicable for a search type
var providerList = _providerConfigurationService.GetProviderList(searchType);
return new Collection<IProvider>(providerList.ForEach(x=> ServiceLocator.GetInstance(typeof(x))).ToList()) ;
}
}
What are my other options? I am currently using Unity for DI.
An alternative is to pass a Func<Type, object> to the constructor and to implement the function through your container:
unity.RegisterInstance<Func<Type, object>>(t => unity.Resolve(t))
Then in your class:
public ProviderFactory(Func<Type, object> createFunc, IProviderConfigurationService pcs)
{
_createFunc = createFunc;
}
public Collection<IProvider> GetProviderInstances(SearchType searchType)
{
var providerList = _providerConfigurationService.GetProviderList(searchType);
return new Collection<IProvider>(providerList.Select(_createFunc).ToList());
}
You are missing an abstraction.
Your ProviderFactory should implement an IProviderFactory abstraction. This way you can place that interface in a base library of your application and you can place the ProviderFactory implementation inside your Composition Root. For code that lives inside your composition root, it is okay to reference the DI library, and in that case you're not using service location.
I have recently solved a very similar issue in my own code by using a DI framework. To satisfy Dependency Inversion, the factory constructor should accept an interface (as the other answers have said), but to get the framework to inject the right type is tricky without having a massive list of arguments detailing each possible concretion.
SimpleInjector allows you to register all concretions of a given abstraction with:
Container.RegisterCollection(typeof(IProvider), new [] {typeof(TKnown).Assembly,...});
Your XML could list the (possibly external) assemblies where the concretions are defined and you could build the assembly array from there. Then your factory just needs to accept them all and pick one, perhaps based on the searchType you mentioned.
public class ProviderFactory
{
private List<IProvider> providers;
public ProviderFactory(IEnumerable<IProvider> providers)
{
this.providers = providers.ToList();
}
public IProvider GetProvider(string searchType)
{
// using a switch here would open the factory to modification
// which would break OCP
var provider = providers.SingleOrDefault(concretion => concretion.GetType().Name == searchType);
if (provider == null) throw new Exception("No provider found of that type. Are you missing an assembly in the RegisterCollection for IProvider?");
return provider;
}
I know I'm way late to the party on this but assuming other folks don't see this approach as problematic, it might be useful.

Is this the right way to RegisterDecorator when some types have no implementation?

Using simple injector with the command pattern described here. Most commands have companion classes that implement fluent validation's AbstractValidator<TCommand>, which means they also implement FV IValidator<TCommand>. However it doesn't always make sense to have a validator implementation for every command.
As far as I can tell, the command decorator implementation cannot take IValidator<TCommand> as a constructor arg unless every ICommandHandler<TCommand> has a corresponding FV.IValidator<TCommand>. I tried the following:
public class FluentValidationCommandDecorator<TCommand>
: IHandleCommands<TCommand>
{
public FluentValidationCommandDecorator(IHandleCommands<TCommand> decorated
, IValidator<TCommand> validator
)
{
_decorated = decorated;
_validator = validator;
}
...
}
...
container.RegisterManyForOpenGeneric(typeof(IValidator<>), assemblies);
container.RegisterDecorator(typeof(IHandleCommands<>),
typeof(FluentValidationCommandDecorator<>),
context =>
{
var validatorType =
typeof (IValidator<>).MakeGenericType(
context.ServiceType.GetGenericArguments());
if (container.GetRegistration(validatorType) == null)
return false;
return true;
});
Unit tests that run Container.Verify() once, pass. Unit tests that run Container.Verify() more than once, fail from an InvalidOperationException on the second invocation:
The configuration is invalid. Creating the instance for type
IValidator<SomeCommandThatHasNoValidatorImplementation> failed. Object reference
not set to an instance of an object.
The following works, by taking the Container as an argument:
public class FluentValidationCommandDecorator<TCommand>
: IHandleCommands<TCommand>
{
private readonly IHandleCommands<TCommand> _decorated;
private readonly Container _container;
public FluentValidationCommandDecorator(Container container
, IHandleCommands<TCommand> decorated
)
{
_container = container;
_decorated = decorated;
}
public void Handle(TCommand command)
{
IValidator<TCommand> validator = null;
if (_container.GetRegistration(typeof(IValidator<TCommand>)) != null)
validator = _container.GetInstance<IValidator<TCommand>>();
if (validator != null) validator.ValidateAndThrow(command);
_decorated.Handle(command);
}
}
...
container.RegisterManyForOpenGeneric(typeof(IValidator<>), assemblies);
container.RegisterDecorator(typeof(IHandleCommands<>),
typeof(FluentValidationCommandDecorator<>));
If this class didn't have to take a dependency on Simple Injector, I could move it into the domain project. The domain already takes a dependency on FluentValidation.net so that domain validity can be unit tested. I think this decorator belongs in the domain, but neither it nor its unit test project takes a dependency on simpleinjector (or should have to, since the domain is not the composition root).
Is there a way to tell simpleinjector to only decorate a CommandHandler<TCommand> instance with a FluentValidationCommandDecorator<TCommand> if there is an implementation registered for IValidator<TCommand>?
What you need is unregistered type resolution, to map missing types to a default implementation. Or in other words, you need to use the RegisterOpenGeneric method:
container.RegisterOpenGeneric(typeof(IValidator<>),
typeof(NullValidator<>));
Now you need to define a NullValidator<T> that implements IValidator<T> with an empty / default implementation.
When you do this every time a certain (unregistered) IValidator<T> is requested, a new instance of NullValidator<T> will be returned. It will not override types that are registered using RegisterManyForOpenGeneric, since those types are explictly registered.
When the NullValidator<T> implementation is thread-safe (which will usually be the case with a empty implementation), you can optimize construction by registering them as singleton:
container.RegisterSingleOpenGeneric(typeof(IValidator<>),
typeof(NullValidator<>));
You can read more information in the wiki: Registration of open generic types

How to avoid Service Locator Anti-Pattern?

I'm trying to remove a Service Locator from an abstract base class, but I'm not sure what to replace it with. Here is a psuedo-example of what I've got:
public abstract class MyController : Controller
{
protected IKernel kernel;
public MyController(IKernel kernel) { this.kernel = kernel); }
protected void DoActions(Type[] types)
{
MySpecialResolver resolver = new MySpecialResolver(kernel);
foreach(var type in types)
{
IMyServiceInterface instance = resolver.Get(type);
instance.DoAction();
}
}
}
The problem with this is that the instanciator of a derived class doesn't know what bindings the kernel must have in order to keep MySpecialResolver from throwing an exception.
This might be intrinsicly intractable because I don't know from here which types I'll have to resolve. The derived classes are responsible for creating the types parameter, but they aren't hardcoded anywhere. (The types are based on the presence of attributes deep within the derived class's composition hierarchy.)
I've trying to fix this with lazy loading delegates, but so far I haven't come up with a clean solution.
Update
There are really two issues here, one is that the IoC container is passed to the controller, acting as a service locator. This is easy to remove--you can move the location up or down the call stack using all sorts of techniques.
The second issue is the difficult one, how can you ensure that the controller has the necessary services when the requirements aren't exposed until runtime. It should have been obvious from the start: you can't! You will always be dependent upon either the state of the service locator or contents of a collection. In this particular case no amount of fiddling will ever resolve the problem described in this article with staticly typed dependencies. I think that what I'm going to end up doing is passing a Lazy array into the controller constructor and throwing an exception if a required dependency is missing.
I agree with #chrisichris and #Mark Seemann.
Ditch the kernel from the controller. I'd switch your resolver composition a little bit so that your controller can remove the dependency on the IoC container and allow the resolver to be the only item that worries about the IoC container.
Then I would let the resolver get passed into the constructor of the controller. This will allow your controller to be far more testable.
For example:
public interface IMyServiceResolver
{
List<IMyServiceInterface> Resolve(Type[] types);
}
public class NinjectMyServiceResolver : IMyServiceResolver
{
private IKernal container = null;
public NinjectMyServiceResolver(IKernal container)
{
this.container = container;
}
public List<IMyServiceInterface> Resolve(Type[] types)
{
List<IMyServiceInterface> services = new List<IMyServiceInterface>();
foreach(var type in types)
{
IMyServiceInterface instance = container.Get(type);
services.Add(instance);
}
return services;
}
}
public abstract class MyController : Controller
{
private IMyServiceResolver resolver = null;
public MyController(IMyServiceResolver resolver)
{
this.resolver = resolver;
}
protected void DoActions(Type[] types)
{
var services = resolver.Resolve(types);
foreach(var service in services)
{
service.DoAction();
}
}
}
Now your controller isn't coupled to a specific IoC container. Also your controller is much more testable since you can mock the resolvers and not require an IoC container at all for your tests.
Alternatively, if you don't get to control when a controller is instantiated, you can modify it slightly:
public abstract class MyController : Controller
{
private static IMyServiceResolver resolver = null;
public static InitializeResolver(IMyServiceResolver resolver)
{
MyController.resolver = resolver;
}
public MyController()
{
// Now we support a default constructor
// since maybe someone else is instantiating this type
// that we don't control.
}
protected void DoActions(Type[] types)
{
var services = resolver.Resolve(types);
foreach(var service in services)
{
service.DoAction();
}
}
}
You would then call this at your application start up to initialize the resolver:
MyController.InitializeResolver(new NinjectMyServiceResolver(kernal));
We did this to handle elements created in XAML who require dependencies resolved but we wanted to remove Service Locator like requests.
Please excuse any syntactical errors :)
I'm writing a blog post series on the topic of refactoring an MVVM application with Service Locator calls in the view models you might find interesting. Part 2 is coming soon :)
http://kellabyte.com/2011/07/24/refactoring-to-improve-maintainability-and-blendability-using-ioc-part-1-view-models/
Maybe you should just do away the Kernel, Types and MySpecialResolver and let the subclasses call DoActions with the IMyServiceInterface instances they need as argument directly. And let the subclasses decide how they get to these instances - they should know best (or in case they don't know which exactly the one who ever decides which instances of IMyServiceInterface are needed)
I would have liked to have a bit more information before posting this answer, but Kelly put me on the spot. :) Telling me to put my code where my mouth is, so to speak.
Like I said in my comment to Kelly, I disagree with moving the resolver/locator from a static implementation to an injected implementation. I agree with ChrisChris that the dependencies the derived type needs should be resolved in that class and not delegated to the base class.
That said, here is how I would remove the service location...
Create Command Interface
First of all I would create a command interface for the specific implementation. In this case the types sent with the DoActions method are generated from attributes, so I would create an IAttributeCommand. I am adding a Matches method to the command in order to declare the command for use by certain types.
public interface IAttributeCommand
{
bool Matches(Type type);
void Execute();
}
Add Command Implementations
To implement the interface, I pass in the specific dependencies I need to execute my command (to be resolved by my container). I add a predicate to my Matches method, and define my Execute behavior.
public class MyTypeAttributeCommand : IAttributeCommand
{
MyDependency dependency;
SomeOtherDependency otherDependency;
public MyTypeAttributeCommand (MyDependency dependency, ISomeOtherDependency otherDependency)
{
this.dependency = dependency;
this.otherDependency = otherDependency
}
public bool Matches(Type type)
{
return type==typeof(MyType)
}
public void Execute()
{
// do action using dependency/dependencies
}
}
Register Commands with Container
In StructureMap (use your favorite container), I would register the array like so:
Scan(s=>
{
s.AssembliesFromApplicationBaseDirectory();
s.AddAllTypesOf<IAttributeCommand>();
s.WithDefaultConventions();
}
Select and Execute Commands Based on Type
Finally, on the base class, I define an IAttributeCommand array in my constructor arguments to be injected by the IOC container. When the derived type passes in the types array, I will execute the correct command based on the predicate.
public abstract class MyController : Controller
{
protected IAttributeCommand[] commands;
public MyController(IAttributeCommand[] commands) { this.commands = commands); }
protected void DoActions(Type[] types)
{
foreach(var type in types)
{
var command = commands.FirstOrDefault(x=>x.Matches(type));
if (command==null) continue;
command.Execute();
}
}
}
If you multiple commands can handle one type, you can change the implementation: commands.Where(x=>x.Matches(type)).ToList().ForEach(Execute);
The effect is the same, but there is a subtle difference in how the class is constructed. The class has no coupling to an IOC container and there is no service location. The implementation is more testable as the class can be constructed with its real dependencies, with no need to wire up a container/resolver.

Categories