6

I'm trying to get dependency injection working in an ASP.NET MVC 3 application using Microsoft Unity. First i have implemented my own IDependencyResolver and activated it in my Global.asax file like so:

DependencyResolver.SetResolver(new UnityDependencyResolver(container));

I found that i don't need to do anything else to get controller injection (via both the constructor and [Dependency] attribute) to work. With the default view engine i also found i could get the [Dependency] attribute to work in the standard views but not the Layout views. Is it possible to get this to work for the Layout Views aswell?

However i have implemented my own view engine which inherits from VirtualPathProviderViewEngine that overrides the CreateView/CreatePartialView methods and returns my own custom view (implements IView). See the Render method of the custom view below:

public void Render(ViewContext viewContext, TextWriter writer) {
    var webViewPage = DependencyResolver.Current.GetService(_type) as WebViewPage;
    //var webViewPage = Activator.CreateInstance(_type) as WebViewPage;

    if (webViewPage == null)
        throw new InvalidOperationException("Invalid view type");

    webViewPage.VirtualPath = _virtualPath;
    webViewPage.ViewContext = viewContext;
    webViewPage.ViewData = viewContext.ViewData;
    webViewPage.InitHelpers();

    WebPageRenderingBase startPage = null;

    if (_runViewStartPages)
        startPage = StartPage.GetStartPage(webViewPage, "_ViewStart", _viewStartFileExtensions);

    var pageContext = new WebPageContext(viewContext.HttpContext, webViewPage, null);
    webViewPage.ExecutePageHierarchy(pageContext, writer, startPage);
}

With the commented out line i completely lost dependency injection within my views so i changed it to the line above which again works fine for the standard views but not for the Layout views. I'd appreciate it if you could show me how the above could be modified to work for the Layout views aswell?

Finally i'm trying to get action filter injection working aswell. I have found two different cases:

  1. Apply the filter to the action via an attribute.

  2. Defining it as a global filter, e.g.:

    GlobalFilters.Filters.Add(new TestAttribute());

Neither seem to use the dependency resolver. Therefore i need to do some extra work. Please correct me if there's a better way. To enable the first scenario i did the following:

public class UnityFilterAttributeFilterProvider : FilterAttributeFilterProvider {
    private IUnityContainer _container;

    protected override IEnumerable<FilterAttribute> GetControllerAttributes(ControllerContext controllerContext, ActionDescriptor actionDescriptor) {
        var attributes = base.GetControllerAttributes(controllerContext, actionDescriptor);

        foreach (var attribute in attributes) {
            _container.BuildUp(attribute.GetType(), attribute);
        }

        return attributes;
    }

    protected override IEnumerable<FilterAttribute> GetActionAttributes(ControllerContext controllerContext, ActionDescriptor actionDescriptor) {
        var attributes = base.GetActionAttributes(controllerContext, actionDescriptor);

        foreach (var attribute in attributes) {
            _container.BuildUp(attribute.GetType(), attribute);
        }

        return attributes;
    }
}

And then defined this within my Global.asax file like so:

FilterProviders.Providers.Remove(FilterProviders.Providers.Single(f => f is FilterAttributeFilterProvider));
FilterProviders.Providers.Add(new UnityFilterAttributeFilterProvider(container));

This works fine but i was wondering if this is the correct way to do it? To resolve the second case i simply changed where i defined my global filter to the following:

GlobalFilters.Filters.Add(DependencyResolver.Current.GetService<TestAttribute>());

This again now works but is this the correct way to do it?

I'd appreciate the help. Thanks

4
  • It appears that .Net 4 doesn't provide ASP.NET MVC the hooks to inject the dependencies into the layout pages. The solution to the filter attributes appears to be working fine but you may wish to inject the global dependencies better by overriding the GetFilters method of the FilterAttributeFilterProvider class and injecting the dependencies similar to how it is done in the other 2 methods. Commented Jun 19, 2012 at 14:54
  • 1
    Dont use the Dependency Resolver it is broken. Stick with constructor injection. Commented Aug 6, 2012 at 16:30
  • To answer your question is this the correct way to do it? I would not do it that way. Commented Aug 6, 2012 at 16:31
  • 1
    Constructor injection is not an option with views. Commented Apr 24, 2014 at 20:20

1 Answer 1

0

It's been a while since I originally asked this but I thought I would share what I ended up doing.

In cases where I could not use constructor or attribute injection I solved it by using the DependencyResolver (service locator pattern). For example if I require the service IService I would simply inject it like so:

public IService Service => DependencyResolver.Current.GetService<IService>();

While some may consider this an anti-pattern I have found this performs well, leads to less problems and with new advances in C# I don't think it looks too bad.

However if you are using ASP.NET Core you should never have to use the service locator pattern as it has been rebuilt with dependency injection at the heart of it.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.