Pregunta Cómo obtener la instancia de Microsoft.AspNet.Http.HttpContext en Class Constructor usando DI


Estoy construyendo una aplicación de usar y tirar en MVC 6 y experimentando con diferentes arquitecturas para las dependencias.

El problema que estoy enfrentando es cómo crear un personalizado 'MyAppContext'objeto específico para la Aplicación. Esto requeriría cierta información del HttpContext y cierta información de la base de datos, y será un repositorio con ámbito de solicitud para los atributos específicos de la aplicación. Quiero pasar la instancia de HttpContext en el constructor de la 'MyAppContext'.

He creado con éxito un 'DataService'objeto con un IDataService interfaz utilizando 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 el HttpContext parámetro en el constructor para ser resuelto por DI. Cuando ejecuto el código, esta es la excepción que me devuelven:

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

Me imagino que esto es porque no hay una instancia específica de HttpContext que este error está ocurriendo, pero no sé cómo registrar el HttpContext instancia en DI. Agregué 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 el segundo HttpContext se supone que es una instancia; sé que no es correcto, pero no he podido averiguar qué es.

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


17
2018-05-05 14:05


origen


Respuestas:


Inyectar IHttpContextAccessor en el constructor


11
2018-05-05 15:15



Al inyectar un HttpContext en su componente está violando el Principios sólidos. Para ser más específico, estás violando:

Ambas violaciones hacen que sea mucho más difícil probar tu código. Aunque en su lugar puede inyectar el IHttpContextAccessor como @victor sugiere, esto sigue siendo una violación tanto del DIP como del ISP, porque esta es una abstracción proporcionada por el framework y aún dependes de HttpContext. Según el DIP, es el cliente quien debe definir la abstracción. Esto hace que su código se acople 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 para las necesidades de su aplicación. Inyectar un gran diccionario con valores de cadena (como HttpContext es, nunca es muy específico). De su pregunta no está claro qué tipo de datos necesita de nuestra MyAppContext, pero espero algo así como información del usuario actualmente conectado. Para esto puedes definir un específico IUserContextabstracción, por ejemplo:

public interface IUserContext {
    IPrincipal CurrentUser { get; }
}

Un adaptador que conecta la aplicación con el marco ASP.NET se puede crear fácilmente 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 no depende de IHttpContextAccessor, pero está bien, ya que el adaptador es un componente de infraestructura ubicado en el Composición Root. Hay varias maneras de registrar esta clase, por ejemplo:

services.AddSingleton<IUserContext, AspNetUserContext>();

11
2018-05-05 15:43



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;
}

3
2018-04-16 22:29



¿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
    }

-4
2018-05-05 15:16