Registering Windsor Component for both direct use and as an array - inversion-of-control

I'm automatically registering multiple components that implement the same interface:
container.Kernel.Resolver.AddSubResolver(
new ArrayResolver(container.Kernel));
container.Register(AllTypes.FromAssembly(Assembly.GetExecutingAssembly())
.BasedOn<IPaymentPostProcessor>()
.WithService.FromInterface(typeof(IPaymentPostProcessor))
.Configure(c => c.Named(c.Implementation.Name))
.Configure(c => c.LifeStyle.PerWebRequest));
This works when I have a dependency on the array itself:
public class PaymentPostProcessorManager{
public PaymentPostProcessorManager(IPaymentPostProcessor[] processors){}
}
But doesn't if I have a dependency on a specific component implementing the interface:
public class SpecialService{
public OtherService(SpecificPostProcessor processor){}
}
This fails, it says no components have been registered for SpecificPostProcessor. If I individually register that SpecificPostProcessor, it the array resolution ends up including it twice.
How can I do the automatic registration based on the interface AND have it automatically register it for specific dependencies?

You need to add WithService.Self() for your SpecificPostProcessor If you want to expose it as a service.

Related

Java hook only for one specific orientDB database

I have been able to create a java hook exactly with the method specified here:
https://orientdb.com/docs/2.2.x/Tutorial-Java-Hooks.html
But I don't want my hook to run for every database present on the server. I want to enable it only for one specific database.
Is it possible to do that simply by specifying it declaratively on the orientdb-server-config.xml ? or By configuring the hook in my Java class extending ODocumentHookAbstract ? Otherwise any idea how to do it programmatically ?
You can do this programatically by conditionally registering your hook based on the database name and implementing the database life cycle listener ODatabaseLifecycleListener. From the docs on hook self registration, you can do this in the overridden onOpen() method with something like:
public class MyHook extends ODocumentHookAbstract implements ODatabaseLifecycleListener {
...
#Override
public void onOpen(final ODatabase iDatabase) {
if("someSpecificDatabaseName".equals(iDatabase.getName()) {
// REGISTER THE HOOK
((ODatabaseComplex<?>)iDatabase).registerHook(this);
}
}
}
ODatabase.getName() javadoc

Autofac - dynamic Resolve based on registered provider

I'm having problems finding proper solution for my problem, namely:
Let's consider workflow:
Application starts
Main components are registered in Autofac
Application loads plugin assembly and registers modules within it
Container is being build
Plugin handling logic is run
Plugin can add its own controllers. To properly handle that I had to prepare interface which will provide me types of custom controllers:
interface ICustomControllerProvider
{
IEnumerable<Type> GetControllerTypes();
}
Based on the above my app knows how to integrate specified types as controllers.
All controllers are also defined as services, so Autofac deals with their creation, and so...
Problem:
I want to avoid specifying custom controller type twice
public PluginControllerProvider : ICustomControllerProvider
{
public IEnumerable<Type> GetControllerTypes()
{
// 1st type specification
// controller types are specified here, so they could be integrated with app
yield return typeof(ControllerX);
yield return typeof(ControllerY);
}
}
public class PluginModule : Module
{
protected override void Load(ContainerBuilder builder)
    {
builder.RegisterType<PluginControllerProvider>().As<ICustomControllerProvider>();
// 2nd type specification
// controllers have to be register in module as well
builder.RegisterType<ControllerX>();
builder.RegisterType<ControllerY>();
}
}
Is there any way how ControllerX and ControllerY could be managed by Autofac, where I specified them only in PluginControllerProvider?
I tried achieving that by providing custom registration source and resolving ICustomControllerProvider, however I cannot resolve ICustomControllerProvider based on arguments provided by IEnumerable<IComponentRegistration> RegistrationsFor(Service service, Func<Service, IEnumerable<ServiceRegistration>> registrationAccessor) from IRegistrationSource
Autofac does not offer the ability to inject a list of types registered with Autofac. You'll have to get that yourself by working with the lifetime scope registry.
Before I get into how you might solve this, I should probably note:
Listing the types registered is not a normal thing from a DI perspective. It'd be like listing all the controllers in your MVC application - you don't normally need to do that, and if you did, you'd likely need to build a whole metadata structure on top of it like the ApiExplorer that was built to do that on top of ASP.NET Core. That structure wouldn't be supported or involved with the DI system because you're querying about the system, not injecting live instances into the system.
If you are relying on DI to resolve controllers, you probably don't need a whole separate controller provider. Once you know what type you need for the request, you'd just resolve it.
All that's to say, while I'll answer the question, the way the design here is posed may be something you'd want to look at. What you're doing, trying to involve DI with listing metadata about the app... seems somewhat backwards (you'd feed the DI container based on the list of types, not get the list of types from the DI container).
But let's just go with it. Given:
There are controllers registered with Autofac
The controllers have no common base class or interface
There's no attributes on the controllers you could query
What I'd do is register all the controllers with some metadata. You need something to be able to locate the controllers in the list of all the types in the container.
builder.RegisterType<ControllerX>().WithMetadata("controller", true);
builder.RegisterType<ControllerY>().WithMetadata("controller", true);
Now in the plugin controller, you need to inject an ILifetimeScope because you have to query the list of stuff registered. The ILifetimeScope that gets injected into the controller will be the same scope from which the plugin controller itself was resolved.
You can use the injected scope to query things in the component registry tagged with your metadata.
public class PluginControllerProvider : ICustomControllerProvider
{
private readonly Type[] _controllerTypes;
public PluginController(ILifetimeScope scope)
{
_controllerTypes = scope
.ComponentRegistry
.Registrations
.Where(r => r.Metadata.ContainsKey("controller"))
.Select(r => r.Activator.LimitType)
.ToArray();
}
public IEnumerable<Type> GetControllerTypes()
{
return _controllerTypes;
}
}
Now, disclaimers:
If you are registering more controllers in child lifetime scopes (e.g., during a BeginLifetimeScope() call), you will need a controller provider from that scope or it won't get all the controller types. The provider needs to come from the scope that has all the registrations.
If you're using registration sources (like the AnyConcreteTypeNotAlreadyRegisteredSource), this won't capture things that come from the registration sources. It'll only capture things that come from direct registrations of a type (or lambda) on a ContainerBuilder.
But it should work.

Castle Windsor Lifestyle configuration

I've spent some time looking around, and there doesn't seem to be an obvious solution to this scenario.
I register all types from an assembly (that's about 80 types, interfaces are in separate assembly)
public static void RegisterAllFromAssemblies(string a)
{
IoC.Container.Register(
AllTypes.FromAssemblyNamed(a)
.Pick()
.WithService.FirstInterface()
.Configure(o => o.LifeStyle.PerWebRequest)
);
}
now say if i want to use a different LifeStyle for one of those objects, i can't override since i'll get the There is a component already registered for the given key error.
i've looked into various ways to modify the lifestyle after this registration, but so far haven't been able to make anything work.
what should be the ideal solution here? i'd prefer not to give up the AllTypes functionality.
i suppose i could specify a .Where filter when registering all and skip a few objects to be registered manually, but that's not a very enterprisey solution..
I believe you're talking about registering all of the types in an assembly where some of the types in the assembly might need to be registered with different lifestyles. So you've got IRepository which needs to be a PerWebRequest and ITypeMapper which can be a singleton.
I clarify because you could also mean that you want to have IRepository be a PerWebRequest at one spot in your code and a singleton in another spot. Without creating crazy lifestyles, you can create your component and register it for the default lifestyle. If you need another lifestyle sometimes you can create a new component and inherit from the existing one just for use in registration (the code sample shows this if this is confusing).
I wrote the sample so that it will work for either scenario and I gave a couple different approaches all focusing around the filtering abilities of configuring multiple items at once.
For this one, I'm calling out configuration for a particular component by type. It's not as "enerprisey" as you put it, but the intent is clearer if you only have a few exceptions to the rule. You'll note you can chain together configures. The unless is required because the second configure will pick up the component for the first configure being that my only condition is the services are based on IService. This assumes that castle processes the configures in order. I believe the assumption is sound, but haven't looked at the source for awhile.
container.Register(
Classes.FromThisAssembly()
.BasedOn<IService>()
.ConfigureFor<MyComponentAsSingleton>(component => component.LifestyleSingleton())
.Configure(component => component.LifestylePerWebRequest()).Unless(type => container.Kernel.GetAssignableHandlers(type).Count() > 0));
This one uses attributes to more generically deviate from the normal lifestyle "PerWebRequest
container2.Register(
Classes.FromThisAssembly()
.BasedOn<IService>()
.ConfigureIf(
//condition to check - do we have our custom Attribute?
registration => registration.Implementation.GetCustomAttributes(false).Any(attr => typeof(ShouldBeSingleton).IsAssignableFrom(attr.GetType())),
//if true register as singleton
component => component.LifestyleSingleton(),
//else register as per web request
component => component.LifestylePerWebRequest()
));
Now that I've given you a few samples that solve your immediate issue (as I understand it) let me give you my advice for free!
First I don't really like WithService.FirstInterface(). As the intelisense states it's non-deterministic when you implement multiple interfaces. Any dev could come in and make a harmless interface change to a class and then break the system. If you can get away with WithService.DefaultInterfaces() you'd have a harder to mess up solution. Default interfaces is just telling castle that when registering the Foo component, use the service IFoo if it implements an interface named IFoo.
Second, I believe if you partition your registration logic into cohesive units you probably wouldn't have run into this problem. The key is to have many installer files that implement IWindsorInstaller. Inside of these installers you only register (using the Classes or Types to keep it enterprisey still) types that make sense for the particular installer. The chances that you have multiple lifestyle concerns in the same installer is pretty low (and if you find this, you probably need more installers)
If you followed this approach you could end up with a RepositoryInstaller, ViewInstaller, ControllerInstaller, etc. More on installers can be found on the castle documentation site
What you could do if you wanted is then have a common boostrapper for all your systems that looks into the application directory and installs all of the installers that are in the directory. Being this wasn't what you asked I'll stop elaborating, but if interested you can ping me and I can show you more about what I'm talking about.
Full sample code as a console app:
using Castle.MicroKernel.Registration;
using Castle.Windsor;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace MultipleLifecyles
{
[AttributeUsage(AttributeTargets.Class)]
public class ShouldBeSingleton : Attribute
{
}
public interface IService
{
void DoSomething();
}
public class MyComponent : IService
{
public void DoSomething()
{
throw new NotImplementedException();
}
}
[ShouldBeSingleton]
public class MyComponentAsSingleton : MyComponent
{
}
class Program
{
static void Main(string[] args)
{
//option 1
IWindsorContainer container = new WindsorContainer();
container.Register(
Classes.FromThisAssembly()
.BasedOn<IService>()
.ConfigureFor<MyComponentAsSingleton>(component => component.LifestyleSingleton())
.Configure(component => component.LifestylePerWebRequest()).Unless(type => container.Kernel.GetAssignableHandlers(type).Count() > 0));
IWindsorContainer container2 = new WindsorContainer();
container2.Register(
Classes.FromThisAssembly()
.BasedOn<IService>()
.ConfigureIf(
//condition to check - do we have our custom Attribute?
registration => registration.Implementation.GetCustomAttributes(false).Any(attr => typeof(ShouldBeSingleton).IsAssignableFrom(attr.GetType())),
//if true register as singleton
component => component.LifestyleSingleton(),
//else register as per web request
component => component.LifestylePerWebRequest()
));
Console.ReadLine();
}
}
}
Is it an option for you register manually the exceptions first? If so, components manually registered will not be re-registered by "AllTypes"(I suggest you to use Classes instead).
If you register manually a component after a "group" registration, an exception will be thrown, but not vice versa.
For example
//YourImplementation lives in assembly 'a'
IoC.Container.Register(
Component.For<YourInterface>().ImplementedBy<YourImplementation>().LifestyleSingleton()
);
IoC.Container.Register(
Classes.FromAssemblyNamed(a)
.Pick()
.WithService.FirstInterface()
.Configure(o => o.LifeStyle.PerWebRequest)
);

Unity Registration: Hooking up an interface to a pre-registered concrete class

I already have a concrete class registered in my unity container and I want to, later on, register an interface that hooks up to that class but uses the existing registration.
I can do this using the following code but it causes a resolve at registration time...
container.RegisterInstance<IMyClass>(container.Resolve<MyClass>());
Is it possible to hook the code up with all resolution done at the point the interface is resolved?
The trick is to use an InjectionFactory:
container.Register<IMyClass>(
new InjectionFactory(c => c.Resolve<MyClass>()));
It sounds like you want to create a factory type. Here, a Func delegate type is used to avoid the creation of a new custom factory type:
container.RegisterInstance<Func<IMyClass>>(() => container.Resolve<MyClass>());
Your other types can then take a dependency on this factory:
private IMyClass myClass;
public MyOtherType(Func<IMyClass> myClassFactory)
{
this.myClass = myClassFactory();
}
IUnityContainer container = new UnityContainer();
var onlyInstance = new MyClass();
container.RegisterInstance<IMyClass>(onlyInstance);
IMyClass resolved = container.Resolve<IMyClass>();
if (object.ReferenceEquals(onlyInstance, resolved))
{
Console.WriteLine("Equal");
}
This prints "Equal". This is the way I would register the instance in the first place.
In a comment above, you imply that you do not control the initial registration. That's the real issue. I would recommend going down one of the following paths (in order of preference, highest to lowest):
Create your own UnityContainer independent of the pre-registered one
Create a child container with CreateChildContainer
Use named (non-default) mappings

MEF and two instances of the same class

How do I put two instances of the same class or interface into MEF? How would I retrieve them?
By default, any part registered with MEF uses a singleton strategy for lifetime management (one per container). This is specified with the default CreationPolicy of Shared. I think you need to be clear on exactly what you need...
Are you wanting a new instance each time you compose?
If so, you can add a PartCreationPolicyAttribute to your export:
[PartCreationPolicy(CreationPolicy.NonShared), Export(typeof(IFoo))]
public class Foo : IFoo { }
Any time you compose a class using your container, you'll get a new instance of Foo.
Are you wanting two independent instances at the same time?
You'll probably want to think of an alternative pattern for getting instances of your parts. You could use an ExportFactory which would allow you to create new instances when you need it, e.g:
[Import]
public ExportFactory<IFoo> Factory { get; set; }
With:
public IFoo CreateFoo()
{
return Factory.CreateExport().Value;
}
(To use ExportFactory<T> with non-Silverlight applications, you should download it here - ExportFactory<T> never made it into .NET 4, only Silverlight).