This project is read-only.

Injecting properties into MVC views

Oct 11, 2013 at 12:51 PM
To support DI in MVC views I suggest adding to the SimpleInjector.Integration.Web.MVC package something like:
public class SimpleInjectorViewPageActivator
    : IViewPageActivator
{
    Container container;

    public SimpleInjectorViewPageActivator(Container container)
    {
        this.container = container;
    }

    public object Create(ControllerContext controllerContext, Type type)
    {
        var view = this.container.GetInstance(type);
        container.InjectProperties(view);
        return view;
    }
}
During the container init simply:
container.Register<IViewPageActivator, SimpleInjectorViewPageActivator>();
I personally use it together with:
container.Options.AutowirePropertiesWithAttribute<InjectAttribute>();
btw: Is there a reason why "AutowirePropertiesWithAttribute" is not directly included in the SimpleInjector assebmly but has to be copied from the documentation by the user? I think it is a rather useful to mark properties for injection with an attribute.

Just for reference: You can specify a custom page-base type in Web.config:
<configuration>
  <system.web.webPages.razor>
    <pages pageBaseType="YourPageBaseType">
...
Oct 12, 2013 at 12:19 PM
Injecting dependencies on views is typically a bad practice. Views should simply get all the data they need from the controller through the view model. When you start adding dependencies to views you are entering a slippery slope. You should keep your views as dumb as possible and prevent them from having any business logic and calls to services.

Because injecting dependencies on views is most of the time not the best thing to do, adding an IViewPageActivator to the integration package doesn't seem a good thing to do. Simple Injector tries to promote best practices by omitting features, and proving such implementation out of the box does the opposite. Besides, plugging your own is easy enough, as you've already shown.

One note about your implementation though. The AutowirePropertiesWithAttribute from the documentation makes use of the IPropertySelectionBehavior interface. This allows property injection that is deeply integrated with the framework. The Container.InjectProperties on the other hand is a legacy method from v1 and it doesn't integrate with IPropertySelectionBehavior and the rest of the framework. It does implicit property injection (skips properties that can't be found without throwing) and injected properties don't show up in the Diagnostic Services. Prefer not to use implicit property injection (especially using the InjectProperties method) if possible. That means that the IViewPageActivator.Create metod can simply look like this:
    public object Create(ControllerContext controllerContext, Type type)
    {
        return this.container.GetInstance(type);
    }
If implicit property injection is really needed (which should be very unlikely), you can always register a custom IPropertySelectionBehavior that specifically enables implicit property injection for a certain set of types (such as MVC views).

>> btw: Is there a reason why "AutowirePropertiesWithAttribute" is not directly included in the SimpleInjector assembly

The design strategy of Simple Injector is to include a sensible set of operations that push developers into using best practices, but to support extendibility. In most cases developers should prefer using constructor injection instead of property injection. When they feel the need to fall back to property injection, in many cases there's a problem with the design. For this reason property injection is not supported out of the box, but extension is possible using the IPropertySelectionBehavior interface. Simple Injector not only tries to make it possible, but tries to make it easy to extend the framework by supplying a lot of code samples in the documentation (and in the CodeSamples project in source control). But by explicitly not including these features in the framework itself we try to communicate best practices.
Marked as answer by dot_NET_Junkie on 3/2/2014 at 11:04 AM
Oct 12, 2013 at 2:06 PM
Edited Oct 12, 2013 at 2:14 PM
Thank you very much for taking the time to write such an extensive answer!
Injecting dependencies on views is typically a bad practice. Views should simply get all the data they need from the controller through the view model. (..)
The main objects I am injecting in the views of my MVC app are localization support (e.g. a string table) and special string processing (e.g. macro expansion) objects. I do not consider them part of the business logic since their sole role is to help formatting the documents back to the client. I could get all strings for a view in the controller or pass the required interfaces as part of the model to the view but I am not convinced that this would be "better design" because it would require much more work and would be inconvenient for the view-developer.
One note about your implementation though. The AutowirePropertiesWithAttribute from the documentation makes use of the IPropertySelectionBehavior interface. (..)
OK - thanks a lot for pointing this out! Sorry, for whatever reason I had the misconception that 'implicit property' injection would still require an explicit call to InjectProperties. It is great that no explicit call is required at all.
The Container.InjectProperties (..) is a legacy method from v1 and it doesn't integrate with IPropertySelectionBehavior and the rest of the framework.
It would be great if you included a tiny hint about the legacy status of InjectProperties in the <summary/> documentation. Maybe it is only me who has not spent enough time reading the (btw fantastic) SimpleInjector documentation .. but it would probably reduce the chance of a wrong usage that I did.
If implicit property injection is really needed (which should be very unlikely), you can always register a custom IPropertySelectionBehavior that specifically enables implicit property injection for a certain set of types (such as MVC views).
I think the documentation has very useful samples for constructor selection and property injection! I wish you would include them in compiled form in the simple-injector assembly - for examle in a saparate namespace. They offer a very wide range of different use-cases and since their usage always is an opt-in model it would be of no harm to anybody. At least for everybody who used other DI-frameworks before who has a code base (e.g. with multiple public ctors) such tools can be a great help!
(..) In most cases developers should prefer using constructor injection instead of property injection. When they feel the need to fall back to property injection, in many cases there's a problem with the design.(..)
I absolutely agree on this. Some people might praise property injection because it does no require to pass down a long list of interfaces to base classes but I think there are probably different solutions for this problem and I always was happy to be able to have one single place (the ctor) where I have a clear list of all dependencies.

