1

在使用参数接口时,我遇到了 Autofac ExtensibleActionInvoker 与 MVC ModelBinder 交互的问题。背景如下:

我正在构建一个 MVC 应用程序,我正在使用 Autofac MVC3 的 ExtensibleActionInvoker 将我的服务作为参数注入到我的操作中,例如

    public ActionResult Test( IMyService service)
    {
        //A new instance of service is created by Autofac ExtensibleActionInvoker 
        return View();
    }

这非常有效,并且设计非常简洁(有关此方法的更多信息,请参阅Alex Meyer-Gleaves 帖子)。我想使用这种方法,因为我正在生成代码生成器来创建操作、视图、服务和 DTO,而按操作服务方法使这更容易。

但是,我还想为从 HttpPost 操作接收输入的操作分类中的参数使用接口。这是因为我使用 DI 在每一层之外创建类。如果我将 DefaultModelBinder 更改为使用 DI 创建类(请参阅 Steve Sanderson 关于 MVC3 的书的第 595 页,了解如何执行此操作),这可以正常工作,例如

    [HttpPost]
    public ActionResult Test(ITestClass dataComingFromView)
    {
        //model binder creates the class via DI and then binds it to the data from the post
        return View();
    }

但是在上面的简单示例中,我与启用的 ExtensibleActionInvoker 发生冲突,即

  1. 在没有启用 ExtensibleActionInvoker 的情况下,上面的方法可以正常工作,即扩展的 DefaultModelBinder 使用 DI 创建 TestClass 类,并且 modelbinder 将来自视图的输入绑定到类中的字段。
  2. 启用 ExtensibleActionInvoker 后它不起作用,即我得到一个没有绑定的空 TestClass 类。我假设 ExtensibleActionInvoker 优先于模型绑定器,并且只创建一个空的 TestClass 类。
  3. (为了完整起见,我应该说,如果我只是“开箱即用”地使用 MVC,即没有新的 DefaultModelBinder 并且没有启用 ExtensibleActionInvoker,那么它说你不能使用接口作为 Action 方法参数。)

对于比我有更好 Autofac 知识的人,我的问题是:我可以更改 Autofac ExtensibleActionInvoker 以选择它绑定的内容吗?我所有注入的服务类都以 IService 开头,因此我可以对其进行过滤。我知道您可以在其他地方的 Autofac 中执行此操作,但无法使用 ExtensibleActionInvoker 执行此操作,但也许我错过了。

任何帮助,将不胜感激。

Jon Smith - 选择性分析

4

2 回答 2

0

您是正确的,问题是由ExtensibleActionInvoker课程引起的。如果您查看它的源代码,则有一个方法称为GetParameterValue(). 见下文:

    protected override object GetParameterValue(ControllerContext controllerContext, ParameterDescriptor parameterDescriptor)
    {
        if (_injectActionMethodParameters)
            return _context.ResolveOptional(parameterDescriptor.ParameterType) ?? base.GetParameterValue(controllerContext, parameterDescriptor);

        return base.GetParameterValue(controllerContext, parameterDescriptor);
    } 

此方法覆盖最终使用 MVC 框架的模型绑定器基础结构的方法。这意味着,ActionInvoker 首先尝试使用 AutoFac 解析参数,如果失败,则回退到默认功能。根据您获得的结果,您的 AutoFac 配置似乎必须设置为提供ITestClass.

为了向 AutoFac 注册自定义 ModelBinder,您有几个选项。您可以使用 a 来装饰视图模型,ModelBinderTypeAttribute也可以在配置中使用RegistrationExtensions.

我发现的一篇文章似乎为类似问题提供了一个简单的解决方案(见最后),但我没有亲自测试过。

于 2012-08-29T14:28:11.273 回答
0

现在解决了这个问题,我找到了一个简单的答案。我的问题是因为我没有真正理解 MVC 模型绑定是如何工作的。

如果您查看我的原始问题,我创建了一个 DefaultModelBinder 以允许我使用接口作为我的模型参数(请参阅顶部的原始问题)。这是在我包括 Autofac 的 ExtensibleActionInvoker 来绑定我的 IService 类型之后添加的。问题在于两种 DI 方法发生冲突。

答案是 DefaultModelBinder 足以绑定我的数据类和服务定义,所以我不需要 Autofac 的 ExtensibleActionInvoker。为了完整起见,我已经包含了 DefaultModelBinder 代码,以防它对其他人有用。

public class DiModelBinder : DefaultModelBinder
{
    protected override object CreateModel(ControllerContext controllerContext, ModelBindingContext bindingContext, Type modelType)
    {
        return modelType.IsInterface
                   ? DependencyResolver.Current.GetService(modelType)
                   : base.CreateModel(controllerContext, bindingContext, modelType);
    }
}

请注意,如果模型类型是接口,我只调用 DependencyResolver,因为我不在层之间传递抽象类。任何替代方法是始终调用 DependencyResolver,然后在 DI 未解析类型时调用 base.CreateModel。我没有这样做,因为调用 DependencyResolver 有点贵,所以我只在知道我需要它时才调用它。

于 2012-09-11T14:04:05.700 回答