I have an ASP.NET MVC 3 application and am using Ninject for injecting dependencies into my classes.
Actions on the Controllers pass ViewModels (that do not contain logic) to the view layer.
When a HTTP form is POSTed MVC 3 creates a ViewModel instance and binds the incoming POST data to the ViewModel's properties. MVC 3 uses a class called DefaultModelBinder to create the instance and perform the binding.
Most of my ViewModels share a dependency which I do not really want to set from each individual Controller method (DRY principle).
Therefore, I have created a customized subclass of DefaultModelBinder as follows:
using System;
using System.Web.Mvc;
namespace Application.Classes {
public seale开发者_C百科d 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 );
}
}
}
And I have set it to replace the DefaultModelBinder as follows (in Global.asax.cs):
protected void Application_Start() {
// ...
ModelBinders.Binders.DefaultBinder = new CustomModelBinder( DependencyResolver.Current );
// ...
}
By doing this when a Controller method receives a ViewModel, it will be one that was built by Ninject using the binding I sepecified in my NinjectModule. The ViewModel now receives it's dependencies injected into it's constructor.
Is this an appropriate use of the Service Locator Pattern?
CLARIFICATION/UPDATES:
- The application uses Ninject and is integrated into the MVC system as documented on the Ninject Wiki (https://github.com/ninject/ninject.web.mvc/wiki/Setting-up-an-MVC3-application)
From what I understand so far is that you have a ViewModel which inherits from ViewModelBase to expose AccountInformation on all Views where a user is logged in.
Unless I completely misunderstood, this is my point of view:
The AccountInformation should only be used for displaying purposes. So it should not be a problem when the default ModelBinder does not instantiate it when a post to your action occurs. I encourage you to fetch the AccountInformation again using the information you have eg. Controller.User
and your database. A registration/profile page is the only place where you'd want this information to come from POST variables. You could cache this information per user if necessary.
As I said in the comments, ViewModels should be as stupid as possible. They should only contain the properties with their types and metadata regarding validation etc.
All the logic you'd want to put in a view, goes into the controller.
So to conclude; There shouldn't be the need to use a Service Locator in your ModelBinder.
View Models should not have dependecies. They are just dumb data containers with no functionallity. Use Filters for cross cutting concerns instead.
have you considered using Ninject for MVC3? You can download it from here
Then in your global.asax inherit from NinjectHttpApplication:
public class MvcApplication : NinjectHttpApplication
{
Create a method to override kernel:
protected override IKernel CreateKernel()
{
return new StandardKernel(new NinjectRepositoryModule(),
new NinjectAggregateServiceModule());
}
NijectRepositoryModule is where I bind my interfaces to concrete implementations:
public class NinjectRepositoryModule: NinjectModule
{
public override void Load()
{
Bind<IContactsRepository>().To<EFContactRepository>();
}
}
精彩评论