views:

63

answers:

2

I'm trying to get Property Injection working on a Custom Action Filter Attribute. It is working as it is supposed to, however, I'd like to use DI on the Property itself. My filter looks like this

[AttributeUsage(AttributeTargets.Class)]
public sealed class HeaderFilterAttribute : ActionFilterAttribute
{
    public IMarketService MarketService
    { get; set; }

    public override void OnActionExecuted(ActionExecutedContext filterContext)
    {
        var view = (ViewResultBase)filterContext.Result;

        if (view != null)
        {
            BaseViewModel viewModel = view.ViewData.Model as BaseViewModel;
            if (viewModel != null)
                viewModel.Header = GetHeaderScript();
        }
        base.OnActionExecuted(filterContext);
    }

   private string GetHeaderScript()
   {
     //Use MarketService here and return header script
     return "script";
   }
}

This is how I'm configuring the property using StructureMap inside my BootStrapper class.

            //HeaderFilterAttribute
        IMarketRepository marketRepository = new SqlMarketRepository();
        IMarketService marketService = new MarketService(marketRepository);
        ObjectFactory.Container.Configure(r => r.ForConcreteType<HeaderFilterAttribute>().
                                          Configure.WithProperty("MarketService").
                                          EqualTo(marketService));

My problem is I do not have access to SqlMarketRepository since all my concrete types are injected via DI and I really don't want to use concrete types in my bootstrapper. So the ultimate question now is, how do I inject MarketService into the Filter attribute without resorting to the above? :)

+1  A: 

In your ObjectFactory.Initialize() call, add the following line:

SetAllProperties(x => x.OfType<IMarketService>());

That will inject the configured IMarketService instance into any property of type IMarketService, on any object retrieved from the container.

Joshua Flanagan
That is exactly what I needed. This is simply awesome :) Thanks Josh!
Praveen
+1  A: 

I think you need a custom action invoker implementation that will resolve the filters. You can dig a Windsor sample out of my company's implementation (about 1/2 way down). There should be several more available online. I know I've seen some on this site.

PS. I noticed you're using a base view model to populate a header. I'd recommend using the ViewData[] collection with a static key instead of inheritance in your view model. :)

Ryan
@Ryan, I'm trying to stay away from the ViewData collection as much as I can :D. Any reason why a strong-type would be bad in this case?
Praveen
Because composition (via ViewData[]) allows you a lot more flexibility than inheritance of view models. Imagine if you later wanted to add more components (header, menus, sidebar, user profile widget, etc) to various pages. If you have to fit all that into your base view model it's going to get crowded and you probably won't even need everything on every view. I use the model purely for the specific view being rendered and then put my other components into ViewData. Sample view code: `var headerModel = ViewData[Constants.HeaderData] as HeaderViewModel`.
Ryan