Validation Rule Contract:
public interface IValidationRule
{
bool IsValid();
}
Concrete Validation Rule:
public class MyClass : IValidationRule
{
public bool IsValid()
{
return true;
}
}
Composite:
public class ValidationRuleComposite : IValidationRule
{
private readonly IEnumerable<IValidationRule> _validationRules;
public ValidationRuleComposite(IEnumerable<IValidationRule> validationRules)
{
_validationRules = validationRules;
}
public bool IsValid()
{
return _validationRules.All(x => x.IsValid());
}
}
When I ask the containter for IValidationRule I want to get ValidationRuleComposite. If I ask the container for a list of IValidationRule I want to get all implementations of IValidationRule except of the ValidationRuleComposite.
How can I achieve this with Ninject?
First you want to set up the bindings for the IEnumerable<IValidationRule> that will be injected into the composite. You can just bind them individually:
// Bind all the individual rules for injection into the composite
kernel.Bind<IValidationRule>().To<MyClass>().WhenInjectedInto<ValidationRuleComposite>();
kernel.Bind<IValidationRule>().To<RuleTwo>().WhenInjectedInto<ValidationRuleComposite>();
Or you can also setup the IEnumerable fairly easy with the convention binding extensions, so that you don't have to add a separate binding for each individual concrete rule. Just be sure to add the Exlcuding clause for the composite class like so:
using Ninject.Extensions.Conventions;
// Bind all the non-composite IValidationRules for injection into ValidationRuleComposite
kernel.Bind(x => x.FromAssemblyContaining(typeof(ValidationRuleComposite))
.SelectAllClasses()
.InheritedFrom<IValidationRule>()
.Excluding<ValidationRuleComposite>()
.BindAllInterfaces()
.Configure(c => c.WhenInjectedInto<ValidationRuleComposite>()));
In my example the composite and the rest of the concretes are in the same assembly, but obviously you can vary your convention binding if they're somewhere else.
Finally, we need to set up the binding so that everywhere else an IValidationRule is request, Ninject provides the composite. There doesn't seem to be an elegant method existing for this, so I wrote my own When clause to avoid the cyclical injection:
// Now bind the composite to the interface for everywhere except itself
kernel.Bind<IValidationRule>().To<ValidationRuleComposite>()
.When(x => x.Target == null
|| x.Target.Member.ReflectedType != typeof(ValidationRuleComposite));
With the help of Soldarnal I came to the following solution:
public static class KernelExtensions
{
public static void BindComposite<TComposite, TCompositeElement>(this StandardKernel container) where TComposite : TCompositeElement
{
container.Bind(x => x.FromAssemblyContaining(typeof(TComposite))
.SelectAllClasses()
.InheritedFrom<TCompositeElement>()
.Excluding<TComposite>()
.BindAllInterfaces()
.Configure(c => c.WhenInjectedInto<TComposite>()));
container.Bind<TCompositeElement>().To<TComposite>()
.When(IsNotCompositeTarget<TComposite>);
}
private static bool IsNotCompositeTarget<TComposite>(IRequest x)
{
if (x.Target == null)
return true;
return x.Target.Member.ReflectedType != typeof(TComposite);
}
}
Usage:
var container = new StandardKernel();
container.BindComposite<ValidationRuleComposite, IValidationRule>();
Here I'm assuming that you want all the validation rules and not a partial list of them, as per the more generic pattern.
I would slightly change the Composition class so that you can do a
kernel.Get<IValidationRuleComposite>()
and a
kernel.GetAll<IValidationRule>()
A simple example follows.
The interfaces
public interface IValidationRule
{
bool IsValid();
}
public interface IValidationRuleComposite : IValidationRule
{
void ValidationRuleCompose(List<IValidationRule> validationRules);
}
and the rules
public class MyClass1 : IValidationRule
{
public bool IsValid()
{
Debug.WriteLine("Valid 1");
return true;
}
}
public class MyClass2 : IValidationRule
{
public bool IsValid()
{
Debug.WriteLine("Valid 2");
return false;
}
}
The composite rule
public class ValidationRuleComposite : IValidationRuleComposite
{
private List<IValidationRule> _validationRules;
public void ValidationRuleCompose(List<IValidationRule> validationRules)
{
_validationRules = _validationRules.Union(validationRules).ToList();
}
public ValidationRuleComposite()
{
_validationRules = new List<IValidationRule>();
}
public bool IsValid()
{
Debug.WriteLine("Composite Valid");
return _validationRules.All(x => x.IsValid());
}
}
and a main
StandardKernel kernel = new StandardKernel();
kernel.Bind<IValidationRule>().To<MyClass1>();
kernel.Bind<IValidationRule>().To<MyClass2>();
kernel.Bind<IValidationRuleComposite>().To<ValidationRuleComposite>();
IValidationRuleComposite try1 = kernel.Get<IValidationRuleComposite>();
IEnumerable<IValidationRule> rules = kernel.GetAll<IValidationRule>();
foreach(IValidationRule trycomp in rules)
{ Debug.WriteLine("trycomp: " + trycomp.GetType().ToString()); trycomp.IsValid(); };
try1.ValidationRuleCompose(rules.ToList());
Console.WriteLine("{0}",try1.IsValid());
Debug.WriteLine("try1: " + try1.GetType().ToString());
EDIT
Equivalent alternative, preserving your composite constructor
public interface IValidationRuleCompositeConstr : IValidationRule
{
}
public class ValidationRuleCompositeOriginal : IValidationRuleCompositeConstr
{
private readonly IEnumerable<IValidationRule> _validationRules;
public ValidationRuleCompositeOriginal(IEnumerable<IValidationRule> validationRules)
{
_validationRules = validationRules;
}
public bool IsValid()
{
return _validationRules.All(x => x.IsValid());
}
}
with corresponding usage:
StandardKernel kernel = new StandardKernel();
kernel.Bind<IValidationRule>().To<MyClass1>();
kernel.Bind<IValidationRule>().To<MyClass2>();
kernel.Bind<IValidationRuleCompositeConstr>().To<ValidationRuleCompositeOriginal>();
IEnumerable<IValidationRule> rules = kernel.GetAll<IValidationRule>();
Ninject.Parameters.ConstructorArgument therules = new Ninject.Parameters.ConstructorArgument("therules", rules);
IValidationRuleCompositeConstr try2 = kernel.Get<IValidationRuleCompositeConstr>(therules);
Debug.WriteLine("Second Class");
Debug.WriteLine (string.Format("{0}",try2.IsValid()));
I don't know how you could do that directly with Ninject, but you could use Ninject to create a class which then creates your validation rules.
public class ValidationRuleFactory : IValidationRuleFactory
{
public IValidationRule CreateComposite()
{
var rules = CreateRules();
return new ValidationRuleComposite(rules);
}
private IEnumerable<IValidationRule> CreateRules()
{
//return all other rules here.
//I would hard code them and add new ones here as they are created.
//If you don't want to do that you could use reflection.
}
}
as this class doesn't hold any state you can then create it with singleton scope.
kernel.Bind<IValidationRuleFactory>().To<ValidationRuleFactory>().InSingletonScope();
Then you inject this class and use it to create your composite
public class MyClass()
{
private readonly IValidationRuleFactory _validationRuleFactory;
public MyClass(IValidationRuleFactory validationRuleFactory)
{
_validationRuleFactory = validationRuleFactory;
}
public bool CheckValid()
{
var composite = _validationRuleFactory.CreateComposite();
return composite.IsValid();
}
}
You wire up your concrete instances of ValidationRule in Ninject, like this.
this.Kernel.Bind<ValidationRule1>().ToSelf();
this.Kernel.Bind<ValidationRule2>().ToSelf();
this.Kernel.Bind<IValidationRule>().To<ValidationRuleComposite>()
.WithConstructorArgument("validationRules",
new IValidationRule[] {
this.Kernel.Get<ValidationRule1>(),
this.Kernel.Get<ValidationRule2>()
});
Now, whenever you have a service that takes an IValidationRule in its constructor, you will get the ValidationRuleComposite concrete type with both ValidationRule1 and ValidationRule2 injected.
As far as I know, Ninject doesn't play nice when it comes to injecting multiple instances of the same type. In this case, we avoid doing that so resolving IValidationRule always results in the composite type.
However, you could build your own scanning convention using Reflection that automatically finds all of the types, excludes any that have the suffix "Composite" in the name, then loops through the types to first bind them to self and then create an array of instances to inject. Have a look at this example of a custom scanning implementation, and its usage.
Related
I'm refactoring a codebase and stumbled upon a factory class that created objects based on the subtype passed into the method.
The class basically has one public method with one parameter of which it is a descendant from a base class. Within this method is a switch statement that determines which subtype is passed and conditionally calls different methods to produce the result.
I'm trying to tidy up a bit and figured a strategy pattern might suit the requirements since the code violates the open-closed principle.
Since Autofac is being used, I figured that the transition would be straight forward, however I've hit a bump in the road.
The problem isn't related to Autofac, but rather to the choice of design.
The following code illustrates the class composition, but it is lacking.
public abstract class Parent { }
public class ChildA : Parent { }
public class ChildB : Parent { }
public interface IChildStrategy<T> where T:Parent
{
IEnumerable<object> CreateObjects(Parent child);
}
public class ChildAStrategy : IChildStrategy<ChildA>
{
private IEnumerable<object> CreateObjects(ChildA child)
{
yield return "child A";
}
public IEnumerable<object> CreateObjects(Parent child) =>
CreateObjects(child as ChildA);
}
public class ChildBStrategy : IChildStrategy<ChildB>
{
private IEnumerable<object> CreateObjects(ChildB child)
{
yield return "child b";
yield return "child b's pet";
}
public IEnumerable<object> CreateObjects(Parent child) =>
CreateObjects(child as ChildB);
}
[TestMethod]
public void TestStrategyPattern()
{
var container = builder.Build();
Parent child = new ChildA();
var type = child.GetType();
var strategy = container.Resolve(typeof(IChildStrategy<>)
.MakeGenericType(type));
// strategy.CreateObjects(child);
// Assert.AreEqual("child A", fromDict);
var dict = new Dictionary<Type, Func<Parent, IEnumerable<object>>>();
dict.Add(typeof(ChildA), x => new ChildAStrategy().CreateObjects(x));
dict.Add(typeof(ChildB), x => new ChildBStrategy().CreateObjects(x));
var fromDict = dict[type](child);
Assert.AreEqual("child A", fromDict);
}
I've tried both registering the interface with the generic type itself, like so:
public interface IChildStrategy<T> where T:Parent
{
IEnumerable<object> CreateObjects(T child);
}
But it doesn't really change the difficulties.
Are there any good alternatives to a design pattern for sub-classes?
Updated
Here's what I ended up with. The changes are basically removing the parameter from the CreateObjects method and rather inject it into the constructor as a dependency and registering the strategies as Keyed<T> registrations.
public abstract class Parent { }
public class ChildA : Parent { }
public class ChildB : Parent { }
public interface IChildStrategy
{
IEnumerable<object> CreateObjects();
}
public class ChildAStrategy : IChildStrategy
{
private readonly ChildA childA;
public ChildAStrategy(ChildA childA)
{
this.childA = childA;
}
public IEnumerable<object> CreateObjects()
{
yield return childA;
}
}
public class ChildBStrategy : IChildStrategy
{
private readonly ChildB childB;
public ChildBStrategy(ChildB childB)
{
this.childB = childB;
}
public IEnumerable<object> CreateObjects()
{
yield return childB;
yield return "child b's pet";
}
}
[TestMethod]
public void TestStrategyPattern()
{
var builder = new ContainerBuilder();
builder.RegisterType<ChildAStrategy>().Keyed<IChildStrategy>(typeof(ChildA));
builder.RegisterType<ChildBStrategy>().Keyed<IChildStrategy>(typeof(ChildB));
var container = builder.Build();
IChildStrategy resolve(Parent x) => container.ResolveKeyed<IChildStrategy>(x.GetType(), new TypedParameter(x.GetType(), x));
Parent root;
IChildStrategy strategy;
root = new ChildA();
strategy = resolve(root);
Assert.IsInstanceOfType(strategy, typeof(ChildAStrategy));
Assert.AreSame(root, strategy.CreateObjects().Single());
root = new ChildB();
strategy = resolve(root);
Assert.IsInstanceOfType(strategy, typeof(ChildBStrategy));
Assert.AreSame(root, strategy.CreateObjects().First());
Assert.AreEqual("child b's pet", strategy.CreateObjects().Last());
}
Updated Answer
Original answer is included, below
I think the pattern you're looking for is a Mediator.
Here's an example implementation that fits your needs, as I understand them. This implementation strengthens the typing of the handlers, but makes even heavier use of dynamic in the mediator itself. If performance is a concern, you might want to run some tests--this implementation will probably be slower than your existing code (see: How does having a dynamic variable affect performance?)
using System.Collections.Generic;
using System.Linq;
using Autofac;
using Microsoft.VisualStudio.TestTools.UnitTesting;
namespace _54542354.MediatorExample
{
/**
* Example Input/Output types
**/
abstract class ActionBase { }
class ExampleAction : ActionBase { public string Name { get; set; } }
class ReturnType { public string Id { get; set; } }
/**
* Interfaces
**/
interface IActionHandler<TAction> where TAction : ActionBase
{
IEnumerable<ReturnType> Handle(TAction action);
}
interface IActionHandlerMediator
{
IEnumerable<ReturnType> Handle(ActionBase action);
}
/**
* Example implementations
**/
class ExampleHandler : IActionHandler<ExampleAction>
{
public IEnumerable<ReturnType> Handle(ExampleAction action)
{
yield return new ReturnType{ Id = $"{action.Name}_First" };
yield return new ReturnType{ Id = $"{action.Name}_Second" };
}
}
class ActionHandlerMediator : IActionHandlerMediator
{
readonly ILifetimeScope container;
public ActionHandlerMediator(ILifetimeScope container)
=> this.container = container;
public IEnumerable<ReturnType> Handle(ActionBase action)
{
// TODO: Error handling. What if no strategy is registered for the provided type?
dynamic handler = container.Resolve(typeof(IActionHandler<>)
.MakeGenericType(action.GetType()));
return (IEnumerable<ReturnType>)handler.Handle((dynamic)action);
}
}
/**
* Usage example
**/
[TestClass]
public class Tests
{
[TestMethod]
public void TestMediator()
{
var builder = new ContainerBuilder();
builder.RegisterType<ExampleHandler>().As<IActionHandler<ExampleAction>>();
builder.RegisterType<ActionHandlerMediator>().As<IActionHandlerMediator>();
var container = builder.Build();
var handler = container.Resolve<IActionHandlerMediator>();
var result = handler.Handle(new ExampleAction() { Name = "MyName" });
Assert.AreEqual("MyName_First", result.First().Id);
Assert.AreEqual("MyName_Second", result.Last().Id);
}
}
}
Original Answer
I took a stab at running your sample code. I had to tweak some things out of the box, but I think it actually worked as you want it to (after my tweaks).
Here's what I ended up with:
[TestMethod]
public void TestStrategyPattern_Dict()
{
// Define the available strategies
var dict = new Dictionary<Type, Func<Parent, IEnumerable<object>>>();
dict.Add(typeof(ChildA), x => new ChildAStrategy().CreateObjects(x));
dict.Add(typeof(ChildB), x => new ChildBStrategy().CreateObjects(x));
// Create the input object
Parent child = new ChildA();
// Invoke the strategy
IEnumerable<object> enumerable = dict[child.GetType()](child);
// Verify the results
Assert.AreEqual("child A", enumerable.Single());
}
[TestMethod]
public void TestStrategyPattern_AutoFac()
{
// Define the available strategies
var builder = new ContainerBuilder();
builder.RegisterType<ChildAStrategy>().As<IChildStrategy<ChildA>>();
builder.RegisterType<ChildBStrategy>().As<IChildStrategy<ChildB>>();
var container = builder.Build();
// Create the input object
Parent child = new ChildA();
// Resolve the strategy
// Because we don't know exactly what type the container will return,
// we need to use `dynamic`
dynamic strategy = container.Resolve(typeof(IChildStrategy<>)
.MakeGenericType(child.GetType()));
// Invoke the strategy
IEnumerable<object> enumerable = strategy.CreateObjects(child);
// Verify the results
Assert.AreEqual("child A", enumerable.Single());
}
These tests both pass. I did not change any code outside of the tests.
The two main changes I introduced are:
Use of .Single() before asserting. This is necessary because the strategy returns an IEnumerable, but the assertion is expecting the first object from that enumerable.
Use of the dynamic type when resolving the strategy from AutoFac. This is necessary because the compiler can't tell what type AutoFac will return. In the original code, the returned type was object, which doesn't have a CreateObjects(Parent) method. dynamic lets us call any method we want--the compiler will just assume it exists. We'll get a runtime exception if the method doesn't exist, but because we know we just created an IChildStrategy<>, we can be confident that the method will exist.
I have generic factory
public interface IViewModelFactory<T> where T : IViewModel
{
T Create<TU>(TU par);
}
public class ViewModelFactory<T> : IViewModelFactory<T> where T : IViewModel
{
private readonly ILifetimeScope _scope;
public ViewModelFactory(ILifetimeScope scope)
{
_scope = scope;
}
public T Create<TU>(TU par)
{
return _scope.Resolve<T>(new TypedParameter(typeof(TU), par));
}
}
which I can use for resolving viewmodel factory in my window class:
public WRPersons(IViewModelFactory<MRPersons> viewModelFactory)
{
var viewModel = viewModelFactory.Create(new MRPersonsUseCaseParams { Filter = 2 });
...
}
ViewModel is implemented by following code
public class MRPersons : IViewModel
{
public MRPersons(MRPersonsUseCaseParams par)
{
_filter = par.Filter;
}
}
public class MRPersonsUseCaseParams
{
public int Filter { get; set; }
}
Registration in my composition root looks like:
var builder = new ContainerBuilder();
builder.RegisterType<ViewModelFactory<MRPersons>>().As<IViewModelFactory<MRPersons>>();
builder.RegisterType<MRPersons>();
As you can see for each new ViewModel (now its only MRPerson) I will need to create two entries into my composition root. Thus for MRCar it will be:
builder.RegisterType<ViewModelFactory<MRCar>>().As<IViewModelFactory<MRCar>>();
builder.RegisterType<MRCar>();
I would like to automatize these registration somehow. I experimented with RegisterAssemblyTypes/AsClosedTypesOf but without success. Can somebody help me?
EDIT:
Based on answer codeline
builder.RegisterType<ViewModelFactory<MRPersons>>().As<IViewModelFactory<MRPersons>>();
is replaced by
builder.RegisterGeneric(typeof(ViewModelFactory<>)).As(typeof(IViewModelFactory<>));
Full automatic registration looks like:
builder.RegisterAssemblyTypes(Assembly.GetEntryAssembly()).Where(x => iViewModelType.IsAssignableFrom(x) && x.IsClass).AsSelf();
builder.RegisterGeneric(typeof(ViewModelFactory<>)).As(typeof(IViewModelFactory<>));
For better testable solution it would be fine to even replace MRPersons by IMRPersons:
public class MRPersons : IViewModel, IMRPersons
{
public MRPersons(MRPersonsUseCaseParams par)
{
_filter = par.Filter;
}
}
public class MRPersonsUseCaseParams
{
public int Filter { get; set; }
}
public interface IMRPersons
{
}
Thus registration in composition root would looks like (NEED TO BE CORRECTED)
builder.RegisterAssemblyTypes(Assembly.GetEntryAssembly()).Where(x => iViewModelType.IsAssignableFrom(x) && x.IsClass).As<??????>.AsSelf();
This would allows me to pass factory into constructor in following way:
public WRPersons(IViewModelFactory<IMRPersons> viewModelFactory)
{
var viewModel = viewModelFactory.Create(new MRPersonsUseCaseParams { Filter = 2 });
...
}
EDIT2:
During chat with Cyril Durand he provided solution for ViewModelFactory without reference to ILifetimeScope. Here is a code:
public interface IViewModelFactory2<T, TU> where T : IViewModel
{
T Create(TU par);
}
public class ViewModelFactory2<T, TU> : IViewModelFactory2<T, TU> where T : IViewModel
{
private readonly Func<TU, T> _factory;
public ViewModelFactory2(Func<TU, T> factory)
{
_factory = factory;
}
public T Create(TU par)
{
return _factory(par);
}
}
My original factory is Ok too since it is presented in composition root where strong references to DI container can be used.
You want to register ViewModelFactory<> as IViewModelFactory<>, you can do it using the RegisterGeneric method.
builder.RegisterGeneric(typeof(ViewModelFactory<>)).As(typeof(IViewModelFactory<>));
Then you will be able to resolve IViewModelFactory<MRCar> without any other registration.
See Registration Concepts - Open Generic Components for more information
For the second part of the question :
For better testable solution it would be fine to even replace MRPersons by IMRPersons
It is not so easy because there is no way to know which interface to use. You can use the AsImplementedInterfaces which will be equivalent to As<IMRPersons>().As<IViewModel>() but it may be a problem if you have a lot of implemented interface.
builder.RegisterAssemblyTypes(Assembly.GetEntryAssembly())
.Where(x => iViewModelType.IsAssignableFrom(x) && x.IsClass)
.AsImplementedInterfaces();
Or you can use a convention that will register all X asIX but I'm not a big fan of this kind of registration.
builder.RegisterAssemblyTypes(Assembly.GetExecutingAssembly())
.Where(x => iViewModelType.IsAssignableFrom(x) && x.IsClass)
.As(t => t.GetInterfaces().Where(i => i.Name.EndsWith(t.Name)));
By the way, after chatting, we figured out that you don't need a IViewModelFactory<> at all but you only need a dependency on Func<TParam, T>
I am trying to selectively use interception on types using Ninject. If an implementation implements a specific interface I want to intercept it. How can I check a Ninject Activation Context to see if its target implements an interface?
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
var kernal = new StandardKernel();
kernal.Bind<IFoo>().To<Foo>();
kernal.Intercept(x =>
{
if (x is an IGetIntercepted)
{
return true;
}
return false;
});
}
public interface IGetIntercepted
{ }
public interface IFoo
{ }
public class Foo : IFoo, IGetIntercepted
{ }
}
Note in this example I want to check Foo, not IFoo. (IFoo is easily found in the Ninject.Activation.Binding.Service property)
I was overlooking the Plan property, this seems to work:
if (x.Plan.Type.GetInterface(typeof(IGetIntercepted).FullName) != null)
{
return true;
}
I have an MVC4 controller like:
public MyThingyController
{
IThingy thingy1;
IThingy thingy2;
public MyClass(IThingy thingy1, IThingy thingy2) {
this.thingy1 = thingy1;
this.thingy2 = thingy2;
}
}
IThingy has two different concrete implementations which I'd like to slowly move between
With ninject I'd use a contextual binding
But my google foo is totally failing me in a search to find the equivalent with StructreMap
and So I want to set up StructureMap something like:
public class IocConfig
{
public static IContainer GetCommonServiceLocator()
{
ObjectFactory.Initialize(x =>
{
x.For<IThingy>()
.Use<LegacyThingy>();
x.For<IThingy>()
.Use<ShinyNewThingy>();
});
return ObjectFactory.Container;
}
}
This should do the job:
x.For<MyThingyController>()
// or better interface
// x.For<IMyThingyController>()
.Use<MyThingyController>()
.Ctor<IThingy>("thingy1")
.Is<LegacyThingy>()
.Ctor<IThingy>("thingy2")
.Is<ShinyNewThingy>();
Can Castle Windsor resolve a collection filtered by a string parameter?
interface IViewFactory
{
IView[] GetAllViewsInRegion(string regionName);
}
My application defines regions as groups of IView-derived types. When I display a particular region at runtime, I want to resolve an instance of every IView type within it (a la Prism).
I've tried doing it with the Castle's Typed Factory Facility, ComponentModel Construction Contributors, and Handler Selectors, but I can't figure out how to map multiple types to a string in a way that Castle can access, nor how to extend Castle to check the string when it decides which types to try to resolve and return in the container.
Is selection by string strictly necessary? Would it be possible to instead have all IView implementations in the same "region" implement a dedicated interface that derives from IView? Then you could use WindsorContainer.ResolveAll() (passing your region-specific IView as T) to resolve the implementations for the region in question (or you could use one of the Collection Resolvers to perform constructor injection).
In general, when trying to do things like this with Windsor, I make every effort to use the type system (and Windsor's support thereof) before resorting to string-based solutions.
Update: since we confirmed that selection by string is necessary in this case, the best solution I see is to simply inspect the list of handlers in the kernel that satisfy the IView service, then filter for the implementers where the region (defined via attribute) matches what we want, then resolve those implementers. This feels a bit hackish, but if you're okay with having a direct reference to the container in your IViewFactory implementation, this appears to work fine. Below is a passing test case demonstrating the solution.
[Test]
public void Test()
{
using (var factory = new ViewFactory())
{
var regionOneViews = factory.GetAllViewsInRegion("One");
Assert.That(regionOneViews, Is.Not.Null);
Assert.That(regionOneViews, Has.Length.EqualTo(2));
Assert.That(regionOneViews, Has.Some.TypeOf<RegionOneA>());
Assert.That(regionOneViews, Has.Some.TypeOf<RegionOneB>());
var regionTwoViews = factory.GetAllViewsInRegion("Two");
Assert.That(regionTwoViews, Is.Not.Null);
Assert.That(regionTwoViews, Has.Length.EqualTo(1));
Assert.That(regionTwoViews, Has.Some.TypeOf<RegionTwoA>());
}
}
}
public interface IViewFactory
{
IView[] GetAllViewsInRegion(string regionName);
}
public class ViewFactory : IViewFactory, IDisposable
{
private readonly WindsorContainer _container;
public ViewFactory()
{
_container = new WindsorContainer();
_container.Register(
Component.For<IView>().ImplementedBy<RegionOneA>(),
Component.For<IView>().ImplementedBy<RegionOneB>(),
Component.For<IView>().ImplementedBy<RegionTwoA>()
);
}
public IView[] GetAllViewsInRegion(string regionName)
{
return _container.Kernel.GetHandlers(typeof (IView))
.Where(h => IsInRegion(h.ComponentModel.Implementation, regionName))
.Select(h => _container.Kernel.Resolve(h.ComponentModel.Name, typeof (IView)) as IView)
.ToArray();
}
private bool IsInRegion(Type implementation,
string regionName)
{
var attr =
implementation.GetCustomAttributes(typeof (RegionAttribute), false).SingleOrDefault() as RegionAttribute;
return attr != null && attr.Name == regionName;
}
public void Dispose()
{
_container.Dispose();
}
}
public interface IView {}
[Region("One")]
public class RegionOneA : IView {}
[Region("One")]
public class RegionOneB : IView {}
[Region("Two")]
public class RegionTwoA : IView {}
[AttributeUsage(AttributeTargets.Class, AllowMultiple = false)]
public class RegionAttribute : Attribute
{
private readonly string _name;
public RegionAttribute(string name)
{
_name = name;
}
public string Name
{
get { return _name; }
}
}