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

Improve DefaultHttpXxx default paths #814

Closed
wants to merge 1 commit into from
Closed
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
84 changes: 58 additions & 26 deletions samples/SampleApp/PooledHttpContext.cs
Original file line number Diff line number Diff line change
@@ -1,54 +1,86 @@
// 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.Collections.Generic;
using System.Security.Claims;
using System.Threading;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Http.Authentication;
using Microsoft.AspNetCore.Http.Features;
using Microsoft.AspNetCore.Http.Internal;

namespace SampleApp
{
public class PooledHttpContext : DefaultHttpContext
public sealed class PooledHttpContext : HttpContext
{
DefaultHttpRequest _pooledHttpRequest;
DefaultHttpResponse _pooledHttpResponse;
private readonly DefaultHttpContext _context;

public PooledHttpContext(IFeatureCollection featureCollection) :
base(featureCollection)
public PooledHttpContext(IFeatureCollection featureCollection)
{
_context = new DefaultHttpContext(featureCollection);
}

protected override HttpRequest InitializeHttpRequest()
public void Initialize(IFeatureCollection featureCollection)
{
if (_pooledHttpRequest != null)
{
_pooledHttpRequest.Initialize(this);
return _pooledHttpRequest;
}
_context.Initialize(featureCollection);
}

return new DefaultHttpRequest(this);
public void Uninitialize()
{
_context.Uninitialize();
}

protected override void UninitializeHttpRequest(HttpRequest instance)
public override IFeatureCollection Features => _context.Features;

public override HttpRequest Request => _context.Request;

public override HttpResponse Response => _context.Response;

public override ConnectionInfo Connection => _context.Connection;

public override WebSocketManager WebSockets => _context.WebSockets;

public override AuthenticationManager Authentication => _context.Authentication;

public override ClaimsPrincipal User
{
_pooledHttpRequest = instance as DefaultHttpRequest;
_pooledHttpRequest?.Uninitialize();
get => _context.User;
set => _context.User = value;
}

protected override HttpResponse InitializeHttpResponse()
public override IDictionary<object, object> Items
{
if (_pooledHttpResponse != null)
{
_pooledHttpResponse.Initialize(this);
return _pooledHttpResponse;
}
get => _context.Items;
set => _context.Items = value;
}

return new DefaultHttpResponse(this);
public override IServiceProvider RequestServices
{
get => _context.RequestServices;
set => _context.RequestServices = value;
}

public override CancellationToken RequestAborted
{
get => _context.RequestAborted;
set => _context.RequestAborted = value;
}

public override string TraceIdentifier
{
get => _context.TraceIdentifier;
set => _context.TraceIdentifier = value;
}

public override ISession Session
{
get => _context.Session;
set => _context.Session = value;
}

protected override void UninitializeHttpResponse(HttpResponse instance)
public override void Abort()
{
_pooledHttpResponse = instance as DefaultHttpResponse;
_pooledHttpResponse?.Uninitialize();
_context.Abort();
}
}
}
1 change: 0 additions & 1 deletion samples/SampleApp/PooledHttpContextFactory.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@

using System;
using System.Collections.Generic;
using System.Text;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Http.Features;
using Microsoft.Extensions.ObjectPool;
Expand Down
7 changes: 7 additions & 0 deletions src/Microsoft.AspNetCore.Http.Features/FeatureReferences.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,13 @@ public FeatureReferences(IFeatureCollection collection)
Revision = collection.Revision;
}

public FeatureReferences(IFeatureCollection collection, int featuresVersion)
{
Collection = collection;
Cache = default(TCache);
Revision = featuresVersion;
}

public IFeatureCollection Collection { get; private set; }
public int Revision { get; private set; }

Expand Down
86 changes: 34 additions & 52 deletions src/Microsoft.AspNetCore.Http/DefaultHttpContext.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

using System;
using System.Collections.Generic;
using System.Runtime.CompilerServices;
using System.Security.Claims;
using System.Threading;
using Microsoft.AspNetCore.Http.Authentication;
Expand All @@ -13,7 +14,7 @@

