How to inject action for MVC 3 using Autofac?

I am creating an ASP.NET MVC 3 application trying to use controller action injection, as described here .

Embedding a controller constructor works without any problems, but I cannot get action injections to work.

I installed Autofac in Global.asax as follows:

var builder = new ContainerBuilder(); builder.Register<ITestInject>(c => new TestInject { TestString = "hi" }); builder.RegisterType<ExtensibleActionInvoker>().As<IActionInvoker>(); builder.RegisterControllers(typeof(MvcApplication).Assembly).InjectActionInvoker(); var container = builder.Build(); DependencyResolver.SetResolver(new AutofacDependencyResolver(container)); 

And my controller has the following action:

 public ActionResult Test(ITestInject testInject) { return View(testInject); } 

The TestInject / ITestInject class / interface is defined as:

 public interface ITestInject { string TestString { get; } } public class TestInject : ITestInject { public string TestString { get; set; } } 

When I try to proceed to the test action, I see this error:

Server error in application "/".

Unable to instantiate interface.

Description: An unhandled exception occurred during the execution of the current web request. Check the stack trace for more information about the error and where it appeared in the code.

Exception Details: System.MissingMethodException: Unable to instantiate interface.

Source Error:

An unhandled exception was thrown during the execution of the current web request. Information about the origin and location of the exception can be identified using the exception stack trace below.

Stack trace:

  [MissingMethodException: Cannot create an instance of an interface.]
    System.RuntimeTypeHandle.CreateInstance (RuntimeType type, Boolean publicOnly, Boolean noCheck, Boolean & canBeCached, RuntimeMethodHandleInternal & ctor, Boolean & bNeedSecurityCheck) +0
    System.RuntimeType.CreateInstanceSlow (Boolean publicOnly, Boolean skipCheckThis, Boolean fillCache) +98
    System.RuntimeType.CreateInstanceDefaultCtor (Boolean publicOnly, Boolean skipVisibilityChecks, Boolean skipCheckThis, Boolean fillCache) +241
    System.Activator.CreateInstance (Type type, Boolean nonPublic) +69
    System.Web.Mvc.DefaultModelBinder.CreateModel (ControllerContext controllerContext, ModelBindingContext bindingContext, Type modelType) +199
    System.Web.Mvc.DefaultModelBinder.BindComplexModel (ControllerContext controllerContext, ModelBindingContext bindingContext) +572
    System.Web.Mvc.DefaultModelBinder.BindModel (ControllerContext controllerContext, ModelBindingContext bindingContext) +449
    System.Web.Mvc.ControllerActionInvoker.GetParameterValue (ControllerContext controllerContext, ParameterDescriptor parameterDescriptor) +317
    Autofac.Integration.Mvc.ExtensibleActionInvoker.GetParameterValue (ControllerContext controllerContext, ParameterDescriptor parameterDescriptor) +122
    System.Web.Mvc.ControllerActionInvoker.GetParameterValues ​​(ControllerContext controllerContext, ActionDescriptor actionDescriptor) +117
    System.Web.Mvc.ControllerActionInvoker.InvokeAction (ControllerContext controllerContext, String actionName) +343
    System.Web.Mvc.Controller.ExecuteCore () +116
    System.Web.Mvc.ControllerBase.Execute (RequestContext requestContext) +97
    System.Web.Mvc.ControllerBase.System.Web.Mvc.IController.Execute (RequestContext requestContext) +10 
    System.Web.Mvc.  < > c_DisplayClassb.  < BeginProcessRequest> b_5 () +37
    System.Web.Mvc.Async.  < > c_DisplayClass1.  < MakeVoidDelegate> b_0 () +21
    System.Web.Mvc.Async.  < > c_DisplayClass8`1.  < BeginSynchronous> b_7 (IAsyncResult) +12
    System.Web.Mvc.Async.WrappedAsyncResult`1.End () +62
    System.Web.Mvc.  < > c_DisplayClasse.  < EndProcessRequest> b_d () +50
    System.Web.Mvc.SecurityUtil.  < GetCallInAppTrustThunk> b_0 (Action f) +7
    System.Web.Mvc.SecurityUtil.ProcessInApplicationTrust (Action action) +22
    System.Web.Mvc.MvcHandler.EndProcessRequest (IAsyncResult asyncResult) +60
    System.Web.Mvc.MvcHandler.System.Web.IHttpAsyncHandler.EndProcessRequest (IAsyncResult result) +9
    System.Web.CallHandlerExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute () +8841105
    System.Web.HttpApplication.ExecuteStep (IExecutionStep step, Boolean & completedSynchronously) +184

Version Information: Microsoft.NET Framework Version: 4.0.30319; ASP.NET Version: 4.0.30319.1

Any ideas on what I'm doing wrong here?

I am using Autofac version 2.4.5.724.

Thanks.

+2
source share
2 answers

In the current implementation of Autofac MVC3, the default action is disabled by default.

To enable it, pass the ExtensibleActionInvoker parameter:

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

This was a fairly recent change, and some documents need updating - sorry for the trouble.

+7
source

The problem is this line

 builder.Register<ITestInject>(c => new TestInject { TestString = "hi" }); 

The first parameter in any Register method is the specific service that you want to register. After this type, β€œhow to create an instance” appears, and then parameters that define the actual interface for providing the service as. You get an exception because Autofac tries to create an instance of the implementation, which in this case is an interface. Obviously, no constructor was found in the interface.

Now look at this:

 builder.Register<TestInject>(c => new TestInject { TestString = "hi" }).As<ITestInject>(); 

This IMO approach is one of Autofacs strengths over other DI frameworks. When others start registering with the interface you want to expose, and ending with the implementation, Autofac starts with the actual implementation and ends with the interface. This makes the syntax clearer, especially in cases where one particular implementation can be displayed as several interfaces, all in one registration.

0
source

All Articles