Как сделать инъекцию действия для MVC 3 с помощью Autofac?
Я создаю ASP.NET приложение MVC 3 пытается воспользоваться впрыском действия контроллера, как описано здесь .
Инъекция конструктора контроллера работает без каких-либо проблем, но я не могу заставить инъекцию действия работать.
Я настроил Autofac в Global.asax вот так:
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));
И мой контроллер имеет такое действие:
public ActionResult Test(ITestInject testInject)
{
return View(testInject);
}
Класс/интерфейс TestInject/ITestInject определяется следующим образом:
public interface ITestInject
{
string TestString { get; }
}
public class TestInject : ITestInject
{
public string TestString { get; set; }
}
Когда я пытаюсь перейдите к действию тест, я вижу эту ошибку:
Ошибка сервера в приложении"/".
невозможно создать экземпляр интерфейса.
Описание: необработанное исключение возникло во время выполнения текущего веб-запроса. Пожалуйста, просмотрите трассировку стека для получения дополнительной информации об ошибке и о том, где она возникла в коде.
Детали Исключения: Система.MissingMethodException: не удается создать экземпляр взаимодействие.
Ошибка Источника:
Необработанное исключение было сгенерировано во время выполнения текущего веб-запроса. Информацию о происхождении и местоположении исключения можно определить с помощью трассировки стека исключений, приведенной ниже.
Трассировка Стека:
[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
Сведения о версии: Microsoft .NET Framework версия: 4.0.30319; ASP.NET версия: 4.0.30319.1
Какие-нибудь идеи о том, что я делаю неправильно здесь?
Я использую Autofac версии 2.4.5.724.
Спасибо.
2 ответов:
Впрыск действия выключен по умолчанию в текущей реализации Autofac MVC3.
Чтобы включить его, передайте параметр в
ExtensibleActionInvoker:builder.RegisterType<ExtensibleActionInvoker>() .As<IActionInvoker>() .WithParameter("injectActionMethodParameters", true);Это было совсем недавнее изменение, и некоторые документы нуждаются в обновлении-извините за хлопоты.
Проблема в этой строке
builder.Register<ITestInject>(c => new TestInject { TestString = "hi" });Первым параметром в любом методе
Registerявляетсяконкретный сервис , который вы хотите зарегистрировать. За этим типом следует "как создать экземпляр", а затем параметры, определяющие фактический интерфейс для предоставления сервиса в качестве. Вы получаете исключение, потому что Autofac пытается создать экземпляр реализации, которая в приведенном выше случае является интерфейсом. Очевидно, что никакой конструктор не найден на интерфейсном типе.Теперь посмотрите на это:
builder.Register<TestInject>(c => new TestInject { TestString = "hi" }).As<ITestInject>();Этот подход IMO является одной из сильных сторон Autofacs по сравнению с другими системами DI. Там, где другие начинают регистрацию с интерфейса, который вы хотите предоставить, и заканчивают реализацией, Autofac начинается с фактической реализации и заканчивается интерфейсом. Это делает синтаксис более чистым, особенно в тех случаях, когда одна конкретная реализация может быть представлена в виде нескольких интерфейсов, все в одной регистрации.
Comments