HttpContext和TelemetryInitializer

Dav*_*New 4 azure-application-insights

我想将用户的"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;
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

我可以创建一个动作过滤器来每次设置上下文,但这感觉很糟糕:

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);
    }
}
Run Code Online (Sandbox Code Playgroud)

有没有更好的方法来实现我想做的事情?

yon*_*sha 7

您应该实现WebTelemetryInitializerBase,它为您提供HttpContext.

您的代码应如下所示:

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;
            }
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 如果它的ctor是内部的(基于2.2.0源),你怎么能从'WebTelemetryInitializerBase`派生出来? (5认同)
  • 不幸的是,这似乎与ASP.NET Core/MVC6不兼容. (2认同)

gar*_*m93 6

我建议在 ClaimTelemetryInitializer 类的构造函数中注入一个 HttpContextAccessor 实例,然后你可以使用它从 HttpContext 中提取值。或者,更好的是,为 TelemetryInitializer 创建一个基类,并使用它的构造函数注入 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...
    }
Run Code Online (Sandbox Code Playgroud)

  • 这似乎不起作用,因为即使服务注册使用 Transient 或 Scoped,构造函数在应用程序的生命周期内也只会被命中一次。 (2认同)
  • 我的错误是,我没有意识到 IHttpContextAccessor 创建一个对象引用,因此构造函数不需要被多次点击。这确实有效。 (2认同)