2012-08-24 37 views
1

使用接口参数时,Autofac ExtensibleActionInvoker与MVC ModelBinder交互时出现问题。背景如下:MVC Autofac ExtensibleActionInvoker使用接口参数阻止我使用接口参数

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

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

这个作品真的很好,使一个真正干净的设计(见Alex Meyer-Gleaves post有关此方法的更多信息)。我想要使​​用这种方法,因为我正在生成一个代码生成器来创建操作,视图,服务和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 class和modelbinder将从视图输入的 绑定到类中的字段。
  2. 使用ExtensibleActionInvoker启用它不起作用,即,我得到一个空的TestClass类,没有绑定。我假设ExtensibleActionInvoker优先于模型联编程序,并创建一个空的TestClass类。
  3. (只是为了保持完整性,我应该说,如果我只是用MVC“开箱即用”,即没有新的DefaultModelBinder并没有ExtensibleActionInvoker启用,那么它说,你不能使用一个接口作为一个操作方法参数。)

我的问题比我有更好的Autofac知识的人是:我可以更改Autofac ExtensibleActionInvoker以选择它绑定到什么?我所有注入的服务都是从IService开始的,所以我可以对此进行过滤。我知道你可以在Autofac的其他地方做到这一点,但看不到任何与ExtensibleActionInvoker相关的事情,但也许我错过了它。

任何帮助,将不胜感激。

乔恩·史密斯 - 选择性分析

回答

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如果modeltype是一个接口,因为我不及格层之间的抽象类。任何替代方法都是始终调用DependencyResolver,如果DI没有解析类型,则调用base.CreateModel。我没有这样做,因为调用DependencyResolver的代价稍微昂贵,所以我只在知道需要时调用它。

0

你是正确的,问题是由ExtensibleActionInvoker类引起的。如果你看the source for it,有一种方法叫做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,您有几个选项。您可以使用ModelBinderTypeAttribute修饰视图模型,也可以在配置中使用RegistrationExtensions中的自定义扩展方法进行修改。

我发现的一篇文章看起来像它提供了(见最后),但我没有亲自测试过。

+0

谢谢@smartcaveman。这是一个非常明确的解释,为什么它正在发生,并链接到一些解决方案 - 完美。看过Autofac如何实现这一点,我想我会编写我自己的GetValueProvider,但是通过筛选我替换的参数。我会尝试并报告。 –