Nevertheless I currently have two places where I am not able to use ctor-injection in my MVC app: a) For the base class of my razor views and b) for the application class in global.asax.cs.

Regarding the Application class: With simple injector I am currently doing the initialization of additional instances of the Application class (on which Application_Start() is not called) using a static field holding the container (set in the one instance on which Application_Start() is called). For previous prjs I used ninject - its extension module supported the property injection into the application objetcs (I guess using a HttpModule?). I agree that accessing properties of an Application instance in controllers or in views (e.g. with HttpContext.ApplicationInstance) is very bad practice and therefore injecting something in public properties of an Application object might encourage this anti-pattern .. but at least it was quite simple to get instances form the container for use in the Application class. The static field that I am using currently does at least not 'feel' better.
Oct 12, 2013 at 2:48 PM
Edited Oct 12, 2013 at 6:45 PM
One question regarding the performance impact of property injection. I saw als long as th Default selection behavior is in place the iteration over the properties of a type is skipped (Registration.cs, ln 192).
            if (this.Container.Options.PropertySelectionBehavior is DefaultPropertySelectionBehavior)
            {
                // Performance tweak. DefaultPropertySelectionBehavior never injects any properties.
                return expressionToWrap;
            }
Is it correct that even with a custom selection policy configured the property selection is done only once per type (e.g. when the instance creator delegate expression is build)? Thus if during the container lifetime multiple instances of that type are requested the injection into the previously selected properties takes place directly without consulting the PropertySelectionBehavior again?
Oct 12, 2013 at 7:05 PM
> It would be great if you included a tiny hint about the legacy status of InjectProperties in the <summary/> documentation.

Good point. I will.

> I wish you would include them in compiled form in the simple-injector assembly - for example in a separate namespace.

I'm against doing this, because I don't want to promote. But anyone is free to start a Simple Injector Contrib project, and I would even contribute to this myself and give maintainers of such project any feedback. But for me its important that users know this is not an official library.

> Is it correct that even with a custom selection policy configured the property selection is done only once per type

Almost. Not once per type, but once per registration. The same type could be registered multiple times in the same container, or even in multiple containers. The performance tweak is meant to prevent the container from reflecting over all properties of all types in the container, when no custom property selection behavior is registered. So there will be an extra performance hit when you register custom behavior, but this is purely a one-time initialization cost. Once the expression of a registration is created it is cached and compiled to a Func<T> delegate and the property selection behavior won't be hit again.

> if ... lifetime multiple instances of that type are requested the injection into the previously selected
> properties takes place directly without consulting the PropertySelectionBehavior again?

Correct. It would be impossible for Simple Injector to be this fast if it didn't optimize this :-)