I have two components registered for a service:
container.Register(
Component.For<IDataStorage>().Named("FirstChoice").ImplementedBy...
Component.For<IDataStorage>().Named("SecondChoice").ImplementedBy
Then I have a set of components deriving from this base class, that depends on those components:
public abstract class BaseMessageHandler
{
public IDataStorage FirstStorage {get; set;}
public IDataStorage SecondStorage {get; set;}
}
If I was registering these "handlers" (deriving from BaseMessageHandler) manually, I would specify a service override, indicating which component I want for properties "FirstStorage" and "SecondStorage". Something like:
.Configure(x => x.DependsOn(
ServiceOverride.ForKey("FirstStorage").Eq("FirstChoice"),
ServiceOverride.ForKey("SecondStorage").Eq("SecondChoice"))
Unfortunately, this registration is done automatically by a framework (NServiceBus). I know that if I register the handlers first (before NServiceBus has a chance to do so), these registrations will stick. But rather than try to guess and mimick the registration NServiceBus does, I wonder if I can specify service overrides in a custom IContributeComponentModelConstruction.
It seems a good place to do so, and I'm able to find these properties:
public class DataStorageOverrideContributor : IContributeComponentModelConstruction
{
public void ProcessModel(Castle.MicroKernel.IKernel kernel, Castle.Core.ComponentModel model)
{
var dataStorageDependencies = model.Properties.Where(
x => x.Dependency.TargetItemType == typeof(IDataStorage));
foreach (var propertyDependency in dataStorageDependencies)
{
// now what??
but I'm not sure the proper way to:
check if a service override is already specified (in which case I would do nothing)
add a service override to a property dependency.
Is this something that could be done inspecting and working the ComponentModel in the IContributeComponentModelConstruction.ProcessModel method?
I would use a subdependency resolver in your scenario. You can see the code below on how to use it.
Goodluck,
Marwijn.
public interface IDataStorage
{
}
public class DataStore1 : IDataStorage
{
}
public class DataStore2 : IDataStorage
{
}
public class BaseMessageHandler
{
public IDataStorage FirstStorage { get; set; }
public IDataStorage SecondStorage { get; set; }
}
public class SubDependencyResolver : ISubDependencyResolver
{
private readonly IKernel _kernel;
public SubDependencyResolver(IKernel kernel)
{
_kernel = kernel;
}
public bool CanResolve(CreationContext context, ISubDependencyResolver contextHandlerResolver, ComponentModel model,
DependencyModel dependency)
{
return model.Implementation == typeof (BaseMessageHandler) && dependency.TargetType == typeof(IDataStorage);
}
public object Resolve(CreationContext context, ISubDependencyResolver contextHandlerResolver, ComponentModel model,
DependencyModel dependency)
{
var handlers = _kernel.GetHandlers(dependency.TargetType);
switch (dependency.DependencyKey)
{
case "FirstStorage":
return handlers.Single(h => h.ComponentModel.Implementation == typeof (DataStore1)).Resolve(context);
case "SecondStorage":
return handlers.Single(h => h.ComponentModel.Implementation == typeof(DataStore2)).Resolve(context);
}
return null;
}
}
[TestFixture]
public class Tests
{
[Test]
public void SomeTest()
{
var container = new WindsorContainer();
container.Kernel.Resolver.AddSubResolver(new SubDependencyResolver(container.Kernel));
container.Register(
Component.For<IDataStorage>().Named("FirstChoice").ImplementedBy<DataStore1>(),
Component.For<IDataStorage>().Named("SecondChoice").ImplementedBy<DataStore2>(),
Component.For<BaseMessageHandler>()
);
var messageHandler = container.Resolve<BaseMessageHandler>();
Assert.AreEqual(typeof(DataStore1), messageHandler.FirstStorage.GetType());
Assert.AreEqual(typeof(DataStore2), messageHandler.SecondStorage.GetType());
}
}
alternative you may use:
case "FirstStorage":
return handlers.Single(h => h.ComponentModel.Name == "FirstChoice").Resolve(context);
case "SecondStorage":
return handlers.Single(h => h.ComponentModel.Name == "SecondChoice").Resolve(context);
to resolve on component name rather then implementation type.
Related
This article, https://medium.com/#dmitryzaets/legacy-net-applications-configuration-management-net-framework-4-5-1-68220335d9d8, describe how to use Options pattern together with Autofac. I have tried to translate this to use with Simple Injector. But I have no luck.
Here is my IOC code
public class IocBootstrap2
{
private Container Container { get; }
public IocBootstrap2()
{
Container = new Container();
var configurationBuilder = new ConfigurationBuilder()
.SetBasePath(Path.Combine(System.AppDomain.CurrentDomain.BaseDirectory, "Configuration"))
.AddJsonFile("settings.json", optional: false, reloadOnChange: true);
var configuration = configurationBuilder.Build();
//Register Options
Container.Register(typeof(IOptions<>), typeof(OptionsManager<>));
Container.Register(typeof(IOptionsMonitor<>), typeof(OptionsMonitor<>));
Container.Register(typeof(IOptionsFactory<>), typeof(OptionsFactory<>));
Container.Register(typeof(IOptionsMonitorCache<>), typeof(OptionsCache<>));
// Register ConfigurationOptions
Container.RegisterConfigurationOptions2<MailingOptions>(configuration.GetSection("mailing"));
#if DEBUG
Container.Verify();
#endif
}
}
public static class ConfigurationSetupExtensions2
{
public static void RegisterConfigurationOptions2<TOptions>(this Container container, IConfiguration config)
where TOptions : class
{
container.Register(typeof(IOptionsChangeTokenSource<TOptions>),
() => new ConfigurationChangeTokenSource<TOptions>(config), Lifestyle.Transient);
container.Register(typeof(IConfigureOptions<TOptions>),
() => new ConfigureFromConfigurationOptions<TOptions>(config), Lifestyle.Transient);
}
}
public class MailingOptions
{
public MailingOptions()
{
BatchSize = 1;
}
public int BatchSize { get; set; }
public int BatchDelay { get; set; }
}
settings.json
{
"mailing": {
"batchSize": 15,
"batchDelay": 1
}
}
Then I inject it in a ViewModel:s constructor like this
public class BlockViewModel
{
private readonly MailingOptions _options;
#region Constructor
public BlockViewModel(IOptions<MailingOptions> options)
{
_options = options.Value;
}
#endregion
}
When I run it I get Exceptions in Container.Verify.
The constructor of type OptionsFactory<MailingOptions> contains the parameter with name 'setups' and type IEnumerable<IConfigureOptions<MailingOptions>> that is not registered. Please ensure IEnumerable<IConfigureOptions<MailingOptions>> is registered, or change the constructor of OptionsFactory<MailingOptions>. There is, however, a registration for IConfigureOptions<MailingOptions>; Did you mean to depend on IConfigureOptions<MailingOptions>?
StackTrace:
at SimpleInjector.Container.ThrowParameterTypeMustBeRegistered(InjectionTargetInfo target)
How will I Register an IEnumerable<IConfigureOptions<MailingOptions>>?
Can someone tell my what I'm doing wrong, or more precise, what is it that I don't understand?
The short answer is: don't inject IOptions<T> into your application components. As explained here, that will only complicate your components, their unit tests, and, as you already noticed, your configuration.
Instead, let BlockViewModel depend on MailingOptions directly:
public class BlockViewModel
{
private readonly MailingOptions _options;
public BlockViewModel(MailingOptions options)
{
_options = options ?? throw new ArgumentNullException(nameof(options));
}
}
This allows you to simplify your configuration to the following:
Container = new Container();
var configutation = new ConfigurationBuilder()
.SetBasePath(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Configuration"))
.AddJsonFile("settings.json", optional: false);
.Build();
MailingOptions options = configuration.GetSection("mailing").Get<MailingOptions>();
Container.RegisterInstance<MailingOptions>(options);
// Register View Models
Container.Register<BlockViewModel>();
Container.Verify();
I want to register an interface like: IInterceptingAware, so that for all classes which implement this interface an interceptor class is used.
public class InterceptorClass : IInterceptor
{
public void Intercept(IInvocation invocation)
{
// Do my work
}
}
public class Foo : IInterceptingAware
{
}
public class Bar : IInterceptingAware
{
}
How do I setup castle windsor for this?
using (var container = new WindsorContainer())
{
container.Register(
Component.For<MyInterceptorClass>(),
Classes.FromThisAssembly()
.BasedOn<IInterceptingAware>()
.WithServiceDefaultInterfaces()
.ConfigureFor<IInterceptingAware>(c => c.Interceptors<MyInterceptorClass>())
);
var foo = container.Resolve<Foo>();
foo.Test();
var bar = container.Resolve<IBar>();
bar.Test();
}
Console.ReadLine();
Keep in mind interceptor requires at least virtual methods on target class, even better your target class should implement an interface in order to have the interceptor working on that contract.
Said so, your Foo class should at least have a method named Test marked as virtual
while Bar should implement IBar:
public interface IBar
{
void Test();
}
With Castle Windsor 3.2
I need to resolve service implementation on the fly depending on contextual parameters.
Here is basic example of what I want to do:
I have a service IFoo
public interface IFoo
{
object GetSomething();
}
Implemented by 2 different classes Foo1 and Foo2
public class FooBase
{
public int Number {get; private set;}
public FooBase(int number)
{
Number = number;
}
}
public class Foo1 : IFoo
{
public Foo1(int number):base(number)
public object GetSomething()
{
return "Foo1";
}
}
public class Foo2 : IFoo
{
public Foo2(int number):base(number)
public object GetSomething()
{
return "Foo2";
}
}
I want to call the castle windsor resolve method with number as parameter, and depending on the number I want to have Foo1 or Foo2 object:
var foo1 = container.Resolve<IFoo>(new {number= 1});
// foo1 is Foo1
var foo2 = container.Resolve<IFoo>(new {number= 2});
// foo2 is Foo2
I tried several potential solutions, but I'm realy confused because of the lack of Castle Windsor documentation and examples, adding to that most of the examples are not up to date and are using obsolete API.
So I have seen some example using the following concepts, but none of them seemed to much my requirement :
HandlerSelector
Typed Factory facility
UsingFactoryMethod
Here is the code that worked for me:
container = new WindsorContainer();
container.AddFacility<TypedFactoryFacility>();
container.Register(
Component.For<IFoo>().ImplementedBy<Foo1>().Named("Foo1"),
Component.For<IFoo>().ImplementedBy<Foo2>().Named("Foo2"),
Component.For<IFooFactory>().AsFactory(c => c.SelectedWith<FooSelector>())
);
Create a Foo factory :
public interface IFooFactory
{
IFoo CreateFoo(int number);
}
and a selector:
public class FooSelector : DefaultTypedFactoryComponentSelector
{
protected override string GetComponentName(System.Reflection.MethodInfo method, object[] arguments)
{
var argument = (int) arguments[0];
return string.Format("Foo{0}", argument);
}
}
use the following registration code:
container = new WindsorContainer();
container.AddFacility<TypedFactoryFacility>();
container.Register(
Component.For<FooSelector>,
Component.For<Foo1>(),
Component.For<Foo2>(),
Component.For<IFooFactory>().AsFactory(c => c.SelectedWith<FooSelector>())
);
Create a Foo factory :
public interface IFooFactory
{
IFoo CreateFoo(int number);
}
and a selector:
public class FooSelector : DefaultTypedFactoryComponentSelector
{
protected override Type GetComponentType(System.Reflection.MethodInfo method, object[] arguments)
{
var argument = (int) arguments[0];
if (argument == 1) return typeof (Foo1);
if (argument == 2) return typeof(Foo2);
throw new ApplicationException();
}
}
Now resolve the IFooFactory and call the create methode with the value that you want.
Kind regards,
Marwijn.
How can I use a ninject factory, which creates an instance with constructor parameters, without relying on the argument names.
The problem is that the ToConstructor()-Method not works, because I bind it to a generic definition.
The following example works, if I use the factory method with the corresponding constructor argument name, but I don't like it rely on names.
Because the following solution is very fragil and breaks if someone chooses a wrong name or renames the ctor-argument in the derived class.
Any solution?
Here's the example code:
[TestFixture]
public class NinjectFactoryBindingsTest
{
[Test]
public void ConstructorSelectionWithArguments()
{
NinjectSettings ninjectSettings = new NinjectSettings();
ninjectSettings.LoadExtensions = false;
using (var kernel = new StandardKernel(ninjectSettings, new FuncModule()))
{
// IDependencyA will be passed to the factory, therefore it is not bounded
//kernel.Bind<IDependencyA>().To<DependencyA>();
kernel.Bind<IDependencyB>().To<DependencyB>();
kernel.Bind(typeof(IGenericBaseClass<>)).To(typeof(GenericDerivedClass<>));
kernel.Bind<IGenericClassFactory>().ToFactory();
IGenericClassFactory factory = kernel.Get<IGenericClassFactory>();
DependencyA dependencyA = new DependencyA();
IGenericBaseClass<GenericImpl> shouldWorkInstance = factory.Create<GenericImpl>(dependencyA);
Assert.NotNull(shouldWorkInstance);
}
}
}
public interface IGenericClassFactory
{
IGenericBaseClass<TGeneric> Create<TGeneric>(IDependencyA someName) where TGeneric : IGeneric;
// This works, but relies on ctor-param-names!!!
// IGenericBaseClass<TGeneric> Create<TGeneric>(IDependencyA otherNameThanInBaseClass) where TGeneric : IGeneric;
}
public class DependencyA : IDependencyA
{
}
public class DependencyB : IDependencyB
{
}
public class GenericDerivedClass<TGeneric> : GenericBaseClass<TGeneric> where TGeneric : IGeneric
{
public GenericDerivedClass(IDependencyA otherNameThanInBaseClass, IDependencyB dependencyB)
: base(otherNameThanInBaseClass, dependencyB)
{
}
}
public abstract class GenericBaseClass<TGeneric> : IGenericBaseClass<TGeneric> where TGeneric : IGeneric
{
protected GenericBaseClass(IDependencyA dependencyA, IDependencyB dependencyB)
{
}
}
public interface IGenericBaseClass<TGeneric> where TGeneric : IGeneric
{
}
public interface IDependencyB
{
}
public interface IDependencyA
{
}
public class GenericImpl : IGeneric
{
}
public interface IGeneric
{
}
The factory extension has the convention that arguments must have the same name as the constructor argument they will be passed to. There are no easy ways to do it differently. The only way I can think of is about the following:
Create a new IParameter implementation that can hold a reference to an IDependencyA.
Create either a hardcoded factory or a custom IInstanceProvider (see documentation) that creates an instance of your IParameter implementation so that it is passed to the Get<> request
Add a new binding for IDependencyA: Bind<IDependency>().ToMethod(ctx => extract and return your parameter from the context)
I have an interface ISession whose instance is produced by a different Session Factory depending on which namespace the class belongs to.
Example of my component registration:
IWindsorContainer container = new WindsorContainer();
container.Register(Component.For<NHibernate.ISession>()
.UsingFactoryMethod((kernel, creationContext) =>
{
NHibernate.ISession session =
new SessionFactoryForNamespace1()
.Instance.GetSession();
return session;
})
.LifestylePerWebRequest());
container.Register(Component.For<NHibernate.ISession>()
.UsingFactoryMethod((kernel, creationContext) =>
{
NHibernate.ISession session =
new SessionFactoryForNamespace2()
.Instance.GetSession();
return session;
})
.LifestylePerWebRequest());
container.Register(Component.For<Namespace1.IRepository1()
.ImplementedBy<Namespace1.Repository1>());
container.Register(Component.For<Namespace2.IRepository2>()
.ImplementedBy<Namespace2.Repository2>());
Example of the resolution graph:
public class MyController
{
public MyController(Namespace1.IRepository1 repo1,
Namespace2.IRepository2 repo2) { }
}
namespace Namespace1
{
public interface IRepository1 { }
public class Repository1 : IRepository1
{
public Repository1(NHibernate.ISession session) { }
}
}
namespace Namespace2
{
public interface IRepository2 { }
public class Repository2 : IRepository2
{
public Repository2(NHibernate.ISession session) { }
}
}
When Castle Windsor is asked to resolve MyController, it then tries to resolve IRepository1 and IRepository2, and subsequently the ISession for each. I want to have Castle Windsor select the component handlers based on the requestor type's namespace which in my example is either Namespace1 or Namespace2.
I am new to Castle Windsor and not sure where in the resolution pipeline I'm supposed to be plugging into.
What is the best approach to accomplish what I have outlined above?
I think a service override would work for this.
UPDATE:
I also did an article on some of Windsor's advanced features (including a section on Service Overrides) that should augment the documentation linked above.
Here is how I implemented service override solution:
Repository interfaces now inherit from a common repository interface:
public class MyController
{
public MyController(Namespace1.IRepository1 repo1,
Namespace2.IRepository2 repo2) { }
}
public interface IRepository { }
namespace Namespace1
{
public interface IRepository1 : IRepository { }
public class Repository1 : IRepository1
{
public Repository1(NHibernate.ISession session) { }
}
}
namespace Namespace2
{
public interface IRepository2 : IRepository { }
public class Repository2 : IRepository2
{
public Repository2(NHibernate.ISession session) { }
}
}
Repository component registeration based on its namespace:
IWindsorContainer container = new WindsorContainer();
...
Action<Type> RegisterRepository = t =>
{
container.Register(
AllTypes.FromAssemblyContaining(t)
.BasedOn(typeof(IRepository))
.WithServiceAllInterfaces()
.Configure(c =>
{
c.DependsOn(
ServiceOverride
.ForKey<NHibernate.ISession>()
.Eq(c.Implementation.Namespace));
c.LifeStyle.Is(LifestyleType.Transient);
})
);
};
RegisterRepository(typeof(Namespace1.IRepository1));
RegisterRepository(typeof(Namespace2.IRepository2));
Seems to work :)