azure-application-insights - 通过 ApplicationInsights ITelemetryInitializer 访问时释放 HttpContext.Request.Body
问题描述
我正在尝试POST, PUT, PATCH
使用ITelemetryInitializer
. 每次有帖子进来,虽然我的身体流似乎已经被某种方式处理掉了。我假设请求管道中有一些我没有正确注册/做的事情。
public class RequestBodyLogger : ITelemetryInitializer
{
readonly IHttpContextAccessor httpContextAccessor;
public RequestBodyLogger(IHttpContextAccessor httpContextAccessor)
{
this.httpContextAccessor = httpContextAccessor;
}
public void Initialize(ITelemetry telemetry)
{
try
{
if (telemetry is RequestTelemetry requestTelemetry)
{
if ((httpContextAccessor.HttpContext.Request.Method == HttpMethods.Post ||
httpContextAccessor.HttpContext.Request.Method == HttpMethods.Put ||
httpContextAccessor.HttpContext.Request.Method == HttpMethods.Patch) &&
httpContextAccessor.HttpContext.Request.Body.CanRead)
{
const string jsonBody = "JsonBody";
if (requestTelemetry.Properties.ContainsKey(jsonBody))
{
return;
}
//Allows re-usage of the stream
httpContextAccessor.HttpContext.Request.EnableRewind();
var stream = new StreamReader(httpContextAccessor.HttpContext.Request.Body);
var body = stream.ReadToEnd(); <<Blows here object disposed (stream)
//Reset the stream so data is not lost
httpContextAccessor.HttpContext.Request.Body.Position = 0;
requestTelemetry.Properties.Add(jsonBody, body);
}
}
}
catch (Exception e)
{
}
}
}
配置服务方法...
public void ConfigureServices(IServiceCollection services)
{
if (_env.IsDevelopment())
{
services.AddSwaggerGen(c =>
{
c.SwaggerDoc(Constants.ApiVersion, new Info { Title = Constants.ApiName, Version = Constants.ApiVersion });
c.AddSecurityDefinition("Bearer", new ApiKeyScheme { In = "header", Description = "Please enter Bearer Token", Name = "Authorization", Type = "apiKey" });
c.AddSecurityRequirement(new Dictionary<string, IEnumerable<string>> { { "Bearer", Enumerable.Empty<string>() } });
c.IncludeXmlComments($"{AppDomain.CurrentDomain.BaseDirectory}\\TradeJournal.Api.xml");
});
}
services.AddAuthentication(options =>
{
options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
})
.AddJwtBearer(options =>
{
options.Authority = Configuration["IdentityAuthority"];
options.TokenValidationParameters = new Microsoft.IdentityModel.Tokens.TokenValidationParameters
{
IssuerSigningKeyResolver = (s, securityToken, identifier, parameters) =>
{
var json = new WebClient().DownloadString(parameters.ValidIssuer + "/.well-known/jwks.json");
var keys = JsonConvert.DeserializeObject<JsonWebKeySet>(json).Keys;
return (IEnumerable<SecurityKey>)keys;
},
ValidIssuer = Configuration["IdentityAuthority"],
ValidateIssuerSigningKey = true,
ValidateIssuer = true,
ValidateLifetime = true,
ValidateAudience = false
};
});
services
.AddCors(c =>
{
c.AddPolicy("AllowOrigin", options => options.AllowAnyOrigin().AllowAnyHeader().AllowAnyMethod().AllowCredentials());
});
services.AddMvc(opts =>
{
opts.Filters.Add(typeof(ModelStateValidationFilter));
}).SetCompatibilityVersion(CompatibilityVersion.Version_2_2)
.AddJsonOptions(opt =>
{
opt.SerializerSettings.DateFormatString = "yyyy-MM-ddTHH:mm:ssZ";
});
services.AddSingleton<ITelemetryInitializer, RequestBodyLogger>();
services.AddTransient<ExceptionToHttpResponseMiddleware>();
services.AddTransient<MaintenanceMiddleware>();
services.AddRouting(opts =>
{
opts.LowercaseUrls = true;
opts.LowercaseQueryStrings = true;
});
BootstrapLayers(services);
}
```
Configure method...
public void Configure(IApplicationBuilder app)
{
if (_env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
app.UseSwagger();
// Enable middleware to serve swagger-ui (HTML, JS, CSS, etc.),
// specifying the Swagger JSON endpoint.
app.UseSwaggerUI(c =>
{
c.SwaggerEndpoint($"/swagger/{Constants.ApiVersion}/swagger.json", Constants.ApiName);
});
}
else
{
//The default HSTS value is 30 days.You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
app.UseHsts();
}
app.UseAuthentication();
app.UseCors(options => options.AllowAnyOrigin().AllowAnyMethod().AllowAnyHeader().AllowCredentials());
app.UseMiddleware<ExceptionToHttpResponseMiddleware>();
app.UseMiddleware<MaintenanceMiddleware>();
app.UseHttpsRedirection();
app.UseMvc();
}
**Why is the context disposed by the time AI calls this telemetry initializer?**
解决方案
这也在 github 中讨论:https ://github.com/microsoft/ApplicationInsights-aspnetcore/issues/940#issuecomment-513297006
由于在运行 TelemetryInitializers 时,请求正文已被释放,因此最好的办法是在正文仍然可用时读取正文并将其填充到 RequestTelemetry 中。如果它是控制器或中间件 - 然后在那里检索 RequestTelemetry,向其中添加正文。以下是要在控制器/中间件中编写的示例代码,您可以在其中检索请求正文。
RequestTelemetry reqTelemetry = httpContext?.Features.Get<RequestTelemetry>();
reqTelemetry.Properties.Add("body","body contents").
推荐阅读
- java - 创建新的 libgdx 项目时如何解决此“Launching Box2DBuild”错误?
- qt - DirectShowPlayerService::doRender: 未解决的错误代码 0x80040266(IDispatch 错误 #102)
- docker - 不可删除或持久的 docker-compose 卷或数据存储
- c# - 如何更改父视图模型的属性
- youtube-analytics-api - 通过内容管理器帐户的客户端 ID 访问 youtube 分析 API
- django - 模板中foreginKey的Django问题
- angular - Angular Flex 布局 Pinterest 布局
- jq - jq如何将数组对象合并为单个对象
- email - .ics 托管文件的深层链接未在 Outlook Mobile 中打开
- php - 在 Laravel 中转换日期时间格式