Sorry, I am new to Castle.Windsor, so this may be a noob question.
I have the following structure:
public class Device
{
...
}
public class Sensor : Device
{
...
}
public class Actuator : Device
{
...
}
I want to query Castle.Windsor for all components that inherit from Device...
How can I achieve this?
Thanks!
Try this:
container.Register(Classes
.FromAssemblyContaining<Device>()
.BasedOn<Device>()
.WithServiceBase()
.LifestyleTransient());
Related
I have a Service that need inject more than one provider, see below for example. How to use Unity to implement this feature?
public class MyService: IMyService
{
public MyService(IEnumerable<Provider> Providers);
}
I know this is an old question, but maybe this will help someone else that stumbles upon this.
As long as you register the implementations with a specific name, this is possible to easily inject. You will then get all registered implementations.
public class MyService: IMyService
{
public MyService(IProvider[] providers)
{
// Do something with the providers
}
}
Just make sure to inject them as an array. Unity will understand this. And when you register them you can register them as such:
container.RegisterType<IProvider, FooProvider>("Foo");
container.RegisterType<IProvider, BarProvider>("Bar");
One way is to inject the UnityContainer itself, and then resolve all the Providers you need:
public class MyService : IMyService
{
public class MyService(IUnityContainer iocContainer)
{
var providers = iocContainer.ResolveAll<IProvider>();
}
}
The only thing you will need to do is register the UnityContainer with itself somewhere on setup:
unityContainer.Register<IUnityContainer>(unityContainer, new ContainerControllerLifetimeManager());
I need to modify an existing web app to use Castle.Windsor as IOC container. It was originally developed with StructureMap.
I am stuck with the following problem.
Lets say I have registered a couple of interfaces and their corresponding implementations:
IFoo -> Foo
IBar -> Bar
Calling container.Resolve<IFoo>() or container.Resolve<IBar>() works just fine. This means that the services are registered correctly.
I have a Web Api class with dependencies on other services, such as IFoo
public class BadRequestErrorHandler : HttpErrorHandler
{
// services
public BadRequestErrorHandler(IFoo foo) {...} // has dependency on IFoo
}
In StructureMap I can call:
var test = ObjectFactory.GetInstance<BadRequestErrorHandler>();
this will resolve the IFoo dependency.
Now this does not work with windsor.
How can this be achieved with windsor?
Thanks!
* EDIT *
I was just able to make it work by explicitely registering the BadRequestErrorHandler.
container.Register(Component.For<BadRequestErrorHandler>());
I am just hoping there is a better way to achieve this, that does not involve registering classes that have dependencies. I have a bunch of them...
* EDIT 2 **
To ease the pain, I added a special method to deal with these concrete types.
public T GetInstanceWithAutoRegister<T>()
{
if (container.Kernel.GetHandler(typeof(T)) == null)
{
container.Register(Component.For<T>());
}
return container.Resolve<T>();
}
public object GetInstanceWithAutoRegister(Type pluginType)
{
if (container.Kernel.GetHandler(pluginType) == null)
{
container.Register(Component.For(pluginType));
}
return container.Resolve(pluginType);
}
not ideal, but at least better than having to explicetly register each type. Hope someone has a better solution
You can achieve what you want by registering an ILazyComponentLoader which is a hook that gets called by Windsor as a "last resort" when a component cannot be resolved.
In your case, the implementation would probably look somewhat like this:
public class JustLetWindsorResolveAllConcreteTypes : ILazyComponentLoader
{
public IRegistration Load(string key, Type service)
{
return Component.For(service);
}
}
-and then it should be registered as such:
container.Register(Component.For<ILazyComponentLoader>()
.ImplementedBy<JustLetWindsorResolveAllConcreteTypes>());
You can read more about it in the docs.
How do I register IPetFactory<TPet> to be resolved with DefaultPetFactory<TPet> where TPet can be any class based on Pet in the example below?
I'd like to be able to resolve IPetFactory<Dog> with DefaultPetFactory<Dog>.
I've just found examples using BasedOn where the Factory itself is based on a class, not the generic argument.
class Pet
{
public string Name { get; set; }
}
class Fish : Pet {}
class Dog : Pet {}
class Cat : Pet { }
interface IPetFactory<TPet> where TPet : Pet;
class DefaultPetFactory<TPet> : IPetFactory<Pet> where TPet : Pet
{
// default implementation
}
My real implementation has a lot of classes based on Pet so I'm looking for a more generic approach than just calling register on each of them.
EDIT:
I found out the problem wasn't what I thought it was. It was due to the generic arguments and an exception of “the arity of the generic type definition” which caused my problems.
And I over-simplified my example. In my real implementation I have to generic arguments and it turns out Windsor need the the same generic parameters to be able to resolve the type.
If I do like this it won't work.
class Owner
{
}
class DefaultPetFactory<TPet> : IPetFactory<Owner, TPet> where TPet : Pet
{
// default implementation
}
If I do like this it will:
class DefaultPetFactory<TOwner, TPet> : IPetFactory<TOwner, TPet>
where TOwner : Owner
where TPet : Pet
{
// default implementation
}
If anyone has a better solution to this, preferably with the registrations it's appreciated. I don't like to change my classes to make the registration work.
(For the updated question)
There is a ticket in Windsor's issue tracker to support scenarios like that (feel free to vote for it), but in general this is something very hard to implement... generically (no pun intended), and as far as I know no container currently supports it.
In Windsor 3 you can workaround it by implementing a new interface called IGenericImplementationMatchingStrategy doing roughly the following (untested, I'm writing this from memory):
public class PetMatcher: IGenericImplementationMatchingStrategy
{
public Type[] GetGenericArguments(ComponentModel model, CreationContext context)
{
if (SomePreconditionToMakeSureThatsReallyTheScenarioDescribedAbove() == false )
{
return null;// which will fallback to default behaviour
}
// implementation needs just one generic arg, second of two the interface has
return new[]{ context.GenericArguments[1] };
}
}
You then register this as follows:
Container.Register(
Classes.FromAssemblyContaining(typeof(IPetFactory<,>)).BasedOn(typeof(IPetFactory<,>))
.WithServiceBase()
.Configure(
c => c.ExtendedProperties(
Property.ForKey(ComponentModel.GenericImplementationMatchingStrategy)
.Eq(new PetMatcher()))));
Is there a better way to hook up dependencies??
This relies on the singleton App.Current and exposing a function that exposes the _container.SatisfyImports.
Is there a more MEF-tastic way of doing things?
Here is part of my main application class
public partial class App : Application
{
private CompositionContainer _container;
....
public void SatisfyImportsOnce(Object satifyMe)
{
_container.SatisfyImportsOnce(satisfyMe);
}
}
Here is a test class instantiated long after ComposeParts is called...
public class TestClass
{
public TestClass()
{
Console.WriteLine("Created a TestClass");
((Microsoft.Samples.XFileExplorer.App)App.Current).SatisfyImportsOnce(this);
}
}
I am in a similar situation in a WPF application where I want the MainWindow instance to import MEF exports. Since MEF does not create the MainWindow instance, it will not satisfy the imports unless you tell it to.
The way you are doing it will work if you do not want your instance to be registered for recomposition. If you do want recomposition, you should call ComposeParts.
Recomposition will update the imports in your class if and when they change.
Can you import using a class that inherits from Lazy rather than Lazy itself? I am exporting using a derivitive of ExportAttribute that contains metadata.
[FeatureExport(/* Feature Metadata Parameters */)]
public class Feature : IFeature
{
// Feature Properties
}
public class FeatureReference : Lazy<IFeature, IFeatureMetadata>
{
}
public class Consumer
{
[ImportMany]
public IEnumerable<FeatureReference> FeatureReferences { get; set; }
}
Is this possible? Would it work? I could try it myself, but I'm in development so I don't actually have any code written.
No, it won't work I'm afraid. You would need to implement your own programming model extension (either a custom part/catalog or possibly via ReflectionModelServices) to make this work.
MEF would have to create the FeatureReference object in order to set it, and considering that FeatureReference might have any constructor imaginable, you can guess why this isn't supported.