OWIN for correlation and registration of requests and responses?

I am writing a piece of custom OWIN middleware to log all HTTP requests and their responses. I would like to โ€œmatchโ€ them with tracking. Here is the code:

public class PacketTrackingMiddleware { private readonly AppFunc _next; public PacketTrackingMiddleware(AppFunc next) { _next = next; } public async Task Invoke(IDictionary<string, object> environment) { IOwinContext context = new OwinContext(environment); var request = context.Request; var response = context.Response; //capture details about the caller identity var identity = (request.User != null && request.User.Identity.IsAuthenticated) ? request.User.Identity.Name : "(anonymous)"; var apiPacket = new ApiPacket { CallerIdentity = identity }; //buffer the request stream in order to intercept downstream reads var requestBuffer = new MemoryStream(); request.Body = requestBuffer; //buffer the response stream in order to intercept downstream writes var responseStream = response.Body; var responseBuffer = new MemoryStream(); response.Body = responseBuffer; //add the "Http-Tracking-Id" response header context.Response.OnSendingHeaders(state => { var ctx = state as IOwinContext; if (ctx == null) return; var resp = ctx.Response; //adding the tracking id response header so that the user //of the API can correlate the call back to this entry resp.Headers.Add("http-tracking-id", new[] { apiPacket.TrackingId.ToString("d") }); }, context); //invoke the next middleware in the pipeline await _next.Invoke(environment); //rewind the request and response buffers to record their content WriteRequestHeaders(request, apiPacket); requestBuffer.Seek(0, SeekOrigin.Begin); var requestReader = new StreamReader(requestBuffer); apiPacket.Request = await requestReader.ReadToEndAsync(); WriteResponseHeaders(response, apiPacket); responseBuffer.Seek(0, SeekOrigin.Begin); var reader = new StreamReader(responseBuffer); apiPacket.Response = await reader.ReadToEndAsync(); //write the apiPacket to the database //await database.InsterRecordAsync(apiPacket); System.Diagnostics.Debug.WriteLine("TrackingId: " + apiPacket.TrackingId); //make sure the response we buffered is flushed to the client responseBuffer.Seek(0, SeekOrigin.Begin); await responseBuffer.CopyToAsync(responseStream); } private static void WriteRequestHeaders(IOwinRequest request, ApiPacket packet) { packet.Verb = request.Method; packet.RequestUri = request.Uri; packet.RequestHeaders = request.Headers; } private static void WriteResponseHeaders(IOwinResponse response, ApiPacket packet) { packet.StatusCode = response.StatusCode; packet.ReasonPhrase = response.ReasonPhrase; packet.ResponseHeaders = response.Headers; } } 

I am having trouble adding the http-tracking-id identifier to the response header (these lines are here).

 context.Response.OnSendingHeaders(state => { var ctx = state as IOwinContext; if (ctx == null) return; var resp = ctx.Response; resp.Headers.Add("http-tracking-id", new[] { apiPacket.TrackingId.ToString("d") }); }, context); 

When adding a header, I sometimes get this error:

HttpException was not handled by user code.

Additional information: the server cannot add the header after the HTTP headers have been sent.


Edit 1: I test this by simply running the api that opens chrome for my http: // localhost: 64051 / address. If I look through any actual API ( http: // localhost: 64051 / api / Accounts / 21067 ), I do not get this error. Should I somehow just send 404 back while browsing to the root of the site?

+7
c # owin
source share
1 answer

I think this could be a simple fix. Try:

 var responseHeaders = (IDictionary<string, string[]>)environment["owin.ResponseHeaders"]; responseHeaders["http-tracking-id"] = new[] {apiPacket.TrackingId.ToString("d")}; 

But not in context.Response.OnSendingHeaders . Just in line with the rest.

+1
source share

All Articles