Castle Windsor: Set component dependencies on existing object
In MEF it's possible to set the dependencies for an existing object using something like:
contain开发者_JS百科er.SatisfyImportsOnce(instance);
Is it possible to do the same with Castle Windsor?
I'm using (read: learning) Caliburn.Micro, and trying to update the template project from MEF to Windsor, which is where I've come across the issue.
Sorry Neil, Windsor doesn't have that feature
Castle Windsor FAQ
Windsor will resolve a property dependency (which it considers an optional dependency) such as an ILogger property if there is a registered component for that service. But this only happens during component activation...when the component is constructed the first time, there is no way to pass Windsor an existing instance and inject components into properties.
With Castle Windsor you can register an existing instance with the container, is this the kind of thing you are looking for?
var instance = new Logger();
var container = new WindsorContainer();
container.Register(Component.For<ILogger>().Instance(instance))
where
public interface ILogger
{
void LogException(Exception ex);
}
public class Logger : ILogger
{
public void LogException(Exception ex)
{
// Log exception
}
}
You can however code this functionality yourself. For example, here is an ASP.NET MVC FilterAttributeFilterProvider, used to inject proprties onto attribute action filters.
public class AttributeFilterProvider : FilterAttributeFilterProvider
{
public AttributeFilterProvider(IKernel kernel)
{
_kernel = kernel;
}
private readonly IKernel _kernel;
protected override IEnumerable<FilterAttribute> GetControllerAttributes(ControllerContext controllerContext, ActionDescriptor actionDescriptor)
{
var attributes = base.GetControllerAttributes(controllerContext, actionDescriptor);
BuildUpAttributeDependancies(attributes);
return attributes;
}
protected override IEnumerable<FilterAttribute> GetActionAttributes(ControllerContext controllerContext, ActionDescriptor actionDescriptor)
{
var attributes = base.GetActionAttributes(controllerContext, actionDescriptor);
BuildUpAttributeDependancies(attributes);
return attributes;
}
private void BuildUpAttributeDependancies(IEnumerable<FilterAttribute> attributes)
{
foreach (var attribute in attributes)
{
var propInfos = attribute.GetType().GetProperties().Where(x => x.GetValue(attribute) == null).AsEnumerable();
foreach (var pi in propInfos)
{
if (_kernel.HasComponent(pi.PropertyType))
{
var service = _kernel.Resolve(pi.PropertyType);
pi.SetValue(attribute, service);
}
}
}
}
}
In the BuildUpAttributeDependancies method, we look for un-initialised (null) properties, and then check to see if the type has been registered with Castle Windsor. If it has, we set the property.
By replacing the default FilterAttributeFilterProvider with our custom one (above) in the global.asax file we can now use Castle Windsors DI features to inject any type onto any Action Filter in our MVC application. To complete this answer fully, here is an example of a global.asax application class with Castle Windsor setup for both Controller (at instantiation time) and ActionFilter (at usage time) dependancy injection:
public class MvcApplication : System.Web.HttpApplication
{
private static IWindsorContainer _container;
private static void BootstrapContainer()
{
_container = new WindsorContainer()
.Install(FromAssembly.This());
var controllerFactory = new ControllerFactory(_container.Kernel);
ControllerBuilder.Current.SetControllerFactory(controllerFactory);
}
private static void BootstrapFilters()
{
var oldProvider = FilterProviders.Providers.Single(f => f is FilterAttributeFilterProvider);
FilterProviders.Providers.Remove(oldProvider);
var provider = new AttributeFilterProvider(_container.Kernel);
FilterProviders.Providers.Add(provider);
}
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
WebApiConfig.Register(GlobalConfiguration.Configuration);
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
RouteConfig.RegisterRoutes(RouteTable.Routes);
BundleConfig.RegisterBundles(BundleTable.Bundles);
BootstrapContainer();
BootstrapFilters();
}
}
精彩评论