代码之家  ›  专栏  ›  技术社区  ›  MyDaftQuestions

如何从控制器获取HttpContext

  •  0
  • MyDaftQuestions  · 技术社区  · 5 年前

    我正在使用ASP。NET核心(MVC)

    如果我调用端点,那么 this.HttpContext 不是null。

    在与我的端点相同的类中,如果我在控制器中设置一个断点, 这个。请求上下文 始终为空。

    我如何获得 HttpContext 从控制器?

    [Authorize]
    [ApiController]
    [Route("api/[controller]")]
    public class LoginController : ControllerBase
    {
        public LoginController()
        {
            var isNull = this.HttpContext; //always null
        }
    
        [HttpGet]
        public async Task Get()
        {
            var isNull = this.HttpContext; //not null
        }
    }
    

    这样做的目的是,在每个端点上,我都想访问一些值(来自cookie)。在NET Framework中,我会将cookie值存储在基类中(从构造函数中)。

    虽然我可以在每个端点上访问HTTPContext,但在构造函数中这样做意味着每个类只编写一次代码。

    我们的目标很大程度上是减少编码。我希望我不是懒惰

    0 回复  |  直到 5 年前
        1
  •  1
  •   Malik Kashmiri    5 年前

    不,这不是正确的方法。您需要使用Filter或中间件来完成。HttpContext类在控制器的构造函数中始终为null

    示例中间件代码(用于日志记录)

    你可以在这里做任何事情,比如读饼干什么的

    public class LoggingMiddleware
    {
        private static readonly TelemetryConfiguration telemetryConfiguration = TelemetryConfiguration.CreateDefault();
        private readonly TelemetryClient telemetryClient;
        private IConfiguration configuration;
        private readonly RecyclableMemoryStreamManager _recyclableMemoryStreamManager;
        private readonly string appName;
        private readonly bool loggingEnabled;
    
        private readonly RequestDelegate _next;
    
        public LoggingMiddleware(RequestDelegate next, IConfiguration config)
        {
            _next = next;
            configuration = config;
            _recyclableMemoryStreamManager = new RecyclableMemoryStreamManager();
            telemetryConfiguration.InstrumentationKey =  configuration.GetValue<string>("ApplicationInsights:InstrumentationKey");
            telemetryClient = new TelemetryClient(telemetryConfiguration);
            appName = configuration.GetValue<string>("AppName");
            loggingEnabled = configuration.GetValue<bool>("Logging:LogRequestResponse"); 
        }
    
        public async Task Invoke(HttpContext httpContext)
        {
            if(loggingEnabled)
            {
                await LogRequest(httpContext);
                await LogResponse(httpContext);
            }
        }
    
        private async Task LogRequest(HttpContext context)
        {
            context.Request.EnableBuffering();
    
            await using var requestStream = _recyclableMemoryStreamManager.GetStream();
            await context.Request.Body.CopyToAsync(requestStream);
    
            string correlationId = context.Request.Headers.Keys.FirstOrDefault(h => h.ToLower() == "correlationid");
            if (correlationId == null) correlationId = string.Empty;
            if (context.Request.Path != "/")
            {
                telemetryClient.TrackEvent($"{appName}-RequestMiddleware", new Dictionary<string, string>
                {
                    { "AppName", appName },
                    { "CorrelationId" , correlationId },
                    { "Method" , context.Request.Method },
                    { "Scheme", context.Request.Scheme},
                    { "Host", context.Request.Host.Value },
                    { "Path", context.Request.Path },
                    { "QueryString", context.Request.QueryString.Value },
                    { "Request Body", ReadStreamInChunks(requestStream) }
    
                });
            }
            context.Request.Body.Position = 0;
        }
    
        private static string ReadStreamInChunks(Stream stream)
        {
            const int readChunkBufferLength = 4096;
    
            stream.Seek(0, SeekOrigin.Begin);
    
            using var textWriter = new StringWriter();
            using var reader = new StreamReader(stream);
    
            var readChunk = new char[readChunkBufferLength];
            int readChunkLength;
    
            do
            {
                readChunkLength = reader.ReadBlock(readChunk,
                                                   0,
                                                   readChunkBufferLength);
                textWriter.Write(readChunk, 0, readChunkLength);
            } while (readChunkLength > 0);
    
            return textWriter.ToString();
        }
    
        private async Task LogResponse(HttpContext context)
        {
            var originalBodyStream = context.Response.Body;
    
            await using var responseBody = _recyclableMemoryStreamManager.GetStream();
            context.Response.Body = responseBody;
    
            await _next(context);
    
            context.Response.Body.Seek(0, SeekOrigin.Begin);
            var text = await new StreamReader(context.Response.Body).ReadToEndAsync();
            context.Response.Body.Seek(0, SeekOrigin.Begin);
            if (context.Request.Path != "/")
            {
                telemetryClient.TrackEvent($"{appName}-ResponseMiddleware", new Dictionary<string, string> {
                    {"Scheme", context.Request.Scheme},
                    { "AppName", appName },
                    {"Host", context.Request.Host.Value},
                    {"Path" , context.Request.Path},
                    {"QueryString", context.Request.QueryString.Value},
                    {"Response Body" , text}
                    });
            }
           await responseBody.CopyToAsync(originalBodyStream);
        }
    }
    
    
    // Extension method used to add the middleware to the HTTP request pipeline.
    public static class LoggingMiddlewareExtensions
    {
        public static IApplicationBuilder UseLoggingMiddleware(this IApplicationBuilder builder)
        {
            return builder.UseMiddleware<LoggingMiddleware>();
        }
    }
    
        2
  •  1
  •   Roar S.    5 年前

    不,你不能这样做,控制器构造函数是危险区域(除非你知道自己在做什么),应该只用于DI。

    相反,您应该看看自定义中间件: https://docs.microsoft.com/en-us/aspnet/core/fundamentals/middleware/write?view=aspnetcore-3.1

    有关asp.net核心生命周期的更多信息: https://www.c-sharpcorner.com/article/asp-net-core-mvc-request-life-cycle/