2009-05-18 34 views
16

Actualmente tengo un ActionFilter que obtiene el nombre de los usuarios actuales de HttpContext y lo pasa a la acción que lo usa en un método de servicio. por ejemplo:ASP.NET MVC: HTTPContext e Inyección de Dependencia

Service.DoSomething(userName); 

Ahora tengo una razón para hacer esto no en el nivel de acción sino en el nivel del constructor del controlador. Actualmente estoy usando el mapa de estructura para crear controladores e inyectar el servicio. Estoy mirando algo como:

public interface IUserProvider 
{ 
    string UserName { get; } 
} 

public class HttpContextUserProvider : IUserProvider 
{ 
    private HttpContext context; 

    public HttpContextUserProvider(HttpContext context) 
    { 
     this.context = context; 
    } 

    public string UserName 
    { 
     get 
     { 
      return context.User.Identity.Name; 
     } 
    } 
} 

Dicho esto, mi foo COI está muy débil ya que este es el primer proyecto en el que he utilizado en.

Así que mi pregunta es ... ¿cómo puedo decir que el mapa de estructura pase en HttpContext en el constructor para HttpContextUserProvider? Esto parece extraño ... No estoy seguro de cómo pensar en HttpContext.

Respuesta

8

Tiene una interfaz abstracta HttpContext.Current. Exponga solo los métodos que necesita. GetUserName() llamaría a HttpContext.Current.User.Identity.Name en el implementación, por ejemplo. Haz que sea lo más delgada posible.

Toma esa abstracción e instálala en tu otra clase de proveedor. Esto te permitirá probar al proveedor burlándose de la http abstracción de contexto. Como beneficio adicional, puedes hacer otras cosas ingeniosas con esa abstracción de HttpContext además de burlarlo. Reutilizarlo, por un lado. Agregue parámetros de tipo genérico a bolsas, etc.

+0

¿Qué quiere decir con "Añadir parámetros de tipo genérico a las bolsas"? Suena intrigante –

+4

proporciona envolturas sólidas en la Sesión –

+3

¿Tiene algún código/enlace de muestra, esto parece interesante? Soy un poco nuevo en DI, así que no entiendo esto correctamente, cualquier ayuda/consejo sería apreciado ... – Haroon

2

Quizás dejé algo fuera, pero la respuesta anterior no funciona para mí (se ha eliminado desde entonces, aunque seguía siendo una respuesta útil, mostraba cómo decirle a SM que pase los argumentos del constructor). En cambio, si lo hago:

ObjectFactory.Initialize(x => 
{ 
    x.BuildInstancesOf<HttpContext>() 
     .TheDefault.Is.ConstructedBy(() => HttpContext.Current); 
    x.ForRequestedType<IUserProvider>() 
     .TheDefault.Is.OfConcreteType<HttpContextUserProvider>(); 
}); 

consigo que funcione. Hice esto después de encontrar: http://codebetter.com/blogs/jeremy.miller/archive/2008/03/20/if-you-need-something-in-structuremap-but-you-can-t-build-it-with-new.aspx


edición:

Gracias a la respuesta de Brad me pensar que tengo un mejor manejo de HttpContext. Su respuesta definitivamente funciona, simplemente no estoy seguro de que me guste tener la llamada a HttpContext.Current dentro de una clase (parece que oculta la dependencia, pero estoy lejos de ser un experto en esto).

El código anterior debería funcionar para inyectar HttpContext por lo que yo sé. Matt Hinze menciona el punto agregado de que si todo lo que necesito de HttpContext es User.Identity.Name, mi diseño debe ser explícito al respecto (tener una interfaz alrededor de HttpContext solo expone lo que necesito). Creo que es una buena idea.

La cosa es durante el almuerzo Me di cuenta de que mi servicio realmente solo necesita depender de una cadena: userName. Tenerlo depender de IUserProvider podría no tener mucho valor agregado. Así que sé que no quiero que dependa de HttpContext, y sé que todo lo que necesito es una cadena (userName). Necesito ver si puedo aprender lo suficiente de StructureMap como para hacer esta conexión por mí. (La respuesta de sirrocoo da una pista sobre por dónde empezar, pero la eliminó: *().

+0

En términos laymens cuando un constructor tiene una dependencia de HttpContext El COI pasará en el caso de HttpContext.Current. Y cuando un constructor tiene una dependencia de IUserProvider, IoC instanciará una nueva instancia de HttpContextUserProvider y la pasará al constructor. –

+0

La interfaz de StructureMap lee bien. Mi confusión es que creo en dos partes: 1) Solo he usado ForRequestedType - cómo sé cuándo romper BuildInstancesOf en su lugar (Probablemente pueda googlear esto - pregunta fácil) 2) ¿Puedo dar por hecho? que StructureMap sabe cómo obtener HttpContext.Current? Creo que HttpContext me confunde un poco porque parece flotar mágicamente en todas partes. No puedo pensar en una sola fuente a la que pueda acceder para obtenerla, ya que todo lo demás tiene una fuente más clara. – anonymous

+0

de hecho, mi solución no funcionó, y con un error grave incluso, la excepción interna decía algo acerca de una limitación de JIT ... wow – sirrocco

3

No estoy seguro de por qué te molestas. Parece que solo usar HttpContext.Current directamente en HttpContextUserProvider es lo correcto para do. Nunca va a sustituir en un HttpContext diferente ...

+0

Yah ... No creo que * obtenga * HttpContext. Supongo que estoy acostumbrado a que algo pase en el constructor donde aparece HttpContext solo globalmente. – anonymous

+0

De acuerdo, hizo el retorno HttpContext.Current.User.Identity.Name; y funciona. Supongo que soy un poco lento con respecto a la adopción aquí, pero actualizo una propiedad estática en HttpContext que tiene la responsabilidad de saber cómo encontrar el HttpContext actual. El único inconveniente es que no se puede (al menos no lo creo) ser explícito al depender de HttpContext a través de la inyección del constructor porque no se puede pasar una propiedad estática o escribir. Podrías hacer un wrapper como IHttpContextProvider que simplemente devuelve HttpContext.Current y entonces sabrías que algo depende de HttpContext? ¿O es tonto? – anonymous

+0

¿Cómo inyectaría el HttpContext en, por ejemplo, una capa de servicio que no hace referencia a la web, quizás podríamos decir que se trata de un escenario de caso de uso para eso, donde los registros/conjuntos de datos dependen del usuario actual? (asp.net mvc2) ... – Haroon

9

Parece que debería estar usando HttpContextBase en lugar de HttpContextUserProvider.Esta es una abstracción de fábrica de HttpContext y le permite crear un simulacro, escribir UnitTests e insertar sus dependencias.

public class SomethingWithDependenciesOnContext 
{ 
    public SomethingWithDependenciesOnContext(HttpContextBase context) { 
     ... 
    } 

    public string UserName 
    { 
     get {return context.User.Identity.Name;} 
    } 
} 

ObjectFactory.Initialize(x => 
      x.For<HttpContextBase>() 
      .HybridHttpOrThreadLocalScoped() 
      .Use(() => new HttpContextWrapper(HttpContext.Current)); 
Cuestiones relacionadas