Microsoft.AspNetCore.Http.HttpContext
differs from the HttpContext
in the example.
⚠ Do not edit this section. It is required for docs.microsoft.com ➟ GitHub issue linking.
@breyed Thank you for the feedback! We will assign this to the author so they can update the document accordingly.
It would be great to still see an example for ASP.NET Core. Can't seem to access session in my ITelemetryInitializer as it's null.
Below is how I'm doing it:
services.AddSingleton<ITelemetryInitializer, WebSessionTelemetryInitializer>();
public class WebSessionTelemetryInitializer : TelemetryInitializerBase
{
public WebSessionTelemetryInitializer(IHttpContextAccessor httpContextAccessor)
: base(httpContextAccessor)
{
}
/// <summary>
/// Called when initialize telemetry.
/// </summary>
/// <param name="platformContext">The platform context.</param>
/// <param name="requestTelemetry">The request telemetry.</param>
/// <param name="telemetry">The telemetry.</param>
protected override void OnInitializeTelemetry(HttpContext platformContext, RequestTelemetry requestTelemetry, ITelemetry telemetry)
{
if (platformContext?.User?.Identity == null)
{
return;
}
telemetry.Context.User.Id = platformContext.User.Identity.Name;
telemetry.Context.User.AccountId = // get account from claims
if (platformContext.Request.Cookies != null && platformContext.Request.Cookies.ContainsKey(UIConstants.WebSessionCookieName))
{
var sessionCookieValue = platformContext.Request.Cookies[UIConstants.WebSessionCookieName];
if (!string.IsNullOrEmpty(sessionCookieValue))
{
var sessionCookieParts = sessionCookieValue.Split('|');
if (sessionCookieParts.Length > 0)
{
// Currently SessionContext takes in only SessionId. The cookies has
// SessionAcquisitionDate and SessionRenewDate as well that we are not
// picking for now.
requestTelemetry.Context.Session.Id = sessionCookieParts[0];
}
}
}
}
}
@aherrick Tried that, and my identity is always empty - there are no claims in the claimprincipal.
@aherrick thanks! 👏
Our code for reference for others:
using Microsoft.ApplicationInsights.AspNetCore.TelemetryInitializers;
using Microsoft.ApplicationInsights.Channel;
using Microsoft.ApplicationInsights.DataContracts;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.DependencyInjection;
namespace OurApp.Web.Services
{
//source: https://github.com/MicrosoftDocs/azure-docs/issues/16002#issuecomment-437146249
public class OurTelemetryInitializer : TelemetryInitializerBase
{
public OurTelemetryInitializer(IHttpContextAccessor httpContextAccessor)
: base(httpContextAccessor) { }
protected override void OnInitializeTelemetry(HttpContext httpContext, RequestTelemetry requestTelemetry, ITelemetry telemetry)
{
if (httpContext.RequestServices == null)
return;
var userService = httpContext.RequestServices.GetService<IUserService>();
if (userService == null)
return;
var userId = userService.GetUserId();
if (userId == null)
return;
telemetry.Context.User.Id = userId;
telemetry.Context.User.AccountId = userId;
}
}
}
@aherrick Tried that, and my identity is always empty - there are no claims in the claimprincipal.
Same here, the claims principal is always empty. I am using Windows Integrated Authentication, and I can see my custom authorization handlers being triggered.
adding @cijothomas
This is what I used. The claims principal has values after the user has logged in as expected.
```c#
using Microsoft.ApplicationInsights.Channel;
using Microsoft.ApplicationInsights.DataContracts;
using Microsoft.ApplicationInsights.Extensibility;
using Microsoft.AspNetCore.Http;
using System.Linq;
using System.Security.Claims;
namespace My.App.Namespace {
public class TelemetryInitializer : ITelemetryInitializer {
private readonly IHttpContextAccessor _httpContextAccessor;
public TelemetryInitializer(
IHttpContextAccessor httpContextAccessor) {
_httpContextAccessor = httpContextAccessor;
}
public void Initialize( ITelemetry telemetry ) {
//Make sure this is a request telemetry entry
if ( telemetry as RequestTelemetry == null ) { return; }
//Get the current http context
HttpContext httpCtx = _httpContextAccessor.HttpContext;
//Check if the user is authenticated
if ( httpCtx?.User?.Identity.IsAuthenticated ?? false ) {
//Add the details to the telemetry
telemetry.Context.User.AuthenticatedUserId = httpCtx.User.Claims.FirstOrDefault( c => c.Type == ClaimTypes.NameIdentifier )?.Value;
}
}
}
}
And then in `Startup.cs`:
```c#
using Microsoft.ApplicationInsights.Extensibility;
using Microsoft.AspNetCore.Http;
using My.App.Namespace;
And in ConfigureServices()
:
c#
services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
services.AddSingleton<ITelemetryInitializer, TelemetryInitializer>();
@rmarskell
services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
is added by SDK so you don't need to add again. There are several threading issues with using HttpContextAccessor, - https://github.com/microsoft/ApplicationInsights-aspnetcore/issues/373
services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
is added by SDK so you don't need to add again. There are several threading issues with using HttpContextAccessor, - microsoft/ApplicationInsights-aspnetcore#373
@cijothomas
What is the recommended way of attaching details about the currently logged on user to the telemetry then?
Hmm. I don't really understand why it's so difficult to properly add the user ID to the telemetry. Until yesterday, I had assumed this was handled automatically.
Its easy to add user id to telemetry. The tricky part is retrieving userid from HttpContextAccessor.
ApplicationInsights is doing it after taking a lock (https://github.com/microsoft/ApplicationInsights-aspnetcore/blob/develop/NETCORE/src/Microsoft.ApplicationInsights.AspNetCore/TelemetryInitializers/TelemetryInitializerBase.cs#L41)
If you are doing this yourself (i.e reading from context and populating,) then it should be protected with locks as sdk does.
Also this issue (https://github.com/aspnet/AspNetCore/issues/14975) about HttpContextAccessor.
I wanted to include User-Agent to all my request telemetry and this worked for me on ASP .NET Core app.
1) Create a custom telemetry initializer that inherits from the ITelemetryInitilizer. Inject HttpContext so that the user-agent can be retrieved from the current HTTP request. If a telemetry is of type request, set the the user-agent as UserId.
public class MyCustomTelemetryInitializer: ITelemetryInitializer
{
readonly IHttpContextAccessor _httpContextAccessor;
public MyCustomTelemetryInitializer(IHttpContextAccessor httpContextAccessor)
{
_httpContextAccessor = httpContextAccessor;
}
public void Initialize(ITelemetry telemetry)
{
if (telemetry is RequestTelemetry requestTelemetry)
{
requestTelemetry.Context.User.Id = _httpContextAccessor.HttpContext.Request.Headers["User-Agent"];
}
}
}
2) Register the custom initilizer in your app startup
builder.Services.AddSingleton<ITelemetryInitializer, MyCustomTelemetryInitializer>();
3) The User-Agent will now appear on the UserId column of request telemetry.
@jordanchang User-Agent
specifies the user's web browser (Chrome, Edge, etc.); it doesn't identify the human who is signed in.
I have tried all the solutions above and Identity.Name is null, except for database dependency calls. Is there a requirement for what order the services are added to the container?
I have tried all the solutions above and Identity.Name is null, except for database dependency calls. Is there a requirement for what order the services are added to the container?
I worked this through with Microsoft support and it appears as if the cause in my case was adding the accessor to the container in startup cs. I removed the extra call to add the accessor and it appears to be working now https://github.com/MicrosoftDocs/azure-docs/issues/16002#issuecomment-549936486
Can we please have an updated working example for ASP.NET Core written in this doc. page?
@SamaraSoucy-MSFT Remove me from this, I haven't worked on it in years.
Most helpful comment
Hmm. I don't really understand why it's so difficult to properly add the user ID to the telemetry. Until yesterday, I had assumed this was handled automatically.