Skip to content
This repository was archived by the owner on Nov 20, 2018. It is now read-only.

Move RequestIdentifierFeature to HttpContext #440

Merged
merged 1 commit into from
Oct 15, 2015
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions src/Microsoft.AspNet.Http.Abstractions/HttpContext.cs
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@ public abstract class HttpContext

public abstract CancellationToken RequestAborted { get; set; }

public abstract string TraceIdentifier { get; set; }

public abstract ISession Session { get; set; }

public abstract void Abort();
Expand Down
15 changes: 15 additions & 0 deletions src/Microsoft.AspNet.Http/DefaultHttpContext.cs
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,15 @@ private ISessionFeature SessionFeature
}
}

private IHttpRequestIdentifierFeature RequestIdentifierFeature
{
get {
return FeatureHelpers.GetOrCreate<IHttpRequestIdentifierFeature>(
_features,
() => new HttpRequestIdentifierFeature());
}
}

public override IFeatureCollection Features { get { return _features; } }

public override HttpRequest Request { get { return _request; } }
Expand Down Expand Up @@ -167,6 +176,12 @@ public override CancellationToken RequestAborted
set { LifetimeFeature.RequestAborted = value; }
}

public override string TraceIdentifier
{
get { return RequestIdentifierFeature.TraceIdentifier; }
set { RequestIdentifierFeature.TraceIdentifier = value; }
}

public override ISession Session
{
get
Expand Down
15 changes: 15 additions & 0 deletions src/Microsoft.AspNet.Http/Features/FeatureHelpers.cs
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,21 @@ public static T GetAndCache<T>(
return obj;
}

public static T GetOrCreate<T>(
IFeatureCollection features,
Func<T> factory)
{
T obj = features.Get<T>();
if (obj == null)
{
obj = factory();
features.Set(obj);
}

return obj;
}


public static T GetOrCreateAndCache<T>(
IFeatureCache cache,
IFeatureCollection features,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,64 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.

using System;
using System.Threading;

namespace Microsoft.AspNet.Http.Features.Internal
{
public class HttpRequestIdentifierFeature : IHttpRequestIdentifierFeature
{
public string TraceIdentifier { get; set; }
// Base64 encoding - but in ascii sort order for easy text based sorting
private static readonly string _encode32Chars = "0123456789ABCDEFGHIJKLMNOPQRSTUV";
// Seed the _requestId for this application instance with
// the number of 100-nanosecond intervals that have elapsed since 12:00:00 midnight, January 1, 0001
// for a roughly increasing _requestId over restarts
private static long _requestId = DateTime.UtcNow.Ticks;

private string _id = null;

public string TraceIdentifier
{
get
{
// Don't incur the cost of generating the request ID until it's asked for
if (_id == null)
{
_id = GenerateRequestId(Interlocked.Increment(ref _requestId));
}
return _id;
}
set
{
_id = value;
}
}

private static unsafe string GenerateRequestId(long id)
{
// The following routine is ~310% faster than calling long.ToString() on x64
// and ~600% faster than calling long.ToString() on x86 in tight loops of 1 million+ iterations
// See: https://github.com/aspnet/Hosting/pull/385

// stackalloc to allocate array on stack rather than heap
char* charBuffer = stackalloc char[13];

charBuffer[0] = _encode32Chars[(int)(id >> 60) & 31];
charBuffer[1] = _encode32Chars[(int)(id >> 55) & 31];
charBuffer[2] = _encode32Chars[(int)(id >> 50) & 31];
charBuffer[3] = _encode32Chars[(int)(id >> 45) & 31];
charBuffer[4] = _encode32Chars[(int)(id >> 40) & 31];
charBuffer[5] = _encode32Chars[(int)(id >> 35) & 31];
charBuffer[6] = _encode32Chars[(int)(id >> 30) & 31];
charBuffer[7] = _encode32Chars[(int)(id >> 25) & 31];
charBuffer[8] = _encode32Chars[(int)(id >> 20) & 31];
charBuffer[9] = _encode32Chars[(int)(id >> 15) & 31];
charBuffer[10] = _encode32Chars[(int)(id >> 10) & 31];
charBuffer[11] = _encode32Chars[(int)(id >> 5) & 31];
charBuffer[12] = _encode32Chars[(int)id & 31];

// string ctor overload that takes char*
return new string(charBuffer, 0, 13);
}
}
}
3 changes: 2 additions & 1 deletion src/Microsoft.AspNet.Http/project.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@
"url": "git://github.com/aspnet/httpabstractions"
},
"compilationOptions": {
"warningsAsErrors": true
"warningsAsErrors": true,
"allowUnsafe": true
},
"dependencies": {
"Microsoft.AspNet.Http.Abstractions": "1.0.0-*",
Expand Down
14 changes: 14 additions & 0 deletions test/Microsoft.AspNet.Http.Tests/DefaultHttpContextTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,20 @@ public void GetItems_DefaultCollectionProvided()
Assert.Same(item, context.Items["foo"]);
}

[Fact]
public void GetItems_DefaultRequestIdentifierAvailable()
{
var context = new DefaultHttpContext(new FeatureCollection());
Assert.Null(context.Features.Get<IHttpRequestIdentifierFeature>());
var traceIdentifier = context.TraceIdentifier;
Assert.NotNull(context.Features.Get<IHttpRequestIdentifierFeature>());
Assert.NotNull(traceIdentifier);
Assert.Same(traceIdentifier, context.TraceIdentifier);

context.TraceIdentifier = "Hello";
Assert.Same("Hello", context.TraceIdentifier);
}

[Fact]
public void SetItems_NewCollectionUsed()
{
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.

using Microsoft.AspNet.Http.Features.Internal;
using Xunit;

namespace Microsoft.AspNet.Http.Tests
{
public class HttpRequestIdentifierFeatureTests
{
[Fact]
public void TraceIdentifier_ReturnsId()
{
var feature = new HttpRequestIdentifierFeature();

var id = feature.TraceIdentifier;

Assert.NotNull(id);
}

[Fact]
public void TraceIdentifier_ReturnsStableId()
{
var feature = new HttpRequestIdentifierFeature();

var id1 = feature.TraceIdentifier;
var id2 = feature.TraceIdentifier;

Assert.Equal(id1, id2);
}

[Fact]
public void TraceIdentifier_ReturnsUniqueIdForDifferentInstances()
{
var feature1 = new HttpRequestIdentifierFeature();
var feature2 = new HttpRequestIdentifierFeature();

var id1 = feature1.TraceIdentifier;
var id2 = feature2.TraceIdentifier;

Assert.NotEqual(id1, id2);
}
}
}