Created
December 30, 2020 08:46
-
-
Save alastairtree/05c2ba97f95ab0ec19c1d4221ec63bb4 to your computer and use it in GitHub Desktop.
Using stevejgordon/CorrelationId inside Azure Functions
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.Collections.Generic; | |
using System.Linq; | |
using System.Threading.Tasks; | |
using CorrelationId; | |
using CorrelationId.Abstractions; | |
using Microsoft.AspNetCore.Http; | |
using Microsoft.AspNetCore.Mvc; | |
using Microsoft.Extensions.Logging; | |
using Microsoft.Extensions.Options; | |
using Microsoft.Extensions.Primitives; | |
namespace ExampleFunc | |
{ | |
public class HttpCorrelation | |
{ | |
private readonly CorrelationIdOptions options; | |
private readonly ICorrelationContextAccessor correlationContextAccessor; | |
private readonly ICorrelationIdProvider correlationIdProvider; | |
private readonly ILogger logger; | |
public HttpCorrelation(ICorrelationContextAccessor correlationContextAccessor, | |
IOptions<CorrelationIdOptions> options, ICorrelationIdProvider correlationIdProvider = null, | |
ILogger logger = null) | |
{ | |
this.correlationContextAccessor = correlationContextAccessor; | |
this.options = options.Value; | |
this.correlationIdProvider = correlationIdProvider; | |
this.logger = logger; | |
} | |
// Inspired by and thanks to https://github.com/stevejgordon/CorrelationId/blob/master/src/CorrelationId/CorrelationIdMiddleware.cs | |
public async Task<IActionResult> Execute(HttpRequest request, Func<Task<IActionResult>> function) | |
{ | |
if (correlationIdProvider is null) | |
{ | |
throw new InvalidOperationException( | |
"No 'ICorrelationIdProvider' has been registered. You must either add the correlation ID services" + | |
" using the 'AddDefaultCorrelationId' extension method or you must register a suitable provider using the" + | |
" 'ICorrelationIdBuilder'."); | |
} | |
var hasCorrelationIdHeader = request.Headers.TryGetValue(options.RequestHeader, out var cid) && | |
!StringValues.IsNullOrEmpty(cid); | |
if (!hasCorrelationIdHeader && options.EnforceHeader) | |
{ | |
return new BadRequestObjectResult( | |
$"The '{options.RequestHeader}' request header is required, but was not found."); | |
} | |
var correlationId = hasCorrelationIdHeader ? cid.FirstOrDefault() : null; | |
if (options.IgnoreRequestHeader || RequiresGenerationOfCorrelationId(hasCorrelationIdHeader, cid)) | |
{ | |
correlationId = GenerateCorrelationId(request.HttpContext); | |
} | |
if (!string.IsNullOrEmpty(correlationId) && options.UpdateTraceIdentifier) | |
{ | |
request.HttpContext.TraceIdentifier = correlationId; | |
} | |
correlationContextAccessor.CorrelationContext = | |
new CorrelationContext(correlationId, options.RequestHeader); | |
if (options.IncludeInResponse && !string.IsNullOrEmpty(correlationId)) | |
{ | |
// apply the correlation ID to the response header for client side tracking | |
request.HttpContext.Response.OnStarting(() => | |
{ | |
if (!request.HttpContext.Response.Headers.ContainsKey(options.ResponseHeader)) | |
{ | |
request.HttpContext.Response.Headers.Add(options.ResponseHeader, correlationId); | |
} | |
return Task.CompletedTask; | |
}); | |
} | |
try | |
{ | |
IActionResult result = null; | |
if (options.AddToLoggingScope && !string.IsNullOrEmpty(options.LoggingScopeKey) && | |
!string.IsNullOrEmpty(correlationId)) | |
{ | |
using (logger.BeginScope(new Dictionary<string, object> | |
{ | |
[options.LoggingScopeKey] = correlationId | |
})) | |
{ | |
await function(); | |
} | |
} | |
else | |
{ | |
result = await function(); | |
} | |
return result; | |
} | |
finally | |
{ | |
correlationContextAccessor.CorrelationContext = null; | |
} | |
} | |
private string GenerateCorrelationId(HttpContext ctx) | |
{ | |
string correlationId; | |
if (options.CorrelationIdGenerator is object) | |
{ | |
correlationId = options.CorrelationIdGenerator(); | |
return correlationId; | |
} | |
correlationId = correlationIdProvider.GenerateCorrelationId(ctx); | |
return correlationId; | |
} | |
private static bool RequiresGenerationOfCorrelationId(bool idInHeader, StringValues idFromHeader) => | |
!idInHeader || StringValues.IsNullOrEmpty(idFromHeader); | |
} | |
} |
how are you registering services/middleware now?
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Example use: