Skip to content

Commit

Permalink
Merge branch 'dev'
Browse files Browse the repository at this point in the history
  • Loading branch information
stevejgordon committed Apr 8, 2018
2 parents 71517f3 + 459144d commit 9d1d04e
Show file tree
Hide file tree
Showing 11 changed files with 246 additions and 35 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,8 @@ public IEnumerable<string> Get()
$"DirectAccessor={correlation}",
$"Transient={_transient.GetCorrelationFromScoped}",
$"Scoped={_scoped.GetCorrelationFromScoped}",
$"Singleton={_singleton.GetCorrelationFromScoped}"
$"Singleton={_singleton.GetCorrelationFromScoped}",
$"TraceIdentifier={HttpContext.TraceIdentifier}"
};
}
}
Expand Down
26 changes: 13 additions & 13 deletions samples/MvcCorrelationIdSample/Properties/launchSettings.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,21 +9,21 @@
},
"profiles": {
"IIS Express": {
"commandName": "IISExpress",
"launchBrowser": true,
"launchUrl": "api/values",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
"commandName": "IISExpress",
"launchBrowser": true,
"launchUrl": "http://localhost:59922/api/values",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
},
"MvcCorrelationIdSample": {
"commandName": "Project",
"launchBrowser": true,
"launchUrl": "api/values",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
},
"applicationUrl": "http://localhost:59923/"
"commandName": "Project",
"launchBrowser": true,
"launchUrl": "http://localhost:59923/api/values",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
},
"applicationUrl": "http://localhost:59923/"
}
}
}
11 changes: 10 additions & 1 deletion src/CorrelationId/CorrelationContext.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,17 +7,26 @@ namespace CorrelationId
/// </summary>
public class CorrelationContext
{
internal CorrelationContext(string correlationId)
internal CorrelationContext(string correlationId, string header)
{
if (string.IsNullOrEmpty(correlationId))
throw new ArgumentNullException(nameof(correlationId));

if (string.IsNullOrEmpty(header))
throw new ArgumentNullException(nameof(header));

CorrelationId = correlationId;
Header = header;
}

/// <summary>
/// The Correlation ID which is applicable to the current request.
/// </summary>
public string CorrelationId { get; }

/// <summary>
/// The name of the header from which the Correlation ID is read/written.
/// </summary>
public string Header { get; }
}
}
1 change: 1 addition & 0 deletions src/CorrelationId/CorrelationContextAccessor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ public class CorrelationContextAccessor : ICorrelationContextAccessor
{
private static AsyncLocal<CorrelationContext> _correlationContext = new AsyncLocal<CorrelationContext>();

/// <inheritdoc />
public CorrelationContext CorrelationContext
{
get => _correlationContext.Value;
Expand Down
17 changes: 14 additions & 3 deletions src/CorrelationId/CorrelationContextFactory.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,27 @@
public class CorrelationContextFactory : ICorrelationContextFactory
{
private readonly ICorrelationContextAccessor _correlationContextAccessor;


/// <summary>
/// Initializes a new instance of the <see cref="T:CorrelationId.CorrelationContextFactory" /> class.
/// </summary>
public CorrelationContextFactory()
: this(null)
{ }

/// <summary>
/// Initializes a new instance of the <see cref="CorrelationContextFactory"/> class.
/// </summary>
/// <param name="correlationContextAccessor">The <see cref="ICorrelationContextAccessor"/> through which the <see cref="CorrelationContext"/> will be set.</param>
public CorrelationContextFactory(ICorrelationContextAccessor correlationContextAccessor)
{
_correlationContextAccessor = correlationContextAccessor;
}

/// <inheritdoc />
public CorrelationContext Create(string correlationId)
public CorrelationContext Create(string correlationId, string header)
{
var correlationContext = new CorrelationContext(correlationId);
var correlationContext = new CorrelationContext(correlationId, header);

if (_correlationContextAccessor != null)
{
Expand Down
10 changes: 9 additions & 1 deletion src/CorrelationId/CorrelationId.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,20 @@
<RepositoryType>git</RepositoryType>
<PackageTags>aspnetcore;correlationid</PackageTags>
<NeutralLanguage>en</NeutralLanguage>
<Version>2.0.1</Version>
<Version>2.1.0</Version>
<DocumentationFile>bin\Release\netstandard1.4\CorrelationId.xml</DocumentationFile>
<PackageProjectUrl>https://github.com/stevejgordon/CorrelationId</PackageProjectUrl>
<RepositoryUrl>https://github.com/stevejgordon/CorrelationId</RepositoryUrl>
</PropertyGroup>

<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'">
<LangVersion>latest</LangVersion>
</PropertyGroup>

<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
<LangVersion>latest</LangVersion>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.Http.Abstractions" Version="1.0.0" />
<PackageReference Include="Microsoft.Extensions.Options" Version="1.0.0" />
Expand Down
42 changes: 31 additions & 11 deletions src/CorrelationId/CorrelationIdMiddleware.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,18 @@
using Microsoft.Extensions.Options;
using System;
using System.Threading.Tasks;
using Microsoft.Extensions.Primitives;

namespace CorrelationId
{
/// <summary>
/// Middleware which attempts to reads / creates a Correlation ID that can then be used in logs and
/// passed to upstream requests.
/// </summary>
public class CorrelationIdMiddleware
{
private readonly RequestDelegate _next;
private readonly IOptions<CorrelationIdOptions> _options;
private readonly CorrelationIdOptions _options;

/// <summary>
/// Creates a new instance of the CorrelationIdMiddleware.
Expand All @@ -18,7 +23,7 @@ public class CorrelationIdMiddleware
public CorrelationIdMiddleware(RequestDelegate next, IOptions<CorrelationIdOptions> options)
{
_next = next ?? throw new ArgumentNullException(nameof(next));
_options = options ?? throw new ArgumentNullException(nameof(options));
_options = options.Value ?? throw new ArgumentNullException(nameof(options));
}

/// <summary>
Expand All @@ -27,26 +32,25 @@ public CorrelationIdMiddleware(RequestDelegate next, IOptions<CorrelationIdOptio
/// </summary>
/// <param name="context">The <see cref="HttpContext"/> for the current request.</param>
/// <param name="correlationContextFactory">The <see cref="ICorrelationContextFactory"/> which can create a <see cref="CorrelationContext"/>.</param>
/// <returns></returns>
public async Task Invoke(HttpContext context, ICorrelationContextFactory correlationContextFactory)
{
if (context.Request.Headers.TryGetValue(_options.Value.Header, out var correlationId))
{
var correlationId = SetCorrelationId(context);

if (_options.UpdateTraceIdentifier)
context.TraceIdentifier = correlationId;
}

correlationContextFactory.Create(context.TraceIdentifier);
correlationContextFactory.Create(correlationId, _options.Header);

if (_options.Value.IncludeInResponse)
if (_options.IncludeInResponse)
{
// apply the correlation ID to the response header for client side tracking
context.Response.OnStarting(() =>
{
if (!context.Response.Headers.ContainsKey(_options.Value.Header))
if (!context.Response.Headers.ContainsKey(_options.Header))
{
context.Response.Headers.Add(_options.Value.Header, context.TraceIdentifier);
context.Response.Headers.Add(_options.Header, correlationId);
}

return Task.CompletedTask;
});
}
Expand All @@ -55,5 +59,21 @@ public async Task Invoke(HttpContext context, ICorrelationContextFactory correla

correlationContextFactory.Dispose();
}

private StringValues SetCorrelationId(HttpContext context)
{
var correlationIdFoundInRequestHeader = context.Request.Headers.TryGetValue(_options.Header, out var correlationId);

if (RequiresGenerationOfCorrelationId(correlationIdFoundInRequestHeader, correlationId))
correlationId = GenerateCorrelationId(context.TraceIdentifier);

return correlationId;
}

private static bool RequiresGenerationOfCorrelationId(bool idInHeader, StringValues idFromHeader) =>
!idInHeader || StringValues.IsNullOrEmpty(idFromHeader);

private StringValues GenerateCorrelationId(string traceIdentifier) =>
_options.UseGuidForCorrelationId || string.IsNullOrEmpty(traceIdentifier) ? Guid.NewGuid().ToString() : traceIdentifier;
}
}
22 changes: 21 additions & 1 deletion src/CorrelationId/CorrelationIdOptions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,33 @@ public class CorrelationIdOptions
private const string DefaultHeader = "X-Correlation-ID";

/// <summary>
/// The header field name where the correlation ID will be stored.
/// The name of the header from which the Correlation ID is read/written.
/// </summary>
public string Header { get; set; } = DefaultHeader;

/// <summary>
/// <para>
/// Controls whether the correlation ID is returned in the response headers.
/// </para>
/// <para>Default: true</para>
/// </summary>
public bool IncludeInResponse { get; set; } = true;

/// <summary>
/// <para>
/// Controls whether the ASP.NET Core TraceIdentifier will be set to match the CorrelationId.
/// </para>
/// <para>Default: true</para>
/// </summary>
public bool UpdateTraceIdentifier { get; set; } = true;

/// <summary>
/// <para>
/// Controls whether a GUID will be used in cases where no correlation ID is retrieved from the request header.
/// When false the TraceIdentifier for the current request will be used.
/// </para>
/// <para> Default: false.</para>
/// </summary>
public bool UseGuidForCorrelationId { get; set; } = false;
}
}
3 changes: 3 additions & 0 deletions src/CorrelationId/CorrelationIdServiceExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@

namespace CorrelationId
{
/// <summary>
/// Extensions on the <see cref="IServiceCollection"/>.
/// </summary>
public static class CorrelationIdServiceExtensions
{
/// <summary>
Expand Down
3 changes: 2 additions & 1 deletion src/CorrelationId/ICorrelationContextFactory.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,9 @@ public interface ICorrelationContextFactory
/// Creates a new <see cref="CorrelationContext"/> with the correlation ID set for the current request.
/// </summary>
/// <param name="correlationId">The correlation ID to set on the context.</param>
/// /// <param name="header">The header used to hold the correlation ID.</param>
/// <returns>A new instance of a <see cref="CorrelationContext"/>.</returns>
CorrelationContext Create(string correlationId);
CorrelationContext Create(string correlationId, string header);

/// <summary>
/// Disposes of the <see cref="CorrelationContext"/> for the current request.
Expand Down
Loading

0 comments on commit 9d1d04e

Please sign in to comment.