C# 这是MVC3ModelBinder中服务定位器模式的适当使用吗?

C# 这是MVC3ModelBinder中服务定位器模式的适当使用吗?,c#,asp.net-mvc-3,design-patterns,ninject,C#,Asp.net Mvc 3,Design Patterns,Ninject,我有一个ASP.NETMVC3应用程序,正在使用Ninject将依赖项注入到我的类中 控制器上的操作将ViewModels(不包含逻辑)传递到视图层 发布HTTP表单时,MVC 3将创建一个ViewModel实例,并将传入的POST数据绑定到ViewModel的属性。MVC3使用名为DefaultModelBinder的类来创建实例并执行绑定 我的大多数ViewModels都有一个依赖关系,我并不想从每个单独的控制器方法中设置这个依赖关系(DRY原则) 因此,我创建了DefaultModelBi

我有一个ASP.NETMVC3应用程序,正在使用Ninject将依赖项注入到我的类中

控制器上的操作将ViewModels(不包含逻辑)传递到视图层

发布HTTP表单时,MVC 3将创建一个ViewModel实例,并将传入的POST数据绑定到ViewModel的属性。MVC3使用名为DefaultModelBinder的类来创建实例并执行绑定

我的大多数ViewModels都有一个依赖关系,我并不想从每个单独的控制器方法中设置这个依赖关系(DRY原则)

因此,我创建了DefaultModelBinder的自定义子类,如下所示:

using System;

using System.Web.Mvc;

namespace Application.Classes {

    public sealed class CustomModelBinder : DefaultModelBinder {

        private readonly IDependencyResolver DependencyResolver;

        public CustomModelBinder( IDependencyResolver dependencyResolver ) {

            DependencyResolver = dependencyResolver;

        }

        protected override object CreateModel( ControllerContext controllerContext , ModelBindingContext modelBindingContext , Type modelType ) {

            return DependencyResolver.GetService( modelType );

        }

    }

}
我将其设置为替换DefaultModelBinder,如下所示(在Global.asax.cs中):

当控制器方法接收到ViewModel时执行此操作,它将是由Ninject使用我在Ninject模块中指定的绑定构建的。ViewModel现在接收注入其构造函数的依赖项

这是服务定位器模式的适当使用吗

澄清/更新:

  • 该应用程序使用Ninject,并集成到MVC系统中,如Ninject Wiki()所述

您是否考虑过将Ninject用于MVC3?你可以从

然后在global.asax中从NinjectHttpApplication继承:

public class MvcApplication : NinjectHttpApplication
{
创建重写内核的方法:

protected override IKernel CreateKernel()
{
   return new StandardKernel(new NinjectRepositoryModule(),
                             new NinjectAggregateServiceModule());
}
NijectRepositoryModule是我将接口绑定到具体实现的地方:

public class NinjectRepositoryModule: NinjectModule
{
        public override void Load()
        {
            Bind<IContactsRepository>().To<EFContactRepository>();
        }
}
公共类NinjectRepositoryModule:NinjectModule
{
公共覆盖无效负载()
{
绑定()到();
}
}

据我目前所知,您有一个从ViewModelBase继承的ViewModel,用于在用户登录的所有视图上公开帐户信息

除非我完全误解,否则这是我的观点:
AccountInformation只能用于显示目的。因此,当操作发生post时,默认ModelBinder没有实例化它时,这应该不是问题。我鼓励您使用您拥有的信息(例如,
Controller.User
和您的数据库)再次获取AccountInformation。注册/配置文件页面是您希望这些信息来自POST变量的唯一地方。如有必要,您可以为每个用户缓存此信息

正如我在评论中所说,ViewModels应该尽可能愚蠢。它们应该只包含属性及其类型和有关验证等的元数据

所有您想放在视图中的逻辑都进入控制器


综上所述;不需要在ModelBinder中使用服务定位器。

视图模型不应具有依赖项。它们只是没有功能的哑数据容器。在横切关注点上使用过滤器。

我在第一行说我正在使用Ninject,并在最后一段中再次提到它。我的例子中的IDependencyResolver是Ninject。我理解这一点,我也在做同样的事情,但后来我在MVC 3中遇到了标准Ninject没有完成这项工作的场景。例如,注入到属性中,所以我问过您是否考虑对ninject=)使用MVC扩展,如果这没有用,那么我很乐意删除答案。我使用Nuget()安装了ninject,页面上说这与扩展NinjectHttpApplication相同。然而,我的测试表明MVC3并没有使用Ninject来创建绑定到Action ViewModels的模型。Ninject可以很好地将依赖项注入到其他地方。例如,控制器可以很好地接收它们的依赖关系。我很好奇您的viewmodels可能需要哪种依赖关系,因为viewmodel应该尽可能地愚蠢。您可以使用ninject将依赖项注入到控制器中,而控制器又可以将依赖项传递给viewmodel的构造函数。@Peter嗯,您无法从MVC 3中的控制器访问viewmodel的构造函数(除非我遗漏了什么)。ViewModels(MVC 3为您创建的动作参数)是在一个名为DefaultModelBinder的“黑盒”中创建的。@Peter我愿意探索ViewModel中的依赖关系。但是我真的很想了解这个CustomModelBinder是否是服务定位器模式的适当使用(我正试图了解其中的许多概念!)。好的,所以依赖关系是一个ViewModelBase.AccountInformation,它是在抽象类ViewModelBase的构造函数中接收的。在所有“登录”页面上都会使用它来显示一个帐户剩余的信用额度以及续费日期。我已经添加了我的答案,希望它能让事情变得更清楚一些。如果您还有问题,我真的很想讨论一下。确实,当发生POST操作时,通常不需要AccountInformation—当然,存在验证错误的情况除外,操作需要重新呈现视图。听起来,对于每个控制器中的每个操作,我都需要重复代码行来填充此ViewModelBase属性。你能详细解释一下为什么依赖注入不是一个更好的解决方案吗?考虑到枯燥的原则,为什么在单点对象图配置上重复自己是可以接受的呢?为什么不在母版页中添加一个Html.RenderAction(“帐户/信息”)呢?这样,您就可以遵循DRY原则,而且更好的是,您不再需要将这些数据与其他viewmodels耦合。这听起来是一个很好的解决方案。正如您所描述的,它的好处是显而易见的。谢谢你花时间思考这个问题。谢谢你的回答。我并不反对过滤器可能更适合此任务,但请您帮助我理解为什么CustomModelBinder不是最佳解决方案。仅为澄清,注入的AccountInformation实例是一个没有任何功能的DTO。就这样
public class NinjectRepositoryModule: NinjectModule
{
        public override void Load()
        {
            Bind<IContactsRepository>().To<EFContactRepository>();
        }
}