2

In MEF it's possible to set the dependencies for an existing object using something like:

container.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.

Neil Barnwell
  • 41,080
  • 29
  • 148
  • 220
  • possible duplicate of [Resolving classes without registering them using Castle Windsor](http://stackoverflow.com/questions/447193/resolving-classes-without-registering-them-using-castle-windsor) – Mauricio Scheffer Nov 26 '10 at 02:16
  • isn't this more like the `container.BuildUp` functionality from Unity, thus duplicating http://stackoverflow.com/questions/851940/windsor-castle-injecting-properties-of-constructed-object ? – mookid8000 Nov 26 '10 at 07:10
  • 2
    Jeez. How is it I look for existing questions, don't find any, then half a dozen people show me duplicates when I eventually raise my own? Oh well, thanks for the links, sorry for the duplicate. – Neil Barnwell Nov 26 '10 at 09:24

3 Answers3

2

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
  }
}
Rohan West
  • 9,262
  • 3
  • 37
  • 64
2

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.

  • actually, I consider Windsor not having this to be a feature. Kind of like the IPhone's not-support for Flash is a feature. It's bad, don't do it. – Krzysztof Kozmic Jan 10 '11 at 11:02
  • @Krzysztof Yeah I totally agree - I prefer Windsor to manage the lifetime of the components it creates. I was only asking because there's a method in Caliburn.Micro that in the sample app uses StructureMap to resolve the dependencies of an object StructureMap didn't necessarily create. I'm a Castle Windsor fanboy though so I wanted to use CW in my own app, hence looking for an equivalent. – Neil Barnwell Jan 25 '11 at 09:44
1

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();
  }
}
BlackSpy
  • 5,563
  • 5
  • 29
  • 38
  • This should be the accepted answer. I like a "No you can't do it, but here's how". :) I knew I had done this before somewhere and when seeing your answer remembered that it was an attribute I was injecting into. Bad practice probably having attributes too intelligent, hides code as well. But if it wasn't for that I wouldn't have known how to do property injection on already constructed objects, something that is needed when working with an old code base when gradually introducing a container. – Aran Mulholland Mar 13 '17 at 08:33