Strategy & factory pattern for base/descendant class resolution - c#

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.

Related

How to create generic mapper like this?

I have many classes, that have similar operations of mapping objects. To keep code dry I want to create base abstract class for all these classes.
base abstract class would have generic mapping function like this:
public TEntity GetEntity(Result<TServiceClientEntity> res)
{
entity = MappingProfiles.TryMap(res.Value);
//some logic with result here
return entity;
}
Result class:
public class Result<T>
{
public T Value{ get; set; }
//some more properties..
}
But the problem is that I can't think a way of how to map generic classes like that:
public static class MappingProfiles
{
public static T2 TryMap<T,T2>(T t)
{
return (T2)Map((Real_T_type)t); //f.e.: the type is ExampleFrom
}
public static ExampleTo Map(ExampleFrom from)
{
return new ExampleTo
{
exapleValue = from.exapleValue
};
}
}
EDIT:
I also want that TryMap generic method use my predefined Map manual methods for mapping.
You can use Reflection (C#) to accomplish such things:
public static TOut Map<TIn, TOut>(TIn source)
where TOut : new()
{
var inPropDict = typeof(TIn).GetProperties()
.Where(p => p.CanRead)
.ToDictionary(p => p.Name);
var outProps = typeof(TOut).GetProperties()
.Where(p => p.CanWrite);
var destination = new TOut();
foreach (var outProp in outProps) {
if (inPropDict.TryGetValue(outProp.Name, out var inProp)) {
object sourceValue = inProp.GetValue(source);
if (inProp.PropertyType != outProp.PropertyType) {
sourceValue = Convert.ChangeType(sourceValue, outProp.PropertyType);
}
outProp.SetValue(destination, sourceValue);
}
}
return destination;
}
Reflection enables you to inspect a type and to get its properties, fields, etc.
Type.GetProperties() returns an array of PropertyInfo with name, type, and other information about a property. It also allows you to read from or to write to a property of an object.
The code above is just a quick and dirty example without exception handling. It does only a flat mapping and does not map collections or nested objects.
It also could be improved by allowing you to declare mappings for properties not having the same name etc.
There is a tool doing all these things and more called AutoMapper.
Solution with manual mapping methods
I suggest defining an interface like this
public interface IMapper<T1, T2>
{
T2 Map(T1 input);
}
Example of a concrete implementation:
public class ExampleFromToMapper : IMapper<ExampleFrom, ExampleTo>
{
public ExampleTo Map(ExampleFrom input)
{
return new ExampleTo {
ExampleValue = input.ExampleValue
};
}
}
The idea is to use dependency injection to do the job of selecting the right mapper.
You can use the NuGet package Microsoft.Extensions.DependencyInjection as an example. But many other dependency injection frameworks exist.
Write a method configuring the mappers (as extension method in this example):
public static IServiceCollection AddMappers(this IServiceCollection services)
{
return services
.AddSingleton<IMapper<ExampleFrom, ExampleTo>, ExampleFromToMapper>()
.AddSingleton<IMapper<OtherFrom, OtherTo>, OtherFromToMapper>();
}
Define the container somewhere:
public static class Config
{
public static ServiceProvider Container { get; set; }
}
And at startup of your application configure the container
var services = new ServiceCollection();
services
.AddMappers()
.AddTransient<MyForm>(); // See below
Config.Container = services.BuildServiceProvider();
As an example, let us assume that you have a WinForms app with a form defined like this (it uses a mapper directly, but instead it could use other services that do use mappers. The DI container resolves the dependencies recursively and injects them in the constructors automatically):
public partial class MyForm : Form
{
private readonly IMapper<ExampleFrom, ExampleTo> _mapper;
public MyForm(IMapper<ExampleFrom, ExampleTo> mapper)
{
_mapper = mapper;
InitializeComponent();
}
}
Now, you can start the application like this:
var frm = Config.Container.GetRequiredService<MyForm>();
Application.Run(frm);
Okay, at the beginning it looks complicated, but once you have set up the basics it becomes easy to add new services. Every class offering some functionality is considered a service.
Solution with manual static mapping methods.
To make classes easier testable (or for some others reasons), generic mapper can be static too.
Thanks to Oliver Jacot-Descombes answer I created this solution:
//This works like static class.
public class MappingProfiles
{
//Constructor needs to be private, so that class work like static class.
private MappingProfiles() { }
private static readonly MappingProfiles _instance = new MappingProfiles();
//We need instance to invoke this class methods.
public static MappingProfiles Instance { get { return _instance; } }
public static TResult? TryMap<TSource, TResult>(TSource source)
where TResult : new()
where TSource : class, new()
{
//Trying to get mapper for result.
var resultMapper = typeof(MappingProfiles).GetMethods().FirstOrDefault(m =>
m.ReturnType == typeof(TResult) &&
m.GetParameters()[0].ParameterType == typeof(TSource));
if (resultMapper is null)
throw new Exception($"Mapper not found. From: {typeof(TSource)}, to: {typeof(TResult)}");
//Makes TSource array, because Invoke method works only with arrays.
TSource[] sources = new TSource[] { source };
//Calls manual mapping method.
object res = resultMapper.Invoke(MappingProfiles.Instance, sources);
return (TResult)res;
}
public static ExampleTo Map(ExampleFrom from)
{
return new ExampleTo
{
//...
};
}
}
To call this mapper:
var mapped = MappingProfiles.TryMap<TExampleFrom, TExampleTo>(exampleFromVariable);

Mock method return value with read only property

I wish to test a method which queries a third-party library. The library returns an object with a IReadOnlyCollection property.
There is no constructor to set the value of the property and the object has no interface for me to mock.
I have used Moq to mock the interface for the service that I call, but I can't create a mocked return value as I can't set the property.
public interface IHitService {
public Hit GetHit();
}
public class Hit {
public Hit() {
}
public IReadOnlyCollection<string> Result { get; }
}
public class TestingClass {
public void MyTest() {
Hit hit = new Hit() {
// cannot set this property
Result = new List<string>() { "hello","goodbye" };
}
Mock<IHitService> service = new Mock<IHitService>();
service.Setup(c => c.GetHit).Returns(hit);
}
}
What would be the best way for me to generate the return value to test my method? Wrapping the object with a new property to hide the base does not work.
You can use unit-test frameworks that allow you to change the behavior of a concrete object, for example in this case i used Typemock Isolator to try and solve your issue, it allows you to change the the return value of the result property so can "set" for your test without changing your code or adding extra code:
public void TestMethod1()
{
List<string> s = new List<string> { "sfas", "asfsa", "blbba" };
var hit = Isolate.Fake.NextInstance<Hit>();
Isolate.WhenCalled(() => hit.Result).WillReturnCollectionValuesOf(s);
}
In this test i mocked the Hit class and modified the return value of the Result property to a list of strings i created.
If you need to test a third-party library, it would be a better idea to create your own abstraction (interface) and rely on that for both testing and real code:
public interface IHitService
{
IHit GetHit();
}
public interface IHit
{
IReadOnlyCollection<string> Result { get; }
}
In your application code, you can create a simple wrapper class that implements IHit by delegating to the concrete third-party class. Now you can test the interface by mocking it as needed.
In general, if you can't change 3rd party code, build an adapter to it and use your own abstraction :-
public interface IHit
{
IReadOnlyCollection<string> Result { get; }
}
public interface IHitService
{
IHit GetHit();
}
public class HitAdapter : IHit
{
private Hit _hit;
public HitAdapter(Hit hit)
{
_hit = hit;
}
public IReadOnlyCollection<string> Result => _hit.Result;
}
public class TestingClass
{
public void MyTest()
{
var hitMock = new Mock<IHit>();
hitMock.Setup(c => c.Result).Returns<IReadOnlyCollection<string>>(x => new List<string>() {"hello", "goodbye"});
var service = new Mock<IHitService>();
service.Setup(c => c.GetHit()).Returns<IHit>(x => hitMock.Object);
}
}

Passing argument in constructor using Simple Injector

I'm having problem in passing parameter dynamically to class constructor using simple injector.
I have following code structure.
Controller example:
public class HomeController : Controller
{
private readonly ICheckService _checkService;
public HomeController(ICheckService checkService)
{
_checkService= checkService;
}
// GET: Home
public ActionResult Index()
{
var list = _checkService.GetAll();
return View(list);
}
}
Service layer (in this layer I need to pass the two constructor parameter for CheckRepository<T> which is implementing ICheckRepository<T>. How do I achieve this using simple injector? I tried but not getting solution around. One example in order to achieve would be really grateful)
public interface ICheckService
{
List<CheckType> GetAll();
}
public class CheckService : ICheckService
{
private readonly ICheckRepository<CheckType> _checkRepository;
public CheckService(ICheckRepository<CheckType> checkRepository)
{
_checkRepository= checkRepository;
}
public List<T> GetAll()
{
return _checkRepository.GetAll().ToList();
}
}
Repository Layer:
public abstract class RepositoryBase<T> where T : class
{
public string Types { get; set; }
public string Segment { get; set; }
public RepositoryBase(string type)
{
Types = type;
}
public RepositoryBase(string type, string segment)
{
Types = type;
Segment = segment;
}
}
public interface ICheckRepository<T> where T : class
{
IEnumerable<T> GetAll();
}
public class CheckRepository<T> : RepositoryBase<T>, ICheckRepository<T> where T : class
{
public CheckRepository(string types, string segment)
: base(types, segment)
{
}
public IEnumerable<T> GetAll()
{
var list = new List<T>();
using (DbAccess dbAccess = new DbAccess(ConnectionString, DatabaseType.SqlServer))
{
return dbAccess.ExecuteReader<T>(StoredProc, CommandType.StoredProcedure).ToList();
}
}
}
My Simple Injector initializer class:
public static void InitializeInjector()
{
var container = new Container();
InitializeContainer(container);
container.RegisterMvcControllers(Assembly.GetExecutingAssembly());
container.RegisterMvcIntegratedFilterProvider();
container.Verify();
DependencyResolver.SetResolver(new SimpleInjectorDependencyResolver(container));
}
private static void InitializeContainer(Container container)
{
container.Register(typeof(IFilterRepository<>), typeof(FilterRepository<>));
//Here is where I am struggling to bind dynamic constructor parameter registering
}
Does anyone have any solution for the above code?
Thanks again.
In case the parameters are fixed to the specific closed-generic types, you should make the registrations as follows:
c.Register<ICheckRepo<Customer>>(() => new CheckRepository<Customer>(constr, "cust_sp"));
c.Register<ICheckRepo<Order>>(() => new CheckRepository<Order>(constr, "order_sp"));
c.Register<ICheckRepo<Product>>(() => new CheckRepository<Product>(constr, "prod_sp"));
// more registrations here
In case your repository mixes dependencies with configuration values, you can also use contextual registration mixed with the registration of the open-generic type:
// Registrations
// One registration for the open generic type
c.Register(typeof(ICheckRepository<>), typeof(CheckRepository<>));
// One registration for the connection string (assuming you only have one)
container.RegisterConditional(typeof(string), CreateStringConstant(constr),
c => c.Consumer.Target.Name == "connectionString");
// Conditional registrations for each closed ICheckRepository<T>
RegisterStoredProcForCheckRepository<Customer>("cuts_sp");
RegisterStoredProcForCheckRepository<Order>("order_sp");
RegisterStoredProcForCheckRepository<Product>("prod_sp");
// more registrations here
// Helper methods
Registration CreateStringConstant(string value) =>
Lifestyle.Singleton.CreateRegistration(typeof(string), () => value, container);
void RegisterStoredProcForCheckRepository<TEntity>(string spName) {
container.RegisterConditional(typeof(string), CreateStringConstant(container, spName),
c => c.Consumer.Target.Name == "segment"
&& c.Contumer.ImplementationType == typeof(CheckRepository<TEntity>));
}
In case the connection string or stored procedure varies per request, you should change the design, as explained here.

Shim and Generic Methods

I want to create a Shim for an Generic Method. But I have a bit a trouble with the Generic in that case.
Here is my example:
class BaseRepository <T> where T: Entity
{
public T[] FindAll()
{
return Method<T>.FindAll()
}
}
class ClassA : base<A>
{
}
class A : Entity
{
}
class ClassB : base<B>
{
}
class B : Entity
{
}
now I want to create a ShimMethod for ClassA and ClassB
ShimBaseRepository<A>.AllInstances.FindAll = (repo) => MethodA();
ShimBaseRepository<B>.AllInstances.FindAll = (repo) => MethodB();
public A MethodA()
{
//Make the Same as MethodB
}
public B MethodB()
{
//Make the Same as MethodA
}
But what if I have mor than 20 "Base" classes? I don't want to create a Delegate/method for every baseClass. I tried something like this:
List<Type> allEntityClasses = (from x in Assembly.GetAssembly(typeof(Entity)).GetTypes()
where !x.IsAbstract && !x.IsInterface
select x).ToList();
foreach(Type type in allEntityClasses=
{
ShimBaseRepository<type????>.AllInstances.FindAll = (repo) => Method();
}
public Entity????? Method()
{
}
In my Unittest I will use the following methods:
ClassA.FindAll()
ClassB.FindAll()
and not:
Base.FindAll()
Edit:
I use Microsoft Fakes,so I can't Change anything in the ShimClass. Here is the generated sourcecode from Shim.
public class ShimBaseRepository<T> : ShimBase<BaseRepository<T>> where T : Entity
{
public static class AllInstances
{
public static FakesDelegates.Func<BaseRepository<T>, T[]> FindAll { [ShimMethod("FindAll", 20)] set; }
}
}
My intention is, that I don't want to create a delegate for every entity, I just want to iterate through all my EntityClasses and create the delegate dynamically. But I have no Idea how I add my Type object in the
ShimBase<T>
Okay, let's discuss this a little.
First of all, here is a straight-forward solution with virtual method:
public class Base<T> where T : Entity
{
public virtual T[] FindAll()
{
return null;
}
}
Then just override FindAll in concrete classes
Or, if you can, make Base abstract and InnerFindAll abstract too.
But, if you need to specify delegate in runtime (as i can see you have a specific Helper for it, but i can't get, why you invoke helper in Base and then you have some undefined in question AllInstances with a Func) this approach won't help. You'll need to implement Strategy pattern with some default strategy assigned in Base. Then you'll have 3 ways to "resolve" strategies in concrete classes:
Hardcode a strategy in constructor of concrete class
Inject strategy to concrete class constructor via DI container
Implement some kind of Mapper which'll return you appropriate Strategy for EntityType (T)
Also, i think you have some troubles with design. I don't see any reason you need to implement FindAll as a lambda injected to a static property of type Func<T> (yep, i think you can replace AllInstances.FindAll with just a static FindAll). So if i were you, i'd use abstract method..
EDIT
Now i got your problem and can give you only a rather ugly solution via reflection... I hoghly don't recomend you to use this since it's really rigour
public class Program
{
static void Main(string[] args)
{
List<Type> allEntityClasses = (from x in Assembly.GetAssembly(typeof(Entity))
.GetTypes().Where(t=>typeof(Entity).IsAssignableFrom(t))
where !x.IsAbstract && !x.IsInterface
select x).ToList();
foreach (var type in allEntityClasses)
{
var genericType = typeof(BaseGeneric<>).MakeGenericType(type);
var helper = new DelegateHelper();
var myLambda = helper.GetLambdaForType(type);
var allInst = genericType.GetProperty("AllInstances").GetValue(null);
if (allInst == null)
{
allInst = Activator.CreateInstance(genericType.GetProperty("AllInstances").PropertyType);
}
allInst.GetType().GetProperty("FindAll").SetValue(allInst,myLambda);
}
}
}
public static class BaseGeneric<T>
{
public static AllInstances<T> AllInstances { get; set; }
}
public class AllInstances<T>
{
public Func<T[]> FindAll { get; set; }
}
public class DelegateHelper
{
public Delegate GetLambdaForType(Type type)
{
var funcType = typeof(Func<>).MakeGenericType(type.MakeArrayType());
var methodInfo = typeof(DelegateHelper).GetMethods().FirstOrDefault(t => t.Name == "FunctionMethod")
.MakeGenericMethod(type);
var #delegate = methodInfo.CreateDelegate(funcType, this);
return #delegate;
}
public T[] FunctionMethod<T>()
{
return new T[10];
}
}
public class Entity
{
}
public class EntityFirst
{
}
public class EntitySecond
{
}

How to use "Composite Design Pattern" with Ninject

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.

Categories