2012-06-01 15 views
8

Estoy trabajando en el sitio web de MVC3, tratando de usar Ninject para resolver mis dependencias. Tengo el siguiente escenario:Uso de Dependency Injection en ASP.NET MVC3 Model Binder

public class UserModelBinder : IModelBinder 
{ 
    //[Inject] 
    public UserDataService userData { get; set; } 

    public object BindModel(
     ControllerContext controllerContext, 
     ModelBindingContext bindingContext) 
    { 
     Guid UserID = 
      (Guid)Membership.GetUser().ProviderUserKey; 

     //userDataService = DependencyResolver.Current 
     // .GetService<UserDataService>(); 

     User user = userDataService.GetUser(UserID); 

     return user; 
    } 
} 

notó las líneas de comentarios de código?

hago registrar el aglutinante en Global.asax como

ModelBinders.Binders[typeof(User)] = new UserModelBinder(); 

Así que no puedo realmente hacer la inyección a través de la construcción.

UserDataService tiene una cadena de dependencias: UserDataService -> UserRepository -> Context. Entonces sería bueno usar Ninject aquí.

El problema es que cuando elimino [Inject] la declaración anterior userData y trato de hacer que Ninject inserte el objeto como parámetro, no funciona por alguna razón: obtengo excepciones de referencia nula.

(Podría ser que UserDataService no tiene una interfaz y estoy vinculante el objeto a sí mismo: kernel.Bind<UserDataService>().ToSelf(); ??)

tengo otra línea comentada en el código:

userDataService = DependencyResolver.Current 
    .GetService<UserDataService>(); 

Cuando no está descompuesto, la configuración funciona, obtengo los objetos correctos insertados, pero ahora dependemos de DependencyResolver y eso no es mucho mejor que decir userDataService = new UserDataService()

¿Me estoy perdiendo algo? ¿Hay alguna otra forma de inyectar un objeto como parámetro y no introducir la dependencia en Ninject o DependencyResolver?

+12

¿La infección dices? – JConstantine

+5

@JLevett: dependiendo de cómo inyecte esas dependencias, podrían infectarse :-) –

+1

+1 solo por el "buen error tipográfico del día" :-) –

Respuesta

6

Un archivador modelo solo debe hacer conversión de datos y no debe depender de ningún servicio y ciertamente no desencadenará ninguna comunicación de base de datos. Eso debería hacerse en otra parte de su aplicación. Su método de Acción debería simplemente tomar un Guid userId y debe llamar al userDataService.GetUser(UserID); desde dentro de sus controladores (o en una capa inferior, por ejemplo, dentro de un business command). Al hacer esto, su problema no existirá.

+1

Sí, tuve eso en primer lugar, pero luego tuve userData .GetUser (UserID) en todos los controladores, en cada llamada. También se confundieron los controladores con dos objetos Guid que se pasaron en: Eliminar (Id. De guía, ID de usuario Guid) y en lugar de ID de objeto, el controlador recibió dos ID de usuario. A menos que haya una manera de resolver este problema ... – trailmax

+0

@trailmax: Entonces, probablemente haya algún problema con su enrutamiento. Y si no, muévase a crear una nueva pregunta aquí en SO. Sin embargo, estás solucionando este problema de la manera incorrecta. – Steven

+0

Sí, entiendo tu punto. Probablemente seguirá su ruta. ¡Gracias! – trailmax

1

Utilice DependencyResolver.Current para obtener su servicio. Esto es en realidad mucho mejor que usar new, porque significa que no ha acoplado ese servicio al tipo de servicio. Puede decidir más adelante hacer una abstracción de UserDataService y conectar diferentes variantes sin cambiar su código de cliente, que es realmente el punto principal.

Además, DependencyResolver.Current es 0table IDependencyResolver, por lo que podría implementar esa interfaz usted mismo, con una clase que lo respalde con Ninject si le gusta ese marco.

Otra forma de hacer la inyección de dependencia en MVC3 es configurar su propio IControllerActivator, que le permite hacer la inyección del constructor en su lugar, si lo desea.

+0

Sí, entiendo lo que hace DependencyResolver y por qué es mejor que crearlo a través de "nuevo". ¿Debería alguna clase ignorar que DI está funcionando? De ahí el título "infección". – trailmax

+2

¿Quieres decir que la mayoría de tus clases ignorarían tu marco DI? ¡Absolutamente, casi todos deberían ignorarlo! Debe ser encapsulado también. Ver este gran artículo de Uncle Bob sobre el tema: http://blog.objectmentor.com/articles/2010/01/17/dependency-injection-inversion – tallseth

4

usted puede hacer esto:

public class UserModelBinder : IModelBinder 
{ 
    public Func<UserDataService> UserData { get; set; } 

    public object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext) 
    { 
     Guid UserID = (Guid)Membership.GetUser().ProviderUserKey; 

     User u = UserData().GetUser(UserID); 

     return u; 
    } 
} 

Luego, cuando le gire hacia arriba:

ModelBinders.Binders[typeof(User)] = new UserModelBinder() 
{ 
    userData =() => DependencyResolver.Current.GetService<UserDataService>(); 
} 

El beneficio es que su UserModelBinder no es consciente de que un contenedor está siendo utilizado, sin dejar de ser abierto para inyección.

Pero estoy de acuerdo con Steven - el uso de una carpeta modelo para esto no parece del todo correcto. En su lugar, puede inyectar un ICurrentUserContext en sus controladores, donde la implementación devuelve al usuario actual. Entonces ni siquiera necesita agregar un parámetro a las acciones de su controlador.

Cuestiones relacionadas