net microsoft ihttpcontextaccessor ejemplos current create clases aspnetcore asp c# asp.net-mvc dependency-injection asp.net-core asp.net-core-mvc

c# - ihttpcontextaccessor - microsoft aspnetcore http httpcontext



Cómo obtener la instancia de Microsoft.AspNet.Http.HttpContext en Class Constructor utilizando DI (4)

¿Por qué pasaría el HttpContext en el constructor? ¿Por qué no acceder directamente a él donde quieras?

public MyAppContext(IDataService dataService) { HttpContext mycontext = HttpContext.Current; //do stuff here with mycontext }

Estoy creando una aplicación desechable en MVC 6 y experimentando con diferentes arquitecturas para dependencias.

El problema al que me enfrento es cómo crear un objeto '' MyAppContext '' personalizado específico para la aplicación. Esto requeriría cierta información de HttpContext y cierta información de la base de datos, y será un repositorio de ámbito de solicitud para atributos específicos de la aplicación. Quiero pasar la instancia de HttpContext al constructor de '' MyAppContext ''.

He creado con éxito un objeto '' DataService '' con una interfaz IDataService usando DI y esto funciona bien. La diferencia con la clase ''MyAppContext'' es que tiene dos parámetros en el constructor: el '' DataService '' y el Microsoft.AspNet.Http.HttpContext . Aquí está la clase MyAppContext:

public class MyAppContext : IMyAppContext { public MyAppContext(IDataService dataService, HttpContext httpContext) { //do stuff here with the httpContext } }

En el código de inicio, registro la instancia de DataService y la instancia de MyAppContext:

public void ConfigureServices(IServiceCollection services) { services.AddMvc(); //adds a singleton instance of the DataService using DI services.AddSingleton<IDataService, DataService>(); services.AddScoped<IMyAppContext, MyAppContext>(); } public void Configure(IApplicationBuilder app) { app.UseErrorPage(); app.UseRequestServices(); app.UseMvc(routes => /* routes stuff */); }

Estoy esperando que el parámetro HttpContext en el constructor se resuelva por DI. Cuando ejecuto el código, esta es la excepción que recibí:

InvalidOperationException: no se puede resolver el servicio para el tipo ''Microsoft.AspNet.Http.HttpContext'' al intentar activar ''MyAppContext''

Me imagino que esto se debe a que no hay una instancia específica de HttpContext que se esté produciendo este error, pero no sé cómo registrar la instancia de HttpContext en DI. app.UseRequestServices(); la línea '' app.UseRequestServices(); ''Pero esto no ha hecho ninguna diferencia. También probé una variante de:

services.AddScoped<HttpContext, HttpContext>();

Pero esto falla porque se supone que el segundo HttpContext es una instancia. Sé que no es correcto, pero no he podido averiguar qué es.

Entonces, en resumen, ¿cómo puedo pasar el objeto HttpContext al constructor de MyAppContext?


Al inyectar un HttpContext en su componente, está violando los principios de SOLID . Para ser más específico, estás violando:

Ambas violaciones hacen que sea mucho más difícil probar su código. Aunque en su lugar puede inyectar el IHttpContextAccessor como sugiere @victor, esto sigue siendo una violación tanto del DIP como del ISP, porque es una abstracción que proporciona el marco y aún depende de HttpContext. Según el DIP, es el cliente quien debe definir la abstracción. Esto hace que su código sea acoplado innecesariamente al marco.

En su lugar, debe esforzarse por especificar interfaces de rol estrechas; interfaces que hacen una cosa específica para usted que es específica a las necesidades de su aplicación. Inyectar un diccionario grande con valores de cadena (como lo que HttpContext es, nunca es muy específico). De su pregunta no está claro qué tipo de datos necesita de MyAppContext , pero espero algo como información del usuario que ha iniciado sesión actualmente. Para esto puedes definir una abstracción específica de IUserContext , por ejemplo:

public interface IUserContext { IPrincipal CurrentUser { get; } }

Se puede crear fácilmente un adaptador que conecta la aplicación con el marco ASP.NET para esta abstracción:

sealed class AspNetUserContextAdapter : IUserContext { private readonly IHttpContextAccessor accessor; public AspNetUserContextAdapter(IHttpContextAccessor accessor) { this.accessor = accessor; } public IPrincipal CurrentUser => accessor.HttpContext.User; }

Este adaptador depende de IHttpContextAccessor , pero esto está bien, ya que el adaptador es un componente de infraestructura ubicado en la raíz de composición . Hay varias maneras de registrar esta clase, por ejemplo:

services.AddSingleton<IUserContext, AspNetUserContext>();


En la clase de inicio:

using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc.Core; using Microsoft.Extensions.DependencyInjection; public void ConfigureServices(IServiceCollection services) { services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>(); services.AddMvcCore(); }

En el controlador:

using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Mvc.Core; private readonly IHttpContextAccessor _httpContextAccessor; public ServerSentEventController(IHttpContextAccessor httpContextAccessor) { _httpContextAccessor = httpContextAccessor; }


Inyectar IHttpContextAccessor en el constructor