【问题标题】:Castle Windsor IOC in MVC ControllerMVC 控制器中的温莎城堡 IOC
【发布时间】:2013-12-19 19:18:47
【问题描述】:

我已经在 MVC 中设置了 Castle Windsor IoC。我已经阅读了教程,并做到了这一点:

public class HomeController : Controller
{

    /////////////////////////////////////////////////////////////
    // Attributes

    public ISearchService SearchService { get; set; }

    public IFeedbackService FeedbackService { get; set; }

HomeController 负责处理搜索和存储反馈,因此 HomeController 有两个由 IoC 创建的服务引用。

这不是我真正想要的。我不想为 Home 控制器上的每个请求构建两个服务,因为大多数时候不需要它们。当我确定需要它们时,我想在动作函数中构造它们。

以前,我使用 Microsoft Unity,我的操作函数中有很多 ServiceLocator.Resolve<thing>()。当涉及到测试时,这是一个真正的痛苦,我已经读过它是不可取的(并且是反模式)。

我的愿望是:

[HttpPost]
public ActionResult(FeedbackViewModel vm,IFeedbackService feedbackService)
{

并让 IoC 构造第二个参数而不是第一个参数。这可能吗?

如果没有,我将不得不找到一种方法来创建服务构造函数的成员,而不使用静态引用。

感谢阅读。

使用 Brent Mannering 的回答更新:

我尝试创建 ResolveThis 参数,但无法检查 BindModel 函数中的属性。所以我坚持解决所有接口:

/// <summary>
/// 
/// </summary>
public class DependencyModelBinder : DefaultModelBinder
{

    /////////////////////////////////////////////////////////////
    // Attributes

    private IKernel _kernel;


    /////////////////////////////////////////////////////////////
    // Construction

    public DependencyModelBinder(IKernel kernel)
    {

        // Initialize member variables
        _kernel = kernel;

    }


    /////////////////////////////////////////////////////////////
    // Implementation

    public override object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
    {

        // If this is an interface...
        if(bindingContext.ModelType.IsInterface)
        {

            // Resolve the object and return 
            return _kernel.Resolve(bindingContext.ModelType);

        }

        // Call base-class function
        return base.BindModel(controllerContext, bindingContext);

    }


}

【问题讨论】:

  • 我建议您只使用普通的旧 DI 并将服务注入控制器的构造函数。
  • 感谢 Maess,但这意味着构建两个服务,以及与它们一起使用的所有存储库类,但它们可能不会被使用。这不是可耻的低效吗?
  • 梅斯是对的。您应该使用构造函数注入,因为 Castle Windsor 中的属性是可选的。如果您忘记注册其中一个依赖项,控制器仍然可以创建,但该属性将为空。这将在稍后导致 NullReferenceException。最好让应用程序失败 a.s.a.p。这意味着您应该使用构造函数注入。
  • 另外,你有没有测试过性能差异是什么?构建依赖图通常是very fast(即使使用像 Castle 这样的框架),尤其是与 Web 框架的开销相比。如果您注入仅在部分时间使用的依赖项,它不应该有任何明显的区别。如果其中一个依赖项需要很长时间才能创建,则意味着该依赖项的构造函数做得太多,应该重构这个类。

标签: asp.net-mvc model-view-controller inversion-of-control castle-windsor


【解决方案1】:

首先,在我看来,您违反了单一责任原则,因此您首先遇到了这个问题。您可能应该重构您的控制器并将搜索或反馈操作(实际上可能两者)移动到它们自己的控制器中,并在构造函数中注入服务依赖项。

但是,直接回答您的问题。 您可以使用自定义模型绑定器来管理它。 大致如下:

public class DependencyModelBinder : DefaultModelBinder
{
    public override object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
    {
        if (bindingContext.ModelType.IsInterface)
        {
            bindingContext.Model = // ServiceLocator logic here using bindingContext.ModelType
        }

        return base.BindModel(controllerContext, bindingContext);
    }
}

然后在您的 Application_Start 中添加以下行:

ModelBinders.Binders.DefaultBinder = new DependencyModelBinder();

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-05-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多