namespace Microsoft.AspNetCore.Http
{
public class DefaultHttpContext : HttpContext
public sealed class DefaultHttpContext : HttpContext
{
// Lambdas hoisted to static readonly fields to improve inlining https://github.com/dotnet/roslyn/issues/13624
private readonly static Func<IFeatureCollection, IItemsFeature> _newItemsFeature = f => new ItemsFeature();
Expand All @@ -26,8 +27,8 @@ public class DefaultHttpContext : HttpContext

private FeatureReferences<FeatureInterfaces> _features;

private HttpRequest _request;
private HttpResponse _response;
private DefaultHttpRequest _request;
private DefaultHttpResponse _response;
private AuthenticationManager _authenticationManager;
private ConnectionInfo _connection;
private WebSocketManager _websockets;
Expand All @@ -41,44 +42,22 @@ public DefaultHttpContext()

public DefaultHttpContext(IFeatureCollection features)
{
Initialize(features);
}
var featuresVersion = features.Revision;

public virtual void Initialize(IFeatureCollection features)
{
_features = new FeatureReferences<FeatureInterfaces>(features);
_request = InitializeHttpRequest();
_response = InitializeHttpResponse();
// Speculatively populate always used features for current version
_features = new FeatureReferences<FeatureInterfaces>(features, featuresVersion);
_request = new DefaultHttpRequest(this, featuresVersion);
_response = new DefaultHttpResponse(this, featuresVersion);
}

public virtual void Uninitialize()
public void Initialize(IFeatureCollection features)
{
_features = default(FeatureReferences<FeatureInterfaces>);
if (_request != null)
{
UninitializeHttpRequest(_request);
_request = null;
}
if (_response != null)
{
UninitializeHttpResponse(_response);
_response = null;
}
if (_authenticationManager != null)
{
UninitializeAuthenticationManager(_authenticationManager);
_authenticationManager = null;
}
if (_connection != null)
{
UninitializeConnectionInfo(_connection);
_connection = null;
}
if (_websockets != null)
{
UninitializeWebSocketManager(_websockets);
_websockets = null;
}
var featuresVersion = features.Revision;

// Speculatively populate always used features for current version
_features = new FeatureReferences<FeatureInterfaces>(features, featuresVersion);
_request.Initialize(features, featuresVersion);
_response.Initialize(features, featuresVersion);
}

private IItemsFeature ItemsFeature =>
Expand Down Expand Up @@ -109,11 +88,11 @@ public virtual void Uninitialize()

public override HttpResponse Response => _response;

public override ConnectionInfo Connection => _connection ?? (_connection = InitializeConnectionInfo());
public override ConnectionInfo Connection => _connection ?? InitializeConnectionInfo();

public override AuthenticationManager Authentication => _authenticationManager ?? (_authenticationManager = InitializeAuthenticationManager());
public override AuthenticationManager Authentication => _authenticationManager ?? InitializeAuthenticationManager();

public override WebSocketManager WebSockets => _websockets ?? (_websockets = InitializeWebSocketManager());
public override WebSocketManager WebSockets => _websockets ?? InitializeWebSocketManager();


public override ClaimsPrincipal User
Expand Down Expand Up @@ -180,21 +159,24 @@ public override void Abort()
LifetimeFeature.Abort();
}

[MethodImpl(MethodImplOptions.NoInlining)]
private ConnectionInfo InitializeConnectionInfo() => (_connection = new DefaultConnectionInfo(Features));

protected virtual HttpRequest InitializeHttpRequest() => new DefaultHttpRequest(this);
protected virtual void UninitializeHttpRequest(HttpRequest instance) { }

protected virtual HttpResponse InitializeHttpResponse() => new DefaultHttpResponse(this);
protected virtual void UninitializeHttpResponse(HttpResponse instance) { }
[MethodImpl(MethodImplOptions.NoInlining)]
private AuthenticationManager InitializeAuthenticationManager() => (_authenticationManager = new DefaultAuthenticationManager(this));

protected virtual ConnectionInfo InitializeConnectionInfo() => new DefaultConnectionInfo(Features);
protected virtual void UninitializeConnectionInfo(ConnectionInfo instance) { }
[MethodImpl(MethodImplOptions.NoInlining)]
private WebSocketManager InitializeWebSocketManager() => (_websockets = new DefaultWebSocketManager(Features));

protected virtual AuthenticationManager InitializeAuthenticationManager() => new DefaultAuthenticationManager(this);
protected virtual void UninitializeAuthenticationManager(AuthenticationManager instance) { }

protected virtual WebSocketManager InitializeWebSocketManager() => new DefaultWebSocketManager(Features);
protected virtual void UninitializeWebSocketManager(WebSocketManager instance) { }
public void Uninitialize()
{
_features = default(FeatureReferences<FeatureInterfaces>);
_request.Uninitialize();
_response.Uninitialize();
_authenticationManager = null;
_connection = null;
_websockets = null;
}

struct FeatureInterfaces
{
Expand Down
12 changes: 1 addition & 11 deletions src/Microsoft.AspNetCore.Http/Internal/DefaultConnectionInfo.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@

namespace Microsoft.AspNetCore.Http.Internal
{
public class DefaultConnectionInfo : ConnectionInfo
public sealed class DefaultConnectionInfo : ConnectionInfo
{
// Lambdas hoisted to static readonly fields to improve inlining https://github.com/dotnet/roslyn/issues/13624
private readonly static Func<IFeatureCollection, IHttpConnectionFeature> _newHttpConnectionFeature = f => new HttpConnectionFeature();
Expand All @@ -19,20 +19,10 @@ public class DefaultConnectionInfo : ConnectionInfo
private FeatureReferences<FeatureInterfaces> _features;

public DefaultConnectionInfo(IFeatureCollection features)
{
Initialize(features);
}

public virtual void Initialize( IFeatureCollection features)
{
_features = new FeatureReferences<FeatureInterfaces>(features);
}

public virtual void Uninitialize()
{
_features = default(FeatureReferences<FeatureInterfaces>);
}

private IHttpConnectionFeature HttpConnectionFeature =>
_features.Fetch(ref _features.Cache.Connection, _newHttpConnectionFeature);

Expand Down
25 changes: 13 additions & 12 deletions src/Microsoft.AspNetCore.Http/Internal/DefaultHttpRequest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,32 +10,28 @@

namespace Microsoft.AspNetCore.Http.Internal
{
public class DefaultHttpRequest : HttpRequest
public sealed class DefaultHttpRequest : HttpRequest
{
// Lambdas hoisted to static readonly fields to improve inlining https://github.com/dotnet/roslyn/issues/13624
private readonly static Func<IFeatureCollection, IHttpRequestFeature> _nullRequestFeature = f => null;
private readonly static Func<IFeatureCollection, IQueryFeature> _newQueryFeature = f => new QueryFeature(f);
private readonly static Func<HttpRequest, IFormFeature> _newFormFeature = r => new FormFeature(r);
private readonly static Func<IFeatureCollection, IRequestCookiesFeature> _newRequestCookiesFeature = f => new RequestCookiesFeature(f);

private HttpContext _context;
private readonly DefaultHttpContext _context;
private FeatureReferences<FeatureInterfaces> _features;

public DefaultHttpRequest(HttpContext context)
{
Initialize(context);
}

public virtual void Initialize(HttpContext context)
public DefaultHttpRequest(DefaultHttpContext context, int featuresVersion)
{
_context = context;
_features = new FeatureReferences<FeatureInterfaces>(context.Features);
Initialize(context.Features, featuresVersion);
}

public virtual void Uninitialize()
public void Initialize(IFeatureCollection features, int featuresVersion)
{
_context = null;
_features = default(FeatureReferences<FeatureInterfaces>);
// Speculatively populate always used features for current version
_features = new FeatureReferences<FeatureInterfaces>(features, featuresVersion);
_features.Cache.Request = (IHttpRequestFeature)features[typeof(IHttpRequestFeature)];
}

public override HttpContext HttpContext => _context;
Expand Down Expand Up @@ -151,6 +147,11 @@ public override Task<IFormCollection> ReadFormAsync(CancellationToken cancellati
return FormFeature.ReadFormAsync(cancellationToken);
}

public void Uninitialize()
{
_features = default(FeatureReferences<FeatureInterfaces>);
}

struct FeatureInterfaces
{
public IHttpRequestFeature Request;
Expand Down
Loading