-
Notifications
You must be signed in to change notification settings - Fork 121
Telemetry Initializer to add request body content from .net core MVC app to request telemetry properties not working #686
Comments
@balakrishnanj It is not possible to read the Post/Put body stream twice - so attempting to read it in TelemetryInitializer is not recommended and will fail. If your intention is to populate/enrich RequestTelemetry with some information from the request body, then the following approach is recommended: And you can enrich this requestTelemetry using any values available to your controller. (which includes the request body as well). The following shows a full example
PLease let us know if this helps! |
@balakrishnanj The @cijothomas's approach saves you one extra stream reading. Also, you can add extra properties only in the controller methods where requests suppose to have the body. |
@balakrishnanj please reopen if you have more questions about this. |
"It is not possible to read the Post/Put body stream twice" is not accurate -- the decision to dispose the request body stream prior to invoking telemetry initializers is what prevents reading the body content. The suggestion to capture request bodies in controllers is not feasible -- why should all relevant endpoints be complicated with code to enable a feature clearly in the domain of middleware? Discussion on stack overflow (https://stackoverflow.com/a/42772603) suggests the OP's approach used to work -- now achieving this effect would require middleware to capture all request body content (as opposed to that of failed requests) and plumbing to make that content available in the telemetry initializer. This is a bug, imo. |
@daspoon is spot on. While
|
@cijothomas Please re-open this issue in light of the above comments. Thank you. |
@michaeltnguyen if I want to get the ResponseBody in |
I'm reluctant to go with @michaeltnguyen's workaround described above, because I don't have a good way to remove items in the dictionary supporting Since this is more about the AspNetCore |
@zamzowd You could remove the item in the |
@michaeltnguyen I considered having the record removed when it's read. I was concerned that I might end up with records added that never get read for some reason, but didn't set up a proof-of-concept to see if that would actually happen. I haven't considered using a cache, I might try that out. |
I solved using the following approach and explained the same in the following blog, This is similar to michaeltnguyen idea but bit different in approach. https://thirum.wordpress.com/2019/08/19/logging-the-http-response-body-in-application-insights/ My idea is to record the response using a delegate handler since the response object is not disposed at the stage of the message handler. The message handler is part of the Web API life cycle i.e. similar to the HTTP module but confined to Web API Life cycle. When I developed and tested this idea, fortunately, It worked I recorded the response in the request message using message handler and retrieved it at the AzureInitializer (HTTP module whose execution happens later than the message handler i.e ASP.NET Web API Life cycle order). Here is the sample code. public class AzureRequestResponseInitializer : ITelemetryInitializer
} config.MessageHandlers.Add(new LoggingHandler());
} |
For .NET Core you don't need an public async Task InvokeAsync(HttpContext context)
{
var request = context.Request;
if (request?.Body?.CanRead == true)
{
request.EnableRewind();
var bodySize = (int)(request.ContentLength ?? request.Body.Length);
if (bodySize > 0)
{
request.Body.Position = 0;
byte[] body;
using (var ms = new MemoryStream(bodySize))
{
await request.Body.CopyToAsync(ms);
body = ms.ToArray();
}
request.Body.Position = 0;
var requestTelemetry = context.Features.Get<RequestTelemetry>();
if (requestTelemetry != null)
{
var requestBodyString = Encoding.UTF8.GetString(body);
requestTelemetry.Properties.Add("RequestBody", bodyString);
}
}
}
await _next(context);
} |
@IanKemp I didn't know the |
@IanKemp Thanks for letting us know. It seems to work on the .NET core but not on ASP.NET 4.6(WEB API). Mine is not on core yet. It seems we have limited capability on the traditional .NET side. |
@ThiruKM try var requestTelemetry = HttpContext.Current?.GetRequestTelemetry(). |
@cijothomas Thanks for responding. My web services are not .NET Core it is on .NET 4.6 - Web api but I went ahead I tried using the above code unfortunately it returned null as pictured below |
Please share a full sample. |
@cijothomas It is current that is null. It is on my production code. I am not allowed to share the code but if you want I need to write an sample. |
Where is this code running? I mean is it inside a TelemetryInitializer? And is httpcontext.current null for RequestTelemetry? or some other telemetry? |
It is part of DelegatingHandler as part of the following method. protected override Task SendAsync(HttpRequestMessage request, CancellationToken cancellationToken) |
okay. I am not an expert here, so not sure why context is null there. We have been receiving a lot of requests about how to log request/response body. There will be a official way to achieve this. |
@cijothomas @Dawgfan Thx for spending some time. I have a work around as mentioned in my blog for now. Happy to wait for the official solution. |
Please yes. |
@cijothomas Any update to share on timing of logging request bodies in an officially supported capacity? |
We did not have resource to tackle this in 2019. @Dawgfan has this as one of the top items to handle in 2020. |
Uh oh!
There was an error while loading. Please reload this page.
I'm trying to integrate application insights to .net core MVC application. Everything worked as expected till I added a telemetry initializer to read request body content. I created a ITelemetryInitializer which reads the content from the request body if the telemetry type is request telemetry. But i'm getting "System.ObjectDisposedException: 'Cannot access a disposed object.'" I tried adding Microsoft.ApplicationInsights.AspNetCore as project reference and even the pre-defined initializers are invoked after the action method.
Issue:
On debugging I noticed, when a POST/PUT http call is made, MVC action method is invoked before Initialize() method. So by the time the Initialize() method is invoked, request body request stream is already disposed. I've a similar implementation for 4.6 framework web api application, but its works fine without this issue.
Is there a way I can invoke the initializers before MVC action is executed. I tried configuring application insights with IWebHostBuilder and IServiceCollection.
Did anyone come across this issue?
Version Info
SDK Version : 2.2.1
.NET Version : .Net core 2.0
How Application was onboarded with SDK(VisualStudio/StatusMonitor/Azure Extension) :
OS :
Hosting Info (IIS/Azure WebApps/ etc) : IIS
The text was updated successfully, but these errors were encountered: