HttpContext 和 TelemetryInitializer
HttpContext and TelemetryInitializer
我想将用户的 "client_id" 声明作为 属性 附加到发送到 Application Insights 的每个请求。
根据我的阅读,我应该实施 ITelemetryInitializer
但我需要 HttpContext
请求才能检索 "client_id"。查看我的初始化程序:
public class ClaimTelemetryInitializer : ITelemetryInitializer
{
public HttpContext HttpContext { get; set; }
public void Initialize(ITelemetry telemetry)
{
this.AddTelemetryContextPropertFromClaims(telemetry, "client_id");
}
private void AddTelemetryContextPropertFromClaims(ITelemetry telemetry, string claimName)
{
if (HttpContext != null)
{
var requestTelemetry = telemetry as RequestTelemetry;
var claim = HttpContext.User.Claims.SingleOrDefault(x => x.Type.Equals(claimName, StringComparison.InvariantCultureIgnoreCase));
if (claim != null)
{
telemetry.Context.Properties[claimName] = claim.Value;
}
}
}
}
我可以创建一个动作过滤器来每次设置上下文,但这感觉很糟糕:
public class TrackClaimsAttribute : ActionFilterAttribute
{
public override Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next)
{
var initialiser = TelemetryConfiguration.Active.TelemetryInitializers.OfType<ClaimTelemetryInitializer>().Single();
initialiser.HttpContext = context.HttpContext;
return base.OnActionExecutionAsync(context, next);
}
}
有没有更好的方法来实现我想做的事情?
您应该实现为您提供 HttpContext 的 WebTelemetryInitializerBase。
您的代码应如下所示:
public class ClaimTelemetryInitializer : WebTelemetryInitializerBase
{
protected override void OnInitializeTelemetry(
HttpContext platformContext,
RequestTelemetry rootRequestTelemetry,
ITelemetry telemetry) {
var claim = HttpContext.User.Claims.SingleOrDefault(x => x.Type.Equals(claimName, StringComparison.InvariantCultureIgnoreCase));
if (claim != null)
{
telemetry.Context.Properties[claimName] = claim.Value;
}
}
}
我希望将其设计到 AppInsights 中,但您可以直接使用静态 HttpContext.Current
。您可以使用它的每个请求 Items
字典作为短期(接近无状态)存储 space 将您的自定义值传递给自定义遥测处理程序。
所以试试
class AppInsightCustomProps : ITelemetryInitializer
{
public void Initialize(ITelemetry telemetry)
{
var requestTelemetry = telemetry as RequestTelemetry;
// Is this a TrackRequest() ?
if (requestTelemetry == null) return;
var httpCtx = HttpContext.Current;
if (httpCtx != null)
{
var customPropVal = (string)httpCtx.Items["PerRequestMyCustomProp"];
if (!string.IsNullOrWhiteSpace(customPropVal))
{
requestTelemetry.Properties["MyCustomProp"] = customPropVal;
}
}
}
}
为了编写所需的自定义程序 属性,您请求管道中的任何地方都有类似
的内容
if (HttpContext.Current != null)
{
HttpContext.Current.Items["PerRequestMyCustomProp"] = myCustomPropValue;
}
我建议在 ClaimTelemetryInitializer class 的构造函数中注入一个 HttpContextAccessor 实例,然后您可以使用它从 HttpContext 中提取值。
或者,更好的是,为您的 TelemetryInitializer 创建一个基础 class,并使用它的构造函数注入 HttpContextAccessor 实例。
例如:
protected ClaimTelemetryInitializer(IHttpContextAccessor httpContextAccessor)
{
this.httpContextAccessor = httpContextAccessor;
}
public void Initialize(ITelemetry telemetry)
{
var context = this.httpContextAccessor.HttpContext;
if (context == null)
{
return;
}
var claim = context.User.Claims.SingleOrDefault(x => x.Type.Equals(claimName, StringComparison.InvariantCultureIgnoreCase));
//Do logic here...
}
我想将用户的 "client_id" 声明作为 属性 附加到发送到 Application Insights 的每个请求。
根据我的阅读,我应该实施 ITelemetryInitializer
但我需要 HttpContext
请求才能检索 "client_id"。查看我的初始化程序:
public class ClaimTelemetryInitializer : ITelemetryInitializer
{
public HttpContext HttpContext { get; set; }
public void Initialize(ITelemetry telemetry)
{
this.AddTelemetryContextPropertFromClaims(telemetry, "client_id");
}
private void AddTelemetryContextPropertFromClaims(ITelemetry telemetry, string claimName)
{
if (HttpContext != null)
{
var requestTelemetry = telemetry as RequestTelemetry;
var claim = HttpContext.User.Claims.SingleOrDefault(x => x.Type.Equals(claimName, StringComparison.InvariantCultureIgnoreCase));
if (claim != null)
{
telemetry.Context.Properties[claimName] = claim.Value;
}
}
}
}
我可以创建一个动作过滤器来每次设置上下文,但这感觉很糟糕:
public class TrackClaimsAttribute : ActionFilterAttribute
{
public override Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next)
{
var initialiser = TelemetryConfiguration.Active.TelemetryInitializers.OfType<ClaimTelemetryInitializer>().Single();
initialiser.HttpContext = context.HttpContext;
return base.OnActionExecutionAsync(context, next);
}
}
有没有更好的方法来实现我想做的事情?
您应该实现为您提供 HttpContext 的 WebTelemetryInitializerBase。
您的代码应如下所示:
public class ClaimTelemetryInitializer : WebTelemetryInitializerBase
{
protected override void OnInitializeTelemetry(
HttpContext platformContext,
RequestTelemetry rootRequestTelemetry,
ITelemetry telemetry) {
var claim = HttpContext.User.Claims.SingleOrDefault(x => x.Type.Equals(claimName, StringComparison.InvariantCultureIgnoreCase));
if (claim != null)
{
telemetry.Context.Properties[claimName] = claim.Value;
}
}
}
我希望将其设计到 AppInsights 中,但您可以直接使用静态 HttpContext.Current
。您可以使用它的每个请求 Items
字典作为短期(接近无状态)存储 space 将您的自定义值传递给自定义遥测处理程序。
所以试试
class AppInsightCustomProps : ITelemetryInitializer
{
public void Initialize(ITelemetry telemetry)
{
var requestTelemetry = telemetry as RequestTelemetry;
// Is this a TrackRequest() ?
if (requestTelemetry == null) return;
var httpCtx = HttpContext.Current;
if (httpCtx != null)
{
var customPropVal = (string)httpCtx.Items["PerRequestMyCustomProp"];
if (!string.IsNullOrWhiteSpace(customPropVal))
{
requestTelemetry.Properties["MyCustomProp"] = customPropVal;
}
}
}
}
为了编写所需的自定义程序 属性,您请求管道中的任何地方都有类似
的内容if (HttpContext.Current != null)
{
HttpContext.Current.Items["PerRequestMyCustomProp"] = myCustomPropValue;
}
我建议在 ClaimTelemetryInitializer class 的构造函数中注入一个 HttpContextAccessor 实例,然后您可以使用它从 HttpContext 中提取值。 或者,更好的是,为您的 TelemetryInitializer 创建一个基础 class,并使用它的构造函数注入 HttpContextAccessor 实例。
例如:
protected ClaimTelemetryInitializer(IHttpContextAccessor httpContextAccessor)
{
this.httpContextAccessor = httpContextAccessor;
}
public void Initialize(ITelemetry telemetry)
{
var context = this.httpContextAccessor.HttpContext;
if (context == null)
{
return;
}
var claim = context.User.Claims.SingleOrDefault(x => x.Type.Equals(claimName, StringComparison.InvariantCultureIgnoreCase));
//Do logic here...
}