skip to Main Content

I want to read the Body of incoming requests with the help of my HttpRequestTelemetryInitializer class. Although my GetRequestHeader method works successfully, I get the following error on the

var body = reader.ReadToEndAsync().Result;

line of my GetRequestBody method.

**

ERROR: Cannot access a disposed object. Object name:
‘HttpRequestStream’.

**

What should I do about this error? Can you help me?

public class HttpRequestTelemetryInitializer : ITelemetryInitializer
{
    private const string _requestBody = "RequestBody";
    private const string _requestHeaders = "RequestHeaders";
    private readonly List<string> _skipBodyLoggingOnErrorApiList;
    private readonly List<string> _skipHeaderLoggingOnErrorApiList;
    private readonly IHttpContextAccessor _httpContextAccessor;

    public HttpRequestTelemetryInitializer(IHttpContextAccessor httpContextAccessor, IConfiguration configuration)
    {
        _httpContextAccessor = httpContextAccessor;
        _skipBodyLoggingOnErrorApiList = configuration.GetSection("HttpRequestTelemetryInitializerConfig:SkipBodyLoggingOnError").Get<List<string>>();
        _skipHeaderLoggingOnErrorApiList = configuration.GetSection("HttpRequestTelemetryInitializerConfig:SkipHeaderLoggingOnError").Get<List<string>>();
    }

    public void Initialize(ITelemetry telemetry)
    {
        try
        {
            if (telemetry == null)
                return;

            if (telemetry is RequestTelemetry requestTelemetry)
            {
                var httpContext = _httpContextAccessor.HttpContext;
                if (httpContext == null || httpContext.Request == null)
                    return;

                var request = httpContext.Request;
                if (request.Method == HttpMethod.Post.Method ||
                    request.Method == HttpMethod.Put.Method ||
                    request.Method == "PATCH")
                {
                    if (!_skipBodyLoggingOnErrorApiList.Any(url => request.Path.Value.Contains(url)))
                    {
                        requestTelemetry.Properties.Add(_requestBody, GetRequestBody(request));
                    }

                    if (!_skipHeaderLoggingOnErrorApiList.Any(url => request.Path.Value.Contains(url)))
                    {
                        requestTelemetry.Properties.Add(_requestHeaders, GetRequestHeaders(request));
                    }
                }
            }
        }
        catch
        {
        }
    }

    private string GetRequestHeaders(HttpRequest request)
    {
        using var writer = new StringWriter();
        foreach (var header in request.Headers)
        {
            writer.WriteLine($"{header.Key}: {header.Value}");
        }
        writer.WriteLine();

        return writer.ToString();
    }

    private string GetRequestBody(HttpRequest request)
    {
        request.EnableBuffering();
        var reader = new StreamReader(request.Body);
        var body = reader.ReadToEndAsync().Result;
        request.Body.Position = 0;
        return body;
    }
}

Startup.cs:

services.AddApplicationInsightsTelemetry();
services.AddSingleton<ITelemetryInitializer, HttpRequestTelemetryInitializer>();

2

Answers


  1. Chosen as BEST ANSWER

    enter image description here

    @Sures Chikkam

    The result still is the same. Does not work your code.


  2. ERROR: Cannot access a disposed object. Object name: ‘HttpRequestStream’.
    What should I do about this error? Can you help me?

    It occurs because the HttpRequestStream is disposed of before you’re trying to read it again.

    • Problem arises when you try to read the body synchronously with ReadToEndAsync().Result, which can lead to issues if the stream is disposed prematurely.

    • Firstly, check that the request body is read asynchronously.

    private async Task<string> GetRequestBodyAsync(HttpRequest request)
    {
        // Enable buffering to allow multiple reads of the body
        request.EnableBuffering();
    
        // Read the request body asynchronously
        using (var reader = new StreamReader(request.Body, Encoding.UTF8, detectEncodingFromByteOrderMarks: false, leaveOpen: true))
        {
            var body = await reader.ReadToEndAsync();
    
            // Rewind the stream for further processing
            request.Body.Position = 0;
    
            return body;
        }
    }
    
    • Update the Initialize method to call the GetRequestBodyAsync method asynchronously.
    public async void Initialize(ITelemetry telemetry)
    {
        try
        {
            if (telemetry == null)
                return;
    
            if (telemetry is RequestTelemetry requestTelemetry)
            {
                var httpContext = _httpContextAccessor.HttpContext;
                if (httpContext == null || httpContext.Request == null)
                    return;
    
                var request = httpContext.Request;
                if (request.Method == HttpMethod.Post.Method ||
                    request.Method == HttpMethod.Put.Method ||
                    request.Method == "PATCH")
                {
                    if (!_skipBodyLoggingOnErrorApiList.Any(url => request.Path.Value.Contains(url)))
                    {
                        requestTelemetry.Properties.Add(_requestBody, await GetRequestBodyAsync(request));
                    }
    
                    if (!_skipHeaderLoggingOnErrorApiList.Any(url => request.Path.Value.Contains(url)))
                    {
                        requestTelemetry.Properties.Add(_requestHeaders, GetRequestHeaders(request));
                    }
                }
            }
        }
        catch
        {
        }
    }
    
    • To generate telemetry data, I have interacted with the application by sending HTTP requests using Postman. Focusing on POST, PUT, and PATCH requests, as these are configured to capture request bodies and headers.

    enter image description here

    Result:

    enter image description here

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search