2

I'm creating an ASP.NET MVC 3 application trying to take advantage of controller action injection as described here.

Controller constructor injection works without any issues, but I can't seem to get action injection to work.

I've set up Autofac in Global.asax like this:

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 an action like this:

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 navigate to the the Test action, I see this error:

Server Error in '/' Application.

Cannot create an instance of an interface.

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

Exception Details: System.MissingMethodException: Cannot create an instance of an interface.

Source Error:

An unhandled exception was generated during the execution of the current web request. Information regarding 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'm using Autofac version 2.4.5.724.

Thanks.

4

2 回答 2

7

当前 Autofac MVC3 实现中默认关闭动作注入。

要启用它,请将参数传递给ExtensibleActionInvoker

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

这是最近的一次更改,一些文档需要更新 - 很抱歉给您带来麻烦。

于 2011-03-25T04:12:41.337 回答
0

问题是这条线

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

Register任何方法中的第一个参数是您要注册的具体服务。在该类型之后是“如何实例化”,然后是定义实际接口以将服务公开为的参数。你得到了异常,因为 Autofac 试图实例化实现,在上面的例子中是一个接口。显然,在接口类型上找不到构造函数。

现在看看这个:

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

与其他 DI 框架相比,这种方法 IMO 是 Autofacs 的优势之一。其他人从您要公开的接口开始注册并以实现结束,而 Autofac 从实际实现开始并以接口结束。这使得语法更清晰,特别是在一个具体实现可以作为多个接口公开的情况下,所有这些都在一个注册中。

于 2011-03-24T22:10:41.813 回答