diff --git a/Directory.Packages.props b/Directory.Packages.props
index e8c3239..4777e38 100644
--- a/Directory.Packages.props
+++ b/Directory.Packages.props
@@ -11,6 +11,10 @@
+
+
+
+
@@ -20,4 +24,4 @@
-
+
\ No newline at end of file
diff --git a/Http.Correlation.sln b/Http.Correlation.sln
index 3bb1821..3fb276d 100644
--- a/Http.Correlation.sln
+++ b/Http.Correlation.sln
@@ -50,6 +50,20 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "NetEvolve.Http.Correlation.
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "NetEvolve.Http.Correlation.HttpClient.Tests.Unit", "tests\NetEvolve.Http.Correlation.HttpClient.Tests.Unit\NetEvolve.Http.Correlation.HttpClient.Tests.Unit.csproj", "{15F2CFB5-C89E-4F93-86E8-F20B98DDC7AC}"
EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "NetEvolve.Http.Correlation.Functions", "src\NetEvolve.Http.Correlation.Functions\NetEvolve.Http.Correlation.Functions.csproj", "{4D933E7A-4828-4BAA-AE47-CE032D5B8973}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "NetEvolve.Http.Correlation.Functions.Tests.Unit", "tests\NetEvolve.Http.Correlation.Functions.Tests.Unit\NetEvolve.Http.Correlation.Functions.Tests.Unit.csproj", "{20994B9E-C3F1-4400-AB82-B569753BB17F}"
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "sample", "sample", "{A85D3A46-4B31-4451-B7CE-4CCD59A5A903}"
+ ProjectSection(SolutionItems) = preProject
+ sample\Directory.Build.props = sample\Directory.Build.props
+ sample\Directory.Packages.props = sample\Directory.Packages.props
+ EndProjectSection
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Sample.WebApi.NET7", "sample\Sample.WebApi.NET7\Sample.WebApi.NET7.csproj", "{EB620E13-40E6-4147-95BE-34F26FB67A6C}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Sample.WebApi.NET6", "sample\Sample.WebApi.NET6\Sample.WebApi.NET6.csproj", "{033D1201-E3EB-4AD6-AF81-FDE2330ED0F5}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -88,6 +102,22 @@ Global
{15F2CFB5-C89E-4F93-86E8-F20B98DDC7AC}.Debug|Any CPU.Build.0 = Debug|Any CPU
{15F2CFB5-C89E-4F93-86E8-F20B98DDC7AC}.Release|Any CPU.ActiveCfg = Release|Any CPU
{15F2CFB5-C89E-4F93-86E8-F20B98DDC7AC}.Release|Any CPU.Build.0 = Release|Any CPU
+ {4D933E7A-4828-4BAA-AE47-CE032D5B8973}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {4D933E7A-4828-4BAA-AE47-CE032D5B8973}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {4D933E7A-4828-4BAA-AE47-CE032D5B8973}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {4D933E7A-4828-4BAA-AE47-CE032D5B8973}.Release|Any CPU.Build.0 = Release|Any CPU
+ {20994B9E-C3F1-4400-AB82-B569753BB17F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {20994B9E-C3F1-4400-AB82-B569753BB17F}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {20994B9E-C3F1-4400-AB82-B569753BB17F}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {20994B9E-C3F1-4400-AB82-B569753BB17F}.Release|Any CPU.Build.0 = Release|Any CPU
+ {EB620E13-40E6-4147-95BE-34F26FB67A6C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {EB620E13-40E6-4147-95BE-34F26FB67A6C}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {EB620E13-40E6-4147-95BE-34F26FB67A6C}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {EB620E13-40E6-4147-95BE-34F26FB67A6C}.Release|Any CPU.Build.0 = Release|Any CPU
+ {033D1201-E3EB-4AD6-AF81-FDE2330ED0F5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {033D1201-E3EB-4AD6-AF81-FDE2330ED0F5}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {033D1201-E3EB-4AD6-AF81-FDE2330ED0F5}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {033D1201-E3EB-4AD6-AF81-FDE2330ED0F5}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@@ -101,6 +131,10 @@ Global
{AB2142E3-0EB7-4E37-B3D7-CF11B540A9B3} = {966730BD-654E-4160-B960-1913EAA151CA}
{6A992CD1-15F8-4BC3-98E6-0492C638C2D8} = {DCCA63A9-B066-4B95-AD66-20DE5F372403}
{15F2CFB5-C89E-4F93-86E8-F20B98DDC7AC} = {966730BD-654E-4160-B960-1913EAA151CA}
+ {4D933E7A-4828-4BAA-AE47-CE032D5B8973} = {DCCA63A9-B066-4B95-AD66-20DE5F372403}
+ {20994B9E-C3F1-4400-AB82-B569753BB17F} = {966730BD-654E-4160-B960-1913EAA151CA}
+ {EB620E13-40E6-4147-95BE-34F26FB67A6C} = {A85D3A46-4B31-4451-B7CE-4CCD59A5A903}
+ {033D1201-E3EB-4AD6-AF81-FDE2330ED0F5} = {A85D3A46-4B31-4451-B7CE-4CCD59A5A903}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {6EA9C0B3-11F7-4677-A2CF-6A4F280BA2A5}
diff --git a/sample/Directory.Build.props b/sample/Directory.Build.props
new file mode 100644
index 0000000..503cf93
--- /dev/null
+++ b/sample/Directory.Build.props
@@ -0,0 +1,9 @@
+
+
+
+
+
+ CS1591
+
+
+
diff --git a/sample/Directory.Packages.props b/sample/Directory.Packages.props
new file mode 100644
index 0000000..6fb5f6c
--- /dev/null
+++ b/sample/Directory.Packages.props
@@ -0,0 +1,8 @@
+
+
+
+ false
+ false
+
+
+
diff --git a/sample/Sample.WebApi.NET6/Controllers/WeatherForecastController.cs b/sample/Sample.WebApi.NET6/Controllers/WeatherForecastController.cs
new file mode 100644
index 0000000..ef1c58b
--- /dev/null
+++ b/sample/Sample.WebApi.NET6/Controllers/WeatherForecastController.cs
@@ -0,0 +1,48 @@
+namespace Sample.WebApi.NET6.Controllers;
+
+using Microsoft.AspNetCore.Mvc;
+using System;
+using System.Collections.Generic;
+using System.Diagnostics.CodeAnalysis;
+using System.Linq;
+
+[ApiController]
+[Route("[controller]")]
+public class WeatherForecastController : ControllerBase
+{
+ private static readonly string[] _summaries = new[]
+ {
+ "Freezing",
+ "Bracing",
+ "Chilly",
+ "Cool",
+ "Mild",
+ "Warm",
+ "Balmy",
+ "Hot",
+ "Sweltering",
+ "Scorching"
+ };
+
+ public WeatherForecastController() { }
+
+ [HttpGet]
+ [SuppressMessage(
+ "Security",
+ "CA5394:Do not use insecure randomness",
+ Justification = "As designed."
+ )]
+ public IEnumerable Get() =>
+ Enumerable
+ .Range(1, 5)
+ .Select(
+ index =>
+ new WeatherForecast
+ {
+ Date = DateTime.UtcNow.AddDays(index),
+ TemperatureC = Random.Shared.Next(-20, 55),
+ Summary = _summaries[Random.Shared.Next(_summaries.Length)]
+ }
+ )
+ .ToArray();
+}
diff --git a/sample/Sample.WebApi.NET6/Program.cs b/sample/Sample.WebApi.NET6/Program.cs
new file mode 100644
index 0000000..08e642a
--- /dev/null
+++ b/sample/Sample.WebApi.NET6/Program.cs
@@ -0,0 +1,32 @@
+namespace Sample.WebApi.NET6;
+
+using Microsoft.AspNetCore.Builder;
+using Microsoft.Extensions.DependencyInjection;
+using NetEvolve.Http.Correlation;
+
+public static class Program
+{
+ public static void Main(string[] args)
+ {
+ var builder = WebApplication.CreateBuilder(args);
+
+ // Add services to the container.
+ _ = builder.Services.AddControllers();
+
+ // Add Http correlation support
+ _ = builder.Services.AddHttpCorrelation().WithGuidGenerator();
+
+ var app = builder.Build();
+
+ // Configure the HTTP request pipeline.
+ _ = app.UseHttpCorrelation();
+
+ _ = app.UseHttpsRedirection();
+
+ _ = app.UseAuthorization();
+
+ _ = app.MapControllers();
+
+ app.Run();
+ }
+}
diff --git a/sample/Sample.WebApi.NET6/Properties/launchSettings.json b/sample/Sample.WebApi.NET6/Properties/launchSettings.json
new file mode 100644
index 0000000..47d4c77
--- /dev/null
+++ b/sample/Sample.WebApi.NET6/Properties/launchSettings.json
@@ -0,0 +1,31 @@
+{
+ "$schema": "https://json.schemastore.org/launchsettings.json",
+ "iisSettings": {
+ "windowsAuthentication": false,
+ "anonymousAuthentication": true,
+ "iisExpress": {
+ "applicationUrl": "http://localhost:30976",
+ "sslPort": 44320
+ }
+ },
+ "profiles": {
+ "Sample.WebApi.NET6": {
+ "commandName": "Project",
+ "dotnetRunMessages": true,
+ "launchBrowser": true,
+ "launchUrl": "weatherforecast",
+ "applicationUrl": "https://localhost:7269;http://localhost:5199",
+ "environmentVariables": {
+ "ASPNETCORE_ENVIRONMENT": "Development"
+ }
+ },
+ "IIS Express": {
+ "commandName": "IISExpress",
+ "launchBrowser": true,
+ "launchUrl": "weatherforecast",
+ "environmentVariables": {
+ "ASPNETCORE_ENVIRONMENT": "Development"
+ }
+ }
+ }
+}
diff --git a/sample/Sample.WebApi.NET6/Sample.WebApi.NET6.csproj b/sample/Sample.WebApi.NET6/Sample.WebApi.NET6.csproj
new file mode 100644
index 0000000..e8950ef
--- /dev/null
+++ b/sample/Sample.WebApi.NET6/Sample.WebApi.NET6.csproj
@@ -0,0 +1,11 @@
+
+
+
+ net6.0
+
+
+
+
+
+
+
diff --git a/sample/Sample.WebApi.NET6/WeatherForecast.cs b/sample/Sample.WebApi.NET6/WeatherForecast.cs
new file mode 100644
index 0000000..d7167c2
--- /dev/null
+++ b/sample/Sample.WebApi.NET6/WeatherForecast.cs
@@ -0,0 +1,14 @@
+namespace Sample.WebApi.NET6;
+
+using System;
+
+public class WeatherForecast
+{
+ public DateTime Date { get; set; }
+
+ public int TemperatureC { get; set; }
+
+ public int TemperatureF => 32 + (int)(TemperatureC / 0.5556);
+
+ public string? Summary { get; set; }
+}
diff --git a/sample/Sample.WebApi.NET6/appsettings.Development.json b/sample/Sample.WebApi.NET6/appsettings.Development.json
new file mode 100644
index 0000000..0c208ae
--- /dev/null
+++ b/sample/Sample.WebApi.NET6/appsettings.Development.json
@@ -0,0 +1,8 @@
+{
+ "Logging": {
+ "LogLevel": {
+ "Default": "Information",
+ "Microsoft.AspNetCore": "Warning"
+ }
+ }
+}
diff --git a/sample/Sample.WebApi.NET6/appsettings.json b/sample/Sample.WebApi.NET6/appsettings.json
new file mode 100644
index 0000000..10f68b8
--- /dev/null
+++ b/sample/Sample.WebApi.NET6/appsettings.json
@@ -0,0 +1,9 @@
+{
+ "Logging": {
+ "LogLevel": {
+ "Default": "Information",
+ "Microsoft.AspNetCore": "Warning"
+ }
+ },
+ "AllowedHosts": "*"
+}
diff --git a/sample/Sample.WebApi.NET7/Controllers/WeatherForecastController.cs b/sample/Sample.WebApi.NET7/Controllers/WeatherForecastController.cs
new file mode 100644
index 0000000..563004d
--- /dev/null
+++ b/sample/Sample.WebApi.NET7/Controllers/WeatherForecastController.cs
@@ -0,0 +1,48 @@
+namespace Sample.WebApi.NET7.Controllers;
+
+using Microsoft.AspNetCore.Mvc;
+using System;
+using System.Collections.Generic;
+using System.Diagnostics.CodeAnalysis;
+using System.Linq;
+
+[ApiController]
+[Route("[controller]")]
+public class WeatherForecastController : ControllerBase
+{
+ private static readonly string[] _summaries = new[]
+ {
+ "Freezing",
+ "Bracing",
+ "Chilly",
+ "Cool",
+ "Mild",
+ "Warm",
+ "Balmy",
+ "Hot",
+ "Sweltering",
+ "Scorching"
+ };
+
+ public WeatherForecastController() { }
+
+ [HttpGet]
+ [SuppressMessage(
+ "Security",
+ "CA5394:Do not use insecure randomness",
+ Justification = "As designed."
+ )]
+ public IEnumerable Get() =>
+ Enumerable
+ .Range(1, 5)
+ .Select(
+ index =>
+ new WeatherForecast
+ {
+ Date = DateOnly.FromDateTime(DateTime.UtcNow.AddDays(index)),
+ TemperatureC = Random.Shared.Next(-20, 55),
+ Summary = _summaries[Random.Shared.Next(_summaries.Length)]
+ }
+ )
+ .ToArray();
+}
diff --git a/sample/Sample.WebApi.NET7/Program.cs b/sample/Sample.WebApi.NET7/Program.cs
new file mode 100644
index 0000000..53eee65
--- /dev/null
+++ b/sample/Sample.WebApi.NET7/Program.cs
@@ -0,0 +1,32 @@
+namespace Sample.WebApi.NET7;
+
+using Microsoft.AspNetCore.Builder;
+using Microsoft.Extensions.DependencyInjection;
+using NetEvolve.Http.Correlation;
+
+public static class Program
+{
+ public static void Main(string[] args)
+ {
+ var builder = WebApplication.CreateBuilder(args);
+
+ // Add services to the container.
+ _ = builder.Services.AddControllers();
+
+ // Add Http correlation support
+ _ = builder.Services.AddHttpCorrelation().WithGuidGenerator();
+
+ var app = builder.Build();
+
+ // Configure the HTTP request pipeline.
+ _ = app.UseHttpCorrelation();
+
+ _ = app.UseHttpsRedirection();
+
+ _ = app.UseAuthorization();
+
+ _ = app.MapControllers();
+
+ app.Run();
+ }
+}
diff --git a/sample/Sample.WebApi.NET7/Properties/launchSettings.json b/sample/Sample.WebApi.NET7/Properties/launchSettings.json
new file mode 100644
index 0000000..f1e2b63
--- /dev/null
+++ b/sample/Sample.WebApi.NET7/Properties/launchSettings.json
@@ -0,0 +1,41 @@
+{
+ "$schema": "https://json.schemastore.org/launchsettings.json",
+ "iisSettings": {
+ "windowsAuthentication": false,
+ "anonymousAuthentication": true,
+ "iisExpress": {
+ "applicationUrl": "http://localhost:42861",
+ "sslPort": 44381
+ }
+ },
+ "profiles": {
+ "http": {
+ "commandName": "Project",
+ "dotnetRunMessages": true,
+ "launchBrowser": true,
+ "launchUrl": "weatherforecast",
+ "applicationUrl": "http://localhost:5114",
+ "environmentVariables": {
+ "ASPNETCORE_ENVIRONMENT": "Development"
+ }
+ },
+ "https": {
+ "commandName": "Project",
+ "dotnetRunMessages": true,
+ "launchBrowser": true,
+ "launchUrl": "weatherforecast",
+ "applicationUrl": "https://localhost:7203;http://localhost:5114",
+ "environmentVariables": {
+ "ASPNETCORE_ENVIRONMENT": "Development"
+ }
+ },
+ "IIS Express": {
+ "commandName": "IISExpress",
+ "launchBrowser": true,
+ "launchUrl": "weatherforecast",
+ "environmentVariables": {
+ "ASPNETCORE_ENVIRONMENT": "Development"
+ }
+ }
+ }
+}
diff --git a/sample/Sample.WebApi.NET7/Sample.WebApi.NET7.csproj b/sample/Sample.WebApi.NET7/Sample.WebApi.NET7.csproj
new file mode 100644
index 0000000..352d970
--- /dev/null
+++ b/sample/Sample.WebApi.NET7/Sample.WebApi.NET7.csproj
@@ -0,0 +1,11 @@
+
+
+
+ net7.0
+
+
+
+
+
+
+
diff --git a/sample/Sample.WebApi.NET7/WeatherForecast.cs b/sample/Sample.WebApi.NET7/WeatherForecast.cs
new file mode 100644
index 0000000..4ef2abf
--- /dev/null
+++ b/sample/Sample.WebApi.NET7/WeatherForecast.cs
@@ -0,0 +1,14 @@
+namespace Sample.WebApi.NET7;
+
+using System;
+
+public class WeatherForecast
+{
+ public DateOnly Date { get; set; }
+
+ public int TemperatureC { get; set; }
+
+ public int TemperatureF => 32 + (int)(TemperatureC / 0.5556);
+
+ public string? Summary { get; set; }
+}
diff --git a/sample/Sample.WebApi.NET7/appsettings.Development.json b/sample/Sample.WebApi.NET7/appsettings.Development.json
new file mode 100644
index 0000000..0c208ae
--- /dev/null
+++ b/sample/Sample.WebApi.NET7/appsettings.Development.json
@@ -0,0 +1,8 @@
+{
+ "Logging": {
+ "LogLevel": {
+ "Default": "Information",
+ "Microsoft.AspNetCore": "Warning"
+ }
+ }
+}
diff --git a/sample/Sample.WebApi.NET7/appsettings.json b/sample/Sample.WebApi.NET7/appsettings.json
new file mode 100644
index 0000000..10f68b8
--- /dev/null
+++ b/sample/Sample.WebApi.NET7/appsettings.json
@@ -0,0 +1,9 @@
+{
+ "Logging": {
+ "LogLevel": {
+ "Default": "Information",
+ "Microsoft.AspNetCore": "Warning"
+ }
+ },
+ "AllowedHosts": "*"
+}
diff --git a/src/NetEvolve.Http.Correlation.Abstractions/NetEvolve.Http.Correlation.Abstractions.csproj b/src/NetEvolve.Http.Correlation.Abstractions/NetEvolve.Http.Correlation.Abstractions.csproj
index d2fe805..c2ef90e 100644
--- a/src/NetEvolve.Http.Correlation.Abstractions/NetEvolve.Http.Correlation.Abstractions.csproj
+++ b/src/NetEvolve.Http.Correlation.Abstractions/NetEvolve.Http.Correlation.Abstractions.csproj
@@ -13,6 +13,7 @@
+
diff --git a/src/NetEvolve.Http.Correlation.AspNetCore/HttpCorrelationMiddleware.cs b/src/NetEvolve.Http.Correlation.AspNetCore/HttpCorrelationMiddleware.cs
index e9bf0d5..60ed776 100644
--- a/src/NetEvolve.Http.Correlation.AspNetCore/HttpCorrelationMiddleware.cs
+++ b/src/NetEvolve.Http.Correlation.AspNetCore/HttpCorrelationMiddleware.cs
@@ -28,7 +28,11 @@ public async Task InvokeAsync(HttpContext context)
{
string? correlationId = null;
if (
- GetCorrelationIdFromHeader(context, out var correlationIdValues, out var usedHeaderName)
+ GetCorrelationIdFromHeader(
+ context.Request,
+ out var correlationIdValues,
+ out var usedHeaderName
+ )
)
{
correlationId = correlationIdValues.FirstOrDefault();
@@ -36,7 +40,7 @@ public async Task InvokeAsync(HttpContext context)
if (string.IsNullOrWhiteSpace(correlationId))
{
- correlationId = GeneratedCorrelationId(context);
+ correlationId = GenerateCorrelationId(context);
}
context.TraceIdentifier = correlationId;
@@ -53,8 +57,11 @@ public async Task InvokeAsync(HttpContext context)
return Task.CompletedTask;
});
- var accessor = context.RequestServices.GetService()!;
- accessor.HeaderName = usedHeaderName;
+ var accessor = context.RequestServices.GetService();
+ if (accessor is not null)
+ {
+ accessor.HeaderName = usedHeaderName;
+ }
var scopeProperties = new Dictionary { { usedHeaderName, correlationId } };
@@ -64,7 +71,7 @@ public async Task InvokeAsync(HttpContext context)
}
}
- private static string GeneratedCorrelationId(HttpContext context)
+ private static string GenerateCorrelationId(HttpContext context)
{
var correlationIdGenerator = context
.RequestServices
@@ -76,7 +83,7 @@ private static string GeneratedCorrelationId(HttpContext context)
}
private static bool GetCorrelationIdFromHeader(
- HttpContext context,
+ HttpRequest request,
out StringValues correlationId,
out string usedHeaderName
)
@@ -84,7 +91,7 @@ out string usedHeaderName
usedHeaderName = HeaderName1;
if (
- context.Request.Headers.TryGetValue(HeaderName1, out correlationId)
+ request.Headers.TryGetValue(HeaderName1, out correlationId)
&& !StringValues.IsNullOrEmpty(correlationId)
)
{
@@ -92,7 +99,7 @@ out string usedHeaderName
}
if (
- context.Request.Headers.TryGetValue(HeaderName2, out correlationId)
+ request.Headers.TryGetValue(HeaderName2, out correlationId)
&& !StringValues.IsNullOrEmpty(correlationId)
)
{
diff --git a/src/NetEvolve.Http.Correlation.Functions/HttpCorrelationFunctionsWorkerMiddleware.cs b/src/NetEvolve.Http.Correlation.Functions/HttpCorrelationFunctionsWorkerMiddleware.cs
new file mode 100644
index 0000000..e4bfb6f
--- /dev/null
+++ b/src/NetEvolve.Http.Correlation.Functions/HttpCorrelationFunctionsWorkerMiddleware.cs
@@ -0,0 +1,102 @@
+namespace NetEvolve.Http.Correlation.Functions;
+
+using Microsoft.Azure.Functions.Worker;
+using Microsoft.Azure.Functions.Worker.Http;
+using Microsoft.Azure.Functions.Worker.Middleware;
+using Microsoft.Extensions.DependencyInjection;
+using Microsoft.Extensions.Primitives;
+using NetEvolve.Http.Correlation.Abstractions;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading.Tasks;
+
+using static CorrelationConstants;
+
+internal sealed class HttpCorrelationFunctionsWorkerMiddleware : IFunctionsWorkerMiddleware
+{
+ public async Task Invoke(FunctionContext context, FunctionExecutionDelegate next)
+ {
+ var logger = context.GetLogger();
+ var correlationId = StringValues.Empty;
+ var usedHeaderName = HeaderName1;
+
+ try
+ {
+ // Support HttpTrigger
+ if (StringValues.IsNullOrEmpty(correlationId))
+ {
+ var httpRequest = await context.GetHttpRequestDataAsync().ConfigureAwait(false);
+ if (httpRequest is not null)
+ {
+ correlationId = GetCorrelationIdFromHttpRequest(
+ httpRequest,
+ out usedHeaderName
+ );
+ }
+ }
+
+ if (StringValues.IsNullOrEmpty(correlationId))
+ {
+ correlationId = GenerateCorrelationId(context);
+ }
+
+ var scopeProperties = new Dictionary
+ {
+ { usedHeaderName, correlationId.ToString() }
+ };
+ using (logger.BeginScope(scopeProperties))
+ {
+ var accessor = context.InstanceServices.GetService();
+ if (accessor is not null)
+ {
+ accessor.HeaderName = usedHeaderName;
+ }
+
+ await next(context).ConfigureAwait(false);
+ }
+ }
+ finally
+ {
+ var response = context.GetHttpResponseData();
+ if (response is not null)
+ {
+ _ = response.Headers.Remove(usedHeaderName);
+ response.Headers.Add(usedHeaderName, correlationId.ToString());
+ }
+ }
+ }
+
+ private static StringValues GenerateCorrelationId(FunctionContext context)
+ {
+ StringValues correlationId;
+ var correlationIdGenerator =
+ context.InstanceServices.GetService();
+
+ correlationId = correlationIdGenerator is null
+ ? context.InvocationId
+ : correlationIdGenerator.GenerateId();
+ return correlationId;
+ }
+
+ private static StringValues GetCorrelationIdFromHttpRequest(
+ HttpRequestData request,
+ out string usedHeaderName
+ )
+ {
+ if (request.Headers.TryGetValues(HeaderName1, out var values) && values.Any())
+ {
+ usedHeaderName = HeaderName1;
+ return values.FirstOrDefault();
+ }
+ else if (request.Headers.TryGetValues(HeaderName2, out values) && values.Any())
+ {
+ usedHeaderName = HeaderName2;
+ return values.FirstOrDefault();
+ }
+
+ usedHeaderName = HeaderName1;
+
+ return StringValues.Empty;
+ }
+}
diff --git a/src/NetEvolve.Http.Correlation.Functions/NetEvolve.Http.Correlation.Functions.csproj b/src/NetEvolve.Http.Correlation.Functions/NetEvolve.Http.Correlation.Functions.csproj
new file mode 100644
index 0000000..e882d0c
--- /dev/null
+++ b/src/NetEvolve.Http.Correlation.Functions/NetEvolve.Http.Correlation.Functions.csproj
@@ -0,0 +1,25 @@
+
+
+
+ net6.0;net7.0
+
+
+
+
+ Implementation of AspNetCore middleware to use Http.Correlation. Based on the primary Http header `X-Correlation-ID` as well as the alternative Http header `X-Request-ID`.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/NetEvolve.Http.Correlation.Functions/README.md b/src/NetEvolve.Http.Correlation.Functions/README.md
new file mode 100644
index 0000000..570f4e7
--- /dev/null
+++ b/src/NetEvolve.Http.Correlation.Functions/README.md
@@ -0,0 +1 @@
+Please give the customer a brief introduction about this library, and how to use it.
diff --git a/tests/NetEvolve.Http.Correlation.Abstractions.Tests.Unit/UnitTest1.cs b/tests/NetEvolve.Http.Correlation.Abstractions.Tests.Unit/UnitTest1.cs
index a16974c..a9ecbfe 100644
--- a/tests/NetEvolve.Http.Correlation.Abstractions.Tests.Unit/UnitTest1.cs
+++ b/tests/NetEvolve.Http.Correlation.Abstractions.Tests.Unit/UnitTest1.cs
@@ -1,5 +1,7 @@
namespace NetEvolve.Http.Correlation.Abstractions.Tests.Unit;
+using Xunit;
+
public class UnitTest1
{
[Fact]
diff --git a/tests/NetEvolve.Http.Correlation.Abstractions.Tests.Unit/Usings.cs b/tests/NetEvolve.Http.Correlation.Abstractions.Tests.Unit/Usings.cs
deleted file mode 100644
index 9df1d42..0000000
--- a/tests/NetEvolve.Http.Correlation.Abstractions.Tests.Unit/Usings.cs
+++ /dev/null
@@ -1 +0,0 @@
-global using Xunit;
diff --git a/tests/NetEvolve.Http.Correlation.AspNetCore.Tests.Unit/UnitTest1.cs b/tests/NetEvolve.Http.Correlation.AspNetCore.Tests.Unit/UnitTest1.cs
index e5312b8..c4c95c1 100644
--- a/tests/NetEvolve.Http.Correlation.AspNetCore.Tests.Unit/UnitTest1.cs
+++ b/tests/NetEvolve.Http.Correlation.AspNetCore.Tests.Unit/UnitTest1.cs
@@ -1,5 +1,7 @@
namespace NetEvolve.Http.Correlation.AspNetCore.Tests.Unit;
+using Xunit;
+
public class UnitTest1
{
[Fact]
diff --git a/tests/NetEvolve.Http.Correlation.AspNetCore.Tests.Unit/Usings.cs b/tests/NetEvolve.Http.Correlation.AspNetCore.Tests.Unit/Usings.cs
deleted file mode 100644
index 9df1d42..0000000
--- a/tests/NetEvolve.Http.Correlation.AspNetCore.Tests.Unit/Usings.cs
+++ /dev/null
@@ -1 +0,0 @@
-global using Xunit;
diff --git a/tests/NetEvolve.Http.Correlation.Functions.Tests.Unit/NetEvolve.Http.Correlation.Functions.Tests.Unit.csproj b/tests/NetEvolve.Http.Correlation.Functions.Tests.Unit/NetEvolve.Http.Correlation.Functions.Tests.Unit.csproj
new file mode 100644
index 0000000..dacd395
--- /dev/null
+++ b/tests/NetEvolve.Http.Correlation.Functions.Tests.Unit/NetEvolve.Http.Correlation.Functions.Tests.Unit.csproj
@@ -0,0 +1,29 @@
+
+
+
+ net7.0
+
+
+
+
+ all
+ runtime; build; native; contentfiles; analyzers; buildtransitive
+
+
+
+
+
+ runtime; build; native; contentfiles; analyzers; buildtransitive
+ all
+
+
+ runtime; build; native; contentfiles; analyzers; buildtransitive
+ all
+
+
+
+
+
+
+
+
diff --git a/tests/NetEvolve.Http.Correlation.Functions.Tests.Unit/UnitTest1.cs b/tests/NetEvolve.Http.Correlation.Functions.Tests.Unit/UnitTest1.cs
new file mode 100644
index 0000000..f6fdb55
--- /dev/null
+++ b/tests/NetEvolve.Http.Correlation.Functions.Tests.Unit/UnitTest1.cs
@@ -0,0 +1,11 @@
+namespace NetEvolve.Http.Correlation.Functions.Tests.Unit;
+
+using Xunit;
+
+public class UnitTest1
+{
+ [Fact]
+ public void Test1()
+ {
+ }
+}
diff --git a/tests/NetEvolve.Http.Correlation.HttpClient.Tests.Unit/UnitTest1.cs b/tests/NetEvolve.Http.Correlation.HttpClient.Tests.Unit/UnitTest1.cs
index c3033ca..24ea9c1 100644
--- a/tests/NetEvolve.Http.Correlation.HttpClient.Tests.Unit/UnitTest1.cs
+++ b/tests/NetEvolve.Http.Correlation.HttpClient.Tests.Unit/UnitTest1.cs
@@ -1,5 +1,7 @@
namespace NetEvolve.Http.Correlation.HttpClient.Tests.Unit;
+using Xunit;
+
public class UnitTest1
{
[Fact]
diff --git a/tests/NetEvolve.Http.Correlation.HttpClient.Tests.Unit/Usings.cs b/tests/NetEvolve.Http.Correlation.HttpClient.Tests.Unit/Usings.cs
deleted file mode 100644
index 9df1d42..0000000
--- a/tests/NetEvolve.Http.Correlation.HttpClient.Tests.Unit/Usings.cs
+++ /dev/null
@@ -1 +0,0 @@
-global using Xunit;
diff --git a/tests/NetEvolve.Http.Correlation.TestGenerator.Tests.Unit/UnitTest1.cs b/tests/NetEvolve.Http.Correlation.TestGenerator.Tests.Unit/UnitTest1.cs
index b4b7f80..d3f9b3a 100644
--- a/tests/NetEvolve.Http.Correlation.TestGenerator.Tests.Unit/UnitTest1.cs
+++ b/tests/NetEvolve.Http.Correlation.TestGenerator.Tests.Unit/UnitTest1.cs
@@ -1,5 +1,7 @@
namespace NetEvolve.Http.Correlation.TestGenerator.Tests.Unit;
+using Xunit;
+
public class UnitTest1
{
[Fact]
diff --git a/tests/NetEvolve.Http.Correlation.TestGenerator.Tests.Unit/Usings.cs b/tests/NetEvolve.Http.Correlation.TestGenerator.Tests.Unit/Usings.cs
deleted file mode 100644
index 9df1d42..0000000
--- a/tests/NetEvolve.Http.Correlation.TestGenerator.Tests.Unit/Usings.cs
+++ /dev/null
@@ -1 +0,0 @@
-global using Xunit;