I am referring to this tutorial.
At the beginning the IController types are registered as:
public class ControllersInstaller:IWindsorInstaller
{
public void Install(IWindsorContainer container, IConfigurationStore store)
{
container.Register(Classes.FromThisAssembly()
.BasedOn<IController>()
.LifestyleTransient());
}
}
But later The EventRepository is registered as below:
public class RepositoriesInstaller : IWindsorInstaller
{
public void Install(IWindsorContainer container, IConfigurationStore store)
{
container.Register(Classes.FromThisAssembly()
.Where(Component.IsInSameNamespaceAs<EventRepository>())
.WithService.DefaultInterfaces()
.LifestyleTransient()));
}
}
What is the difference between the two? I tried using the method used for IController registration to register IEventRepository but it doesn't work? Why?
Now in case of IEventRepository, its implementation EventRepository is used in the registration. If I implement another class say AnotherEventRepository, then I will have to add another registration for that. Can't we use a single registration to register all types of IEventRepository.
If you need to registrer all classes implementing IEventRepository you need to add BasedOn as above. Don't forget the Where you added... That means you are considering only classes belonging to that ns.
The first registration is pretty straightforward. You just register all classes implementing IController interface. Those classes are also they services. So if you want to resolve eg. HomeController you just call container.Resolve<HomeController>().
The second registration takes all classes from the namespace where the EventRepository is declared and registers them with default interfaces. So if you want to resolve EventRepository you have to call container.Resolve<IEventRepository>().
In case of AnotherEventRepository you don't have to add another registration if it is in the same namespace. But if it also implements IEventRepository you won't actually know which implementations will be resolved.
Related
Most of my components are registered using the code-based (fluent) approach, but there is one particular component that I need to resolve differently at runtime. This is the interface and a couple of concrete implementations:-
public interface ICommsService ...
public class SerialCommsService : ICommsService ...
public class TcpCommsService : ICommsService ...
Some of our users will need the serial service while others will need the TCP service. My current solution (which works btw) is to use a typed factory and a custom component selector - the latter reads an app.config setting to determine which implementation the typed factory will resolve and return.
First the typed factory (nothing special about this):-
public interface ICommsServiceFactory
{
ICommsService Create();
void Release(ICommsService component);
}
Next, the custom component selector, which reads the fully-qualified type name from app.config (e.g. "MyApp.SomeNamespace.TcpCommsService"):-
public class CommsFactoryComponentSelector : DefaultTypedFactoryComponentSelector
{
protected override string GetComponentName(MethodInfo method, object[] arguments)
{
return ConfigurationManager.AppSettings["commsServiceType"];
}
}
Then the registration stuff:-
var container = new WindsorContainer();
container.AddFacility<TypedFactoryFacility>();
container.Register(Component.For<ITypedFactoryComponentSelector>()
.ImplementedBy<CommsFactoryComponentSelector>());
container.Register(Component.For<ICommsFactory>()
.AsFactory(o => o.SelectedWith<CommsFactoryComponentSelector>()));
container.Register(Component.For<ICommsService>()
.ImplementedBy<SerialCommsService>().LifeStyle.Singleton);
container.Register(Component.For<ICommsService>()
.ImplementedBy<TcpCommsService>().LifeStyle.Singleton);
Finally, an example class with a dependency on ICommsService:-
public class Test
{
public Test(ICommsFactory commsFactory)
{
var commsService = commsFactory.Create();
...
}
}
As already mentioned, the above solution does work, but I don't like having to inject the factory. It would be more intuitive if I could just inject an ICommsService, and let something somewhere figure out which implementation to resolve and inject - similar to what I'm doing now but earlier in Windsor's "resolving pipeline". Is something like that possible?
You can use UsingFactoryMethod here:
container.Register(Component.For<ICommsService>().UsingFactoryMethod(kernel => kernel.Resolve<ICommsServiceFactory>().Create()));
You can inject ICommsService to any class now. ICommsServiceFactory can be a simple interface now:
interface ICommsServiceFactory
{
ICommsService Create();
}
I'm trying to figure out Windsor as an IOC container.
The problem I'm facing right now is to register all of my viewmodels at once.
I've taken a look at the docs and thought that the following code should work.
However, when I check the container afterwards, nothing is registered.
container.Register(Classes.FromThisAssembly()
.BasedOn<ViewModelBase>()
.LifestyleTransient());
where ViewModelBase is my baseclass.
Also tried the following:
container.Register(Classes.FromThisAssembly()
.InSameNamespaceAs<MainWindowViewModel>()
.LifestyleTransient());
The necessary dependencies can be resolved, the viewmodels not.
I suppose I'm missing something obvious here?
Edit
My dependencies are registered as follows:
this.container.Register(Component.For<IDALHandler>().ImplementedBy<DALHandler>());
this.container.Register(Component.For<IBLHandler>().ImplementedBy<BLHandler>());
UPDATE
Since the suggestions didn't work, I was planning on adding the code from my baseclass and viewmodel here.
While doing so I noticed that my viewmodel-class was internal sealed. When changing it to public sealed, the above code did work.
Can someone explain why internal classes can't be registered in the container?
I've already tested other IOC containers with the exact same setup and they didn't complain about it.
Your example of registration started working well in my application when I added selection of the service for component. E.g. .WithService.AllInterfaces()
container.Register(Classes.FromThisAssembly()
.BasedOn(typeof(MyBaseClass<>))
.WithService.AllInterfaces()
.LifestylePerWebRequest()
);
container.Register(Classes.FromThisAssembly()
.InSameNamespaceAs<MyBaseClass>()
.WithService.AllInterfaces()
.LifestylePerWebRequest()
);
UPDATE:
In order to register internal types, .IncludeNonPublicTypes() should be used.
public class ExampleTest
{
[Test]
public void MyBaseClass_Base()
{
var target = new WindsorContainer();
target.Register(Classes.FromThisAssembly()
.IncludeNonPublicTypes()
.BasedOn(typeof(MyBaseClass<>))
.WithService.Base()
//.LifestylePerWebRequest()
);
//assert
target.Resolve<MyBaseClass<int>>().Should().BeOfType<A>();
target.Resolve<MyBaseClass<string>>().Should().BeOfType<B>();
}
[Test]
public void MyBaseClass_Self()
{
var target = new WindsorContainer();
target.Register(Classes.FromThisAssembly()
.IncludeNonPublicTypes()
.BasedOn(typeof(MyBaseClass<>))
.WithService.Self()
//.LifestylePerWebRequest()
);
//assert
target.Resolve<MyBaseClass<int>>().Should().BeOfType<MyBaseClass<int>>();
target.Resolve<MyBaseClass<string>>().Should().BeOfType<MyBaseClass<string>>();
target.Resolve<A>().Should().BeOfType<A>();
target.Resolve<B>().Should().BeOfType<B>();
}
}
internal class MyBaseClass<T>
{
}
internal class A : MyBaseClass<int>
{
}
internal class B : MyBaseClass<string>
{
}
My guess is your viewmodels have been registered in the container, but they are not resolvable through their interface.
Set a breakpoint after the registration and check if container has been filled as expected.
UPDATE as per my comment below:
Keep in mind "group" registration (Classes.) skips internal class.
If they have been registered, let say you have a ViewModel like this
public class MyViewModel1 : ViewModelBase, IMyViewModel1
container.Resolve<MyViewModel1>() // resolve
container.Resolve<IMyViewModel1>() // no resolve
to accomplish the second resolving scenario you have to do what Ilya pointed about about adding WithService during registration, so you can resolve by interface instead of by concrete.
I have some executor-classes that implements one or two interfaces (IHandleMessages<> and/or CommandExecutor<>).
Can I register all these executor classes - with whichever interface(s) it implements of the two - as services. Without ending up having all other interfaces on the class as services too.
My initial attempt was this:
public class Test
{
[Fact]
public void SomeTest()
{
var container = new WindsorContainer();
container.Register(Classes.FromThisAssembly().BasedOn(typeof(CommandExecutor<>)).WithService.Base().LifestyleTransient(),
Classes.FromThisAssembly().BasedOn(typeof(IHandleMessages<>)).WithService.Base().LifestyleTransient());
container.ResolveAll<CommandExecutor<object>>().Count().ShouldBe(2);
container.ResolveAll<IHandleMessages<object>>().Count().ShouldBe(2);
}
public interface IHandleMessages<T> { }
public interface CommandExecutor<T> { }
public class HandlesMessagesOnly : IHandleMessages<object> { }
public class HandlesMessagesAndExecutesCommands : CommandExecutor<object>, IHandleMessages<object> { }
public class ExecutesCommandsOnly : CommandExecutor<object> { }
}
But that does not work. Is there a solution for this?
I'm using Windsor 3.1.0.
EDIT: I guess what I'm really asking is: Is it possible to find the same type twice, and just have the discoverer add more services to that type's registration?
This will make your test pass:
container.Register(
Classes
.FromThisAssembly()
.BasedOn(typeof(CommandExecutor<>))
.WithServiceBase()
.WithServiceFirstInterface() // Ensures first interface is included.
.LifestyleTransient(),
Classes
.FromThisAssembly()
.BasedOn(typeof(IHandleMessages<>))
.WithServiceBase()
.LifestyleTransient()
);
For more sophisticated interface selection techniques see this question.
I've made a pull request to Windsor which was accepted in 3.2, and you can now do this:
Container.Register(
Classes.FromThisAssembly()
.BasedOn<IFoo>()
.OrBasedOn(typeof(IBar))
.WithServiceBase()
.LifestyleTransient());
Read more here
I have a class like this:
public FooRepo : IFooRepo
{
public FooRepo(IDbContextFactory factory)
{
context = factory.GetContext();
}
}
In my app I register everything with LifeStyle.PerWebRequest,
but now I need to call one Method which uses this IFooRepo like this (because it's gonna take about an hour):
{
...
ThreadPool.QueueUserWorkItem(s => RequestReport(number));
...
}
private void RequestReport(int number)
{
// IFooRepo needed here
}
the problem is that I need this IFooRepo with PerWebRequest lifestyle most of the time, and I needed here in the thread also to stay alive, also it has a dependency IDbContextFactory which I don't know if I need to register it also in a different way
well then register your FooRepo twice and setup service override for whoever uses in on the ThreadPool to use the other component. Easy.
How to register two services with one instance of implementation? I used:
_container.Register(Component.For(new [] { typeof(IHomeViewModel), typeof(IPageViewModel) }).
ImplementedBy(typeof(HomeViewModel)).Named("IHomeViewModel").LifeStyle.Singleton)
But upper code registers two instances of HomeViewModel.
That's exactly the way to do it. See "Type Forwarding" in the docs. It registers one logical component accessible via IHomeViewModel or IPageViewModel. The following test passes:
public interface IHomeViewModel {}
public interface IPageViewModel {}
public class HomeViewModel: IHomeViewModel, IPageViewModel {}
[Test]
public void Forward() {
var container = new WindsorContainer();
container.Register(Component.For(new[] {typeof (IHomeViewModel), typeof (IPageViewModel)})
.ImplementedBy(typeof(HomeViewModel)).Named("IHomeViewModel").LifeStyle.Singleton);
Assert.AreSame(container.Resolve<IHomeViewModel>(), container.Resolve<IPageViewModel>());
}
BTW you might want to use generics instead of all those typeof, and also remove the lifestyle declaration, since singleton is the default:
container.Register(Component.For<IHomeViewModel, IPageViewModel>()
.ImplementedBy<HomeViewModel>());