I have a Windsor service and two components implementing it: One being the "real" service, and one being a "proxy" (implemented as a decorator) that routes the call either to the "real" service, or to a webservice.
Now the ideal situation would be that if the proxy DLL was found, the proxy would be used as a decorator. And if it doesn't exist, all calls would go directly to the "real" service.
I'm currently using "FromAssembly.InDirectory" to register the components, and this works like a charm. However, I think this only works because the assemblies happen to be named in the correct alphabetic order, so that the "real" service is registered before the "proxy" (decorator). (Please correct me if I'm wrong.)
This doesn't look very robust to me. Is there a better way to do it without manually configuring every single component in a config file?
I'd either like a configuration file where I would only list the assemblies in the correct order, and all components from those files would be registered automatically (just like FromAssembly.Named).
Or - and that would be even better - some mechanism that automatically figures out which component is the decorator (after all, it has a dependency on the service it implements, whereas the "real" service doesn't), and which one is the "real service", and then automatically registers them in the correct order.
I could of course implement the latter logic myself, but I don't want to reinvent the wheel.
Any suggestions will be highly appreciated. Thank you!
Edit: This is what I have so far. How can I make sure the default component (the decorator, if there is one, the default component otherwise) gets named, so that the WCF facility can find it by its name? I mean, I could just add a "Named" call to the decorator part, but what if there are no decorators defined?
public void Install(IWindsorContainer container, IConfigurationStore store)
{
var currDomain = AppDomain.CurrentDomain;
var webAppBinDir = currDomain.RelativeSearchPath;
var assemblyDir = (!string.IsNullOrEmpty(webAppBinDir)) ? webAppBinDir : currDomain.BaseDirectory;
container.Register(
Classes.FromAssemblyInDirectory(new AssemblyFilter(assemblyDir, Mask))
.Where(ImplementsServiceContract)
.WithServiceSelect((x, y) => GetServices(x))
.ConfigureIf(IsDecorator, c => c.IsDefault(y => IsDecorating(c, y)))
);
}
private static bool ImplementsServiceContract(Type type)
{
return GetServices(type).Any();
}
private static IEnumerable<Type> GetServices(Type type)
{
return type.GetInterfaces().Where(IsServiceContract);
}
private static bool IsServiceContract(Type type)
{
var ns = type.Namespace;
return ns != null && ns.StartsWith(NamespacePrefix) && Attribute.IsDefined(type, typeof(ServiceContractAttribute));
}
private static bool IsDecorator(ComponentRegistration c)
{
Type component = c.Implementation;
return GetServices(component).Any(x => IsDecorating(c, x));
}
private static bool IsDecorating(ComponentRegistration c, Type service)
{
Type component = c.Implementation;
return service.Assembly != component.Assembly;
}