Josh
Josh

Reputation: 2790

Can Autofac inject dependencies into layout view files?

I'm trying to inject a dependency into the shared layout view page to avoid having to do it in every view that uses the layout.

I've followed the guidance in the wiki for injecting dependencies into views, but the property is always null.

Can Autofac inject properties into a custom view page that is a layout file?

Here's my setup. CustomViewPage

namespace MyApp
{
    using System.Web.Mvc;

    public abstract class CustomViewPage : WebViewPage
    {
        public IHelper Helper { get; set; }
    }
}

~/Views/Shared/_Layout.cshtml

@inherits MyApp.CustomViewPage
<!DOCTYPE html>
<html>
...
@if(this.Helper.HasFoo()){@Html.ActionLink("Bar")}

Global Registration...

builder.RegisterType<Helper>().AsImplementedInterfaces();
builder.RegisterModelBinderProvider();
builder.RegisterFilterProvider();
builder.RegisterModule(new AutofacWebTypesModule());
builder.RegisterSource(new ViewRegistrationSource());
var container = builder.Build();
DependencyResolver.SetResolver(new AutofacDependencyResolver(container));

The "child" views that use the layout do NOT derive from the CustomViewPage.

Upvotes: 18

Views: 6895

Answers (5)

Pavel
Pavel

Reputation: 554

Just create partial page and insert it into layout page:

@Html.Partial("_MyPartialPage");

Dependencies are injected into partial pages.

Upvotes: 1

Lapenkov Vladimir
Lapenkov Vladimir

Reputation: 3218

For result with no parameters you don't need to extend your WebViewPage to pass data to. I would solve it this way: 1. Declare a class HelperActionFilter derived from ActionFilter, inject your service to it via property http://docs.autofac.org/en/latest/integration/mvc.html 2. Inside HelperActionFilter.OnActionExecuting setup ViewBag.HasFoo check it in layout.

Upvotes: 0

Stan
Stan

Reputation: 1999

Most of solutions will be just a wrapper around DependencyResolver.Current.GetService call, so it might be easier to call it directly from layout:

@{
    var helper = DependencyResolver.Current.GetService<IHelper>();
}
...
@if (helper.HasFoo()) { @Html.ActionLink("Bar") }
...

Also this way helps to make page model more SRP, because can avoid mixing service routines/models and business ones.

Upvotes: 25

shenku
shenku

Reputation: 12468

Here is a little work around that will work with most DI frameworks.

First adjust you CustomPageView a little bit:

public abstract class CustomViewPage : WebViewPage
{
    public IHelper Helper { 
        get { return ViewData[Helper.ViewDataKey] as IHelper; }    
    }

}

Now well need to get the dependancy into your ViewData, introduce an attribute to do this:

public sealed class HelperAttribute : ActionFilterAttribute
{
    public override void OnResultExecuting(ResultExecutingContext filterContext)
    {
        var viewResult = filterContext.Result as ViewResult;
        if (viewResult != null)
            viewResult.ViewData.Add(Helper.ViewDataKey, GetHelperFromIoC());

        base.OnResultExecuting(filterContext);
    }
}

On you action method or controller:

[Helper]
public ActionResult Index()
{
    return View();
}

And in your view you should now be able to use your Helper as expected:

 @Helper.HelloWorld()

See this blog for the original post.

Upvotes: 1

VJAI
VJAI

Reputation: 32768

It's not only with AutoFac basically you can't achieve DI in layouts. You may need a reference to the IOC Container in CustomViewPage to resolve the dependencies.

Unless it's REALYYY REQUIRED just avoid DI in views (just my opinion).

From my point of view I don't see much benefits. I think you are not going to write unit tests for the base view page class do you? unless there is any special reason just avoid it. Instead of having dependency with the container it's better to have dependencies with concrete implementations.

Upvotes: 0

Related Questions