I'm messing around with Ninject and MVC and design partterns. In my simple application I have a structure like this:
(the abstract classes)
- interface ICoffee
- abstract class Coffee: ICoffee
(couple of classes)
- public class Espresso : Coffee, ICoffee
- public class Cappuccino: Coffee, ICoffee
- public class Late: Coffee, ICoffee
(couple of decorator classes)
- public class Milk : ICoffee
- public class Chocolate: ICoffee
The decorator classes accept a parameter of type ICoffee , change some settings and then return it.
Then I have the following classes:
public abstract class CoffeeStore : ICoffeeStore
{
private readonly IProcessedOrderFactory processedOrderFactory;
private readonly IDictionary<string, Func<ICoffee, ICoffee>> condimentsStrategies;
public CoffeeStore(
IProcessedOrderFactory processedOrderFactory,
IDictionary<string, Func<ICoffee, ICoffee>> condimentsStrategies)
{
if (condimentsStrategies == null)
{
throw new ArgumentNullException(nameof(condimentsStrategies));
}
if (processedOrderFactory == null)
{
throw new ArgumentNullException(nameof(processedOrderFactory));
}
this.processedOrderFactory = processedOrderFactory;
this.condimentsStrategies = condimentsStrategies;
}
public IProcessedOrder ProcessOrder(IOrder order)
{
ICoffee coffee;
var coffeeType = order.SelectedCoffeeType;
CoffeSizeType coffeeSize;
Enum.TryParse(order.SelectedCoffeeSize, out coffeeSize);
coffee = this.CreateCoffee(coffeeType, coffeeSize);
foreach (var condimentAsString in order.SelectedCoffeeCodimentsList)
{
if (!this.condimentsStrategies.ContainsKey(condimentAsString))
{
throw new ArgumentException(condimentAsString);
}
//error occurs on the following line:
coffee = this.condimentsStrategies[condimentAsString](coffee);
}
var processedOrder = this.processedOrderFactory.CreateOrder(coffee);
return processedOrder;
}
// abstract factory method
protected abstract ICoffee CreateCoffee(string coffeeType, CoffeSizeType size);
}
and
public class SofiaCoffeeStore : CoffeeStore
{
private readonly IDictionary<string, Func<CoffeSizeType, ICoffee>> strategies;
public SofiaCoffeeStore(
IProcessedOrderFactory processedOrderFactory,
IDictionary<string, Func<ICoffee, ICoffee>> condimentsStrategies,
IDictionary<string, Func<CoffeSizeType, ICoffee>> strategies)
: base(processedOrderFactory, condimentsStrategies)
{
if (strategies == null)
{
throw new ArgumentNullException(nameof(strategies));
}
this.strategies = strategies;
}
protected override ICoffee CreateCoffee(string coffeeType, CoffeSizeType size)
{
if (!this.strategies.ContainsKey(coffeeType))
{
throw new ArgumentNullException();
}
return this.strategies[coffeeType](size);
}
}
also the ninject registering module looks like this:
private static void RegisterServices(IKernel kernel)
{
kernel.Bind(x => x
.FromAssemblyContaining<ICoffee>()
.SelectAllClasses()
.Excluding<ICoffee>()
.BindAllInterfaces());
kernel.Bind(x => x
.FromAssemblyContaining<ICoffee>()
.SelectAllInterfaces()
.EndingWith("Factory")
.BindToFactory());
kernel.Bind<ICoffee>().To<Americano>().NamedLikeFactoryMethod((ICoffeeTypeFactory f) => f.GetAmericano(default(CoffeSizeType)));
kernel.Bind<ICoffee>().To<Cappuccino>().NamedLikeFactoryMethod((ICoffeeTypeFactory f) => f.GetCappucino(default(CoffeSizeType)));
kernel.Bind<ICoffee>().To<Espresso>().NamedLikeFactoryMethod((ICoffeeTypeFactory f) => f.GetEspresso(default(CoffeSizeType)));
kernel.Bind<ICoffee>().To<Latte>().NamedLikeFactoryMethod((ICoffeeTypeFactory f) => f.GetLatte(default(CoffeSizeType)));
kernel.Bind<ICoffee>().To<Ristretto>().NamedLikeFactoryMethod((IPlovdivStoreCoffeeTypeFactory f) => f.GetRistretto(default(CoffeSizeType)));
kernel.Bind<ICoffee>().To<Doppio>().NamedLikeFactoryMethod((ISofiaStoreCoffeeTypeFactory f) => f.GetDoppio(default(CoffeSizeType)));
kernel.Bind<ICoffee>().To<Caramel>().NamedLikeFactoryMethod((ICondimentsFactory f) => f.GetCaramel(default(ICoffee)));
kernel.Bind<ICoffee>().To<Chocolate>().NamedLikeFactoryMethod((ICondimentsFactory f) => f.GetChocolate(default(ICoffee)));
kernel.Bind<ICoffee>().To<Cinnamon>().NamedLikeFactoryMethod((ICondimentsFactory f) => f.GetCinnamon(default(ICoffee)));
kernel.Bind<ICoffee>().To<Milk>().NamedLikeFactoryMethod((ICondimentsFactory f) => f.GetMilk(default(ICoffee)));
kernel.Bind<ICoffee>().To<WhippedCream>().NamedLikeFactoryMethod((ICondimentsFactory f) => f.GetWhippedCream(default(ICoffee)));
var sofiaStoreStrategies = new Dictionary<string, Func<CoffeSizeType, ICoffee>>
{
{ "Americano", kernel.Get<ICoffeeTypeFactory>().GetAmericano },
{ "Capuccino", kernel.Get<ICoffeeTypeFactory>().GetCappucino },
{ "Espresso", kernel.Get<ICoffeeTypeFactory>().GetEspresso },
{ "Latte", kernel.Get<ICoffeeTypeFactory>().GetLatte },
{ "Doppio", kernel.Get<ISofiaStoreCoffeeTypeFactory>().GetDoppio },
};
var plovdivStoreStrategies = new Dictionary<string, Func<CoffeSizeType, ICoffee>>
{
{ "Americano", kernel.Get<ICoffeeTypeFactory>().GetAmericano },
{ "Capuccino", kernel.Get<ICoffeeTypeFactory>().GetCappucino },
{ "Espresso", kernel.Get<ICoffeeTypeFactory>().GetEspresso },
{ "Latte", kernel.Get<ICoffeeTypeFactory>().GetLatte },
{ "Ristretto", kernel.Get<IPlovdivStoreCoffeeTypeFactory>().GetRistretto },
};
var condimentsStrategies = new Dictionary<string, Func<ICoffee, ICoffee>>
{
{ "Milk", kernel.Get<ICondimentsFactory>().GetMilk },
{ "Caramel", kernel.Get<ICondimentsFactory>().GetCaramel },
{ "Chocolate", kernel.Get<ICondimentsFactory>().GetChocolate },
{ "Cinnamon", kernel.Get<ICondimentsFactory>().GetCinnamon },
{ "Whipped cream", kernel.Get<ICondimentsFactory>().GetWhippedCream },
};
kernel.Bind<IDictionary<string, Func<CoffeSizeType, ICoffee>>>().ToConstant(sofiaStoreStrategies)
.WhenInjectedInto<SofiaCoffeeStore>();
kernel.Bind<IDictionary<string, Func<CoffeSizeType, ICoffee>>>().ToConstant(plovdivStoreStrategies)
.WhenInjectedInto<PlovdivCoffeeStore>();
kernel.Bind<IDictionary<string, Func<ICoffee, ICoffee>>>().ToConstant(condimentsStrategies)
.WhenInjectedInto<CoffeeStore>();
//some more bellow
}
An error occurs in method ProcessOrder (class CoffeeStore).
Ninject.ActivationException occurred
HResult=0x80131500
Message=Error activating ICoffee
More than one matching bindings are available.
Matching bindings:
1) binding from ICoffee to Caramel
2) binding from ICoffee to Chocolate
3) binding from ICoffee to Cinnamon
.....
22) binding from ICoffee to WhippedCream
Activation path:
2) Injection of dependency ICoffee into parameter coffee of constructor of type Cinnamon
1) Request for ICoffee
Suggestions:
1) Ensure that you have defined a binding for ICoffee only once.
I'm collecting user input as string from 3-stage wizard form and then use it at once for object initialization. Hope the code I shared is enough to get an idea what i'm trying to do next: First I want to initialize one of the coffee type classes and then to decorate the object with one or more of the decorator classes. The error occurs on the second step - when I try to initialize a decorator class, the first step goes ok. Any idea how to overcome this ?
Aucun commentaire:
Enregistrer un commentaire