plankalkul plankalkul - 1 month ago 23
ASP.NET (C#) Question

ASP.NET Autofac Singleton running twice constructor injection

I'm not sure if my expectations are wrong. I am using ASP.NET MVC (not core) and Autofac. I have an image that appears on every page of my website, and I have created a service to return a random image name like so

INTERFACE

public interface IBreadCrumbImage
{
string GetImage();
}


CLASS (snipped for brevity)

public class BreadCrumbImage : IBreadCrumbImage
{
public string GetImage()
{
return ImageUrl;
}
}


GLOBAL.ASAX.CS (Autofac registration)

protected void Application_Start()
{
var builder = new ContainerBuilder();
builder.RegisterControllers(typeof(MvcApplication).Assembly);
builder.RegisterType<BreadCrumbImage>().As<IBreadCrumbImage>().SingleInstance();
var container = builder.Build();
DependencyResolver.SetResolver(new AutofacDependencyResolver(container));
}


CONTROLLER

public class HomeController : Controller
{
private IBreadCrumbImage _breadCrumbImage;

public ActionResult Index(BreadCrumbImage breadCrumbImage)
{
_breadCrumbImage = breadCrumbImage;
var x = _breadCrumbImage.GetImage();
ViewBag.BreadCrumbImage = "/img/BreadCrumbs/" + x;
return View();
}
}


All of this works, and I get my IMAGE showing up random.. however, setting breakpoints, this BreadCrumbImage service is being instantiated every time it is accessed. I'd like to have this instantiated once (the loading of the images is done in the constructor of BreadCrumbImage, it reads files and puts them into an array -- no need to do that more than once on app startup, and the GetImages just grabs rnd from array).

Am I registering this wrong with the SingleInstance, or does this just not work as I'm expecting it to and I'm going to have to have some base resolver that's tied to the builder that's created in Global.asax.cs?

UPDATE: Answer, thank you Travis. Needed to put this in to the autofac configuration, and everything worked like a charm.

builder.RegisterType<ExtensibleActionInvoker>()
.As<IActionInvoker>()
.WithParameter("injectActionMethodParameters", true);

Answer

Looking at the controller you provided, you're not using constructor injection. The Index method is an action method, not a constructor. Further, it's asking for a BreadCrumbImage not an IBreadCrumbImage.

If you look at the call stack from your breakpoints, I'm guessing you're going to see MVC model binding going on instantiating that BreadCrumbImage, not Autofac. I don't see anywhere in your Autofac setup that you're using the action parameter injection mechanism, and if you were you'd still see MVC model binding in the call stack because you didn't register BreadCrumbImage as itself - you registered it as IBreadCrumbImage so that's the only thing Autofac will resolve it as. You won't be able to resolve the concrete BreadCrumbImage out of the container using the registrations you're showing.

Comments