Merge branch 'lodejard/featurereferences' into dev
This commit is contained in:
commit
364a712cb3
|
|
@ -0,0 +1,54 @@
|
|||
// 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;
|
||||
using Microsoft.AspNet.Http.Features;
|
||||
using Microsoft.AspNet.Http.Internal;
|
||||
|
||||
namespace SampleApp
|
||||
{
|
||||
public class PooledHttpContext : DefaultHttpContext
|
||||
{
|
||||
DefaultHttpRequest _pooledHttpRequest;
|
||||
DefaultHttpResponse _pooledHttpResponse;
|
||||
|
||||
public PooledHttpContext(IFeatureCollection featureCollection) :
|
||||
base(featureCollection)
|
||||
{
|
||||
}
|
||||
|
||||
protected override HttpRequest InitializeHttpRequest()
|
||||
{
|
||||
if (_pooledHttpRequest != null)
|
||||
{
|
||||
_pooledHttpRequest.Initialize(this, Features);
|
||||
return _pooledHttpRequest;
|
||||
}
|
||||
|
||||
return new DefaultHttpRequest(this, Features);
|
||||
}
|
||||
|
||||
protected override void UninitializeHttpRequest(HttpRequest instance)
|
||||
{
|
||||
_pooledHttpRequest = instance as DefaultHttpRequest;
|
||||
_pooledHttpRequest?.Uninitialize();
|
||||
}
|
||||
|
||||
protected override HttpResponse InitializeHttpResponse()
|
||||
{
|
||||
if (_pooledHttpResponse != null)
|
||||
{
|
||||
_pooledHttpResponse.Initialize(this, Features);
|
||||
return _pooledHttpResponse;
|
||||
}
|
||||
|
||||
return new DefaultHttpResponse(this, Features);
|
||||
}
|
||||
|
||||
protected override void UninitializeHttpResponse(HttpResponse instance)
|
||||
{
|
||||
_pooledHttpResponse = instance as DefaultHttpResponse;
|
||||
_pooledHttpResponse?.Uninitialize();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,65 @@
|
|||
// 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.Collections.Generic;
|
||||
using Microsoft.AspNet.Http;
|
||||
using Microsoft.AspNet.Http.Features;
|
||||
|
||||
namespace SampleApp
|
||||
{
|
||||
public class PooledHttpContextFactory : IHttpContextFactory
|
||||
{
|
||||
private readonly IHttpContextAccessor _httpContextAccessor;
|
||||
private readonly Stack<PooledHttpContext> _pool = new Stack<PooledHttpContext>();
|
||||
|
||||
public PooledHttpContextFactory(IHttpContextAccessor httpContextAccessor)
|
||||
{
|
||||
_httpContextAccessor = httpContextAccessor;
|
||||
}
|
||||
|
||||
public HttpContext Create(IFeatureCollection featureCollection)
|
||||
{
|
||||
PooledHttpContext httpContext = null;
|
||||
lock (_pool)
|
||||
{
|
||||
if (_pool.Count != 0)
|
||||
{
|
||||
httpContext = _pool.Pop();
|
||||
}
|
||||
}
|
||||
|
||||
if (httpContext == null)
|
||||
{
|
||||
httpContext = new PooledHttpContext(featureCollection);
|
||||
}
|
||||
else
|
||||
{
|
||||
httpContext.Initialize(featureCollection);
|
||||
}
|
||||
|
||||
if (_httpContextAccessor != null)
|
||||
{
|
||||
_httpContextAccessor.HttpContext = httpContext;
|
||||
}
|
||||
return httpContext;
|
||||
}
|
||||
|
||||
public void Dispose(HttpContext httpContext)
|
||||
{
|
||||
if (_httpContextAccessor != null)
|
||||
{
|
||||
_httpContextAccessor.HttpContext = null;
|
||||
}
|
||||
|
||||
var pooled = httpContext as PooledHttpContext;
|
||||
if (pooled != null)
|
||||
{
|
||||
pooled.Uninitialize();
|
||||
lock (_pool)
|
||||
{
|
||||
_pool.Push(pooled);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,62 @@
|
|||
// 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;
|
||||
|
||||
namespace Microsoft.AspNet.Http.Features
|
||||
{
|
||||
public struct FeatureReferences<TCache>
|
||||
{
|
||||
public FeatureReferences(IFeatureCollection collection)
|
||||
{
|
||||
Collection = collection;
|
||||
Cache = default(TCache);
|
||||
Revision = collection.Revision;
|
||||
}
|
||||
|
||||
public IFeatureCollection Collection { get; private set; }
|
||||
public int Revision { get; private set; }
|
||||
|
||||
// cache is a public field because the code calling Fetch must
|
||||
// be able to pass ref values that "dot through" the TCache struct memory,
|
||||
// if it was a Property then that getter would return a copy of the memory
|
||||
// preventing the use of "ref"
|
||||
public TCache Cache;
|
||||
|
||||
public TFeature Fetch<TFeature, TState>(
|
||||
ref TFeature cached,
|
||||
TState state,
|
||||
Func<TState, TFeature> factory)
|
||||
{
|
||||
var cleared = false;
|
||||
if (Revision != Collection.Revision)
|
||||
{
|
||||
cleared = true;
|
||||
Cache = default(TCache);
|
||||
Revision = Collection.Revision;
|
||||
}
|
||||
|
||||
var feature = cached;
|
||||
if (feature == null)
|
||||
{
|
||||
feature = Collection.Get<TFeature>();
|
||||
if (feature == null)
|
||||
{
|
||||
feature = factory(state);
|
||||
|
||||
Collection.Set(feature);
|
||||
if (!cleared)
|
||||
{
|
||||
Cache = default(TCache);
|
||||
}
|
||||
Revision = Collection.Revision;
|
||||
}
|
||||
cached = feature;
|
||||
}
|
||||
return feature;
|
||||
}
|
||||
|
||||
public TFeature Fetch<TFeature>(ref TFeature cached, Func<IFeatureCollection, TFeature> factory) =>
|
||||
Fetch(ref cached, Collection, factory);
|
||||
}
|
||||
}
|
||||
|
|
@ -12,56 +12,27 @@ using Microsoft.AspNet.Http.Features.Authentication.Internal;
|
|||
|
||||
namespace Microsoft.AspNet.Http.Authentication.Internal
|
||||
{
|
||||
public class DefaultAuthenticationManager : AuthenticationManager, IFeatureCache
|
||||
public class DefaultAuthenticationManager : AuthenticationManager
|
||||
{
|
||||
private IFeatureCollection _features;
|
||||
private int _cachedFeaturesRevision = -1;
|
||||
|
||||
private IHttpAuthenticationFeature _authentication;
|
||||
private FeatureReferences<IHttpAuthenticationFeature> _features;
|
||||
|
||||
public DefaultAuthenticationManager(IFeatureCollection features)
|
||||
{
|
||||
_features = features;
|
||||
((IFeatureCache)this).SetFeaturesRevision();
|
||||
Initialize(features);
|
||||
}
|
||||
|
||||
void IFeatureCache.CheckFeaturesRevision()
|
||||
public virtual void Initialize(IFeatureCollection features)
|
||||
{
|
||||
if (_cachedFeaturesRevision != _features.Revision)
|
||||
{
|
||||
ResetFeatures();
|
||||
}
|
||||
_features = new FeatureReferences<IHttpAuthenticationFeature>(features);
|
||||
}
|
||||
|
||||
void IFeatureCache.SetFeaturesRevision()
|
||||
public virtual void Uninitialize()
|
||||
{
|
||||
_cachedFeaturesRevision = _features.Revision;
|
||||
_features = default(FeatureReferences<IHttpAuthenticationFeature>);
|
||||
}
|
||||
|
||||
public void UpdateFeatures(IFeatureCollection features)
|
||||
{
|
||||
_features = features;
|
||||
ResetFeatures();
|
||||
}
|
||||
|
||||
private void ResetFeatures()
|
||||
{
|
||||
_authentication = null;
|
||||
|
||||
((IFeatureCache)this).SetFeaturesRevision();
|
||||
}
|
||||
|
||||
private IHttpAuthenticationFeature HttpAuthenticationFeature
|
||||
{
|
||||
get
|
||||
{
|
||||
return FeatureHelpers.GetOrCreateAndCache(
|
||||
this,
|
||||
_features,
|
||||
() => new HttpAuthenticationFeature(),
|
||||
ref _authentication);
|
||||
}
|
||||
}
|
||||
private IHttpAuthenticationFeature HttpAuthenticationFeature =>
|
||||
_features.Fetch(ref _features.Cache, f => new HttpAuthenticationFeature());
|
||||
|
||||
public override IEnumerable<AuthenticationDescription> GetAuthenticationSchemes()
|
||||
{
|
||||
|
|
|
|||
|
|
@ -10,70 +10,30 @@ using Microsoft.AspNet.Http.Features.Internal;
|
|||
|
||||
namespace Microsoft.AspNet.Http.Internal
|
||||
{
|
||||
public class DefaultConnectionInfo : ConnectionInfo, IFeatureCache
|
||||
public class DefaultConnectionInfo : ConnectionInfo
|
||||
{
|
||||
private IFeatureCollection _features;
|
||||
private int _cachedFeaturesRevision = -1;
|
||||
|
||||
private IHttpConnectionFeature _connection;
|
||||
private ITlsConnectionFeature _tlsConnection;
|
||||
private FeatureReferences<FeatureInterfaces> _features;
|
||||
|
||||
public DefaultConnectionInfo(IFeatureCollection features)
|
||||
{
|
||||
_features = features;
|
||||
((IFeatureCache)this).SetFeaturesRevision();
|
||||
Initialize(features);
|
||||
}
|
||||
|
||||
void IFeatureCache.CheckFeaturesRevision()
|
||||
public virtual void Initialize( IFeatureCollection features)
|
||||
{
|
||||
if (_cachedFeaturesRevision != _features.Revision)
|
||||
{
|
||||
ResetFeatures();
|
||||
}
|
||||
_features = new FeatureReferences<FeatureInterfaces>(features);
|
||||
}
|
||||
|
||||
void IFeatureCache.SetFeaturesRevision()
|
||||
public virtual void Uninitialize()
|
||||
{
|
||||
_cachedFeaturesRevision = _features.Revision;
|
||||
_features = default(FeatureReferences<FeatureInterfaces>);
|
||||
}
|
||||
|
||||
public void UpdateFeatures(IFeatureCollection features)
|
||||
{
|
||||
_features = features;
|
||||
ResetFeatures();
|
||||
}
|
||||
private IHttpConnectionFeature HttpConnectionFeature =>
|
||||
_features.Fetch(ref _features.Cache.Connection, f => new HttpConnectionFeature());
|
||||
|
||||
private void ResetFeatures()
|
||||
{
|
||||
_connection = null;
|
||||
_tlsConnection = null;
|
||||
|
||||
((IFeatureCache)this).SetFeaturesRevision();
|
||||
}
|
||||
|
||||
private IHttpConnectionFeature HttpConnectionFeature
|
||||
{
|
||||
get
|
||||
{
|
||||
return FeatureHelpers.GetOrCreateAndCache(
|
||||
this,
|
||||
_features,
|
||||
() => new HttpConnectionFeature(),
|
||||
ref _connection);
|
||||
}
|
||||
}
|
||||
|
||||
private ITlsConnectionFeature TlsConnectionFeature
|
||||
{
|
||||
get
|
||||
{
|
||||
return FeatureHelpers.GetOrCreateAndCache(
|
||||
this,
|
||||
_features,
|
||||
() => new TlsConnectionFeature(),
|
||||
ref _tlsConnection);
|
||||
}
|
||||
}
|
||||
private ITlsConnectionFeature TlsConnectionFeature=>
|
||||
_features.Fetch(ref _features.Cache.TlsConnection, f => new TlsConnectionFeature());
|
||||
|
||||
public override IPAddress RemoteIpAddress
|
||||
{
|
||||
|
|
@ -115,5 +75,11 @@ namespace Microsoft.AspNet.Http.Internal
|
|||
{
|
||||
return TlsConnectionFeature.GetClientCertificateAsync(cancellationToken);
|
||||
}
|
||||
|
||||
struct FeatureInterfaces
|
||||
{
|
||||
public IHttpConnectionFeature Connection;
|
||||
public ITlsConnectionFeature TlsConnection;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -14,173 +14,99 @@ using Microsoft.AspNet.Http.Features.Internal;
|
|||
|
||||
namespace Microsoft.AspNet.Http.Internal
|
||||
{
|
||||
public class DefaultHttpContext : HttpContext, IFeatureCache
|
||||
public class DefaultHttpContext : HttpContext
|
||||
{
|
||||
private readonly DefaultHttpRequest _request;
|
||||
private readonly DefaultHttpResponse _response;
|
||||
private FeatureReferences<FeatureInterfaces> _features;
|
||||
|
||||
private DefaultAuthenticationManager _authenticationManager;
|
||||
private DefaultConnectionInfo _connection;
|
||||
private DefaultWebSocketManager _websockets;
|
||||
|
||||
private IItemsFeature _items;
|
||||
private IServiceProvidersFeature _serviceProviders;
|
||||
private IHttpAuthenticationFeature _authentication;
|
||||
private IHttpRequestLifetimeFeature _lifetime;
|
||||
private ISessionFeature _session;
|
||||
|
||||
private IFeatureCollection _features;
|
||||
private int _cachedFeaturesRevision = -1;
|
||||
private HttpRequest _request;
|
||||
private HttpResponse _response;
|
||||
private AuthenticationManager _authenticationManager;
|
||||
private ConnectionInfo _connection;
|
||||
private WebSocketManager _websockets;
|
||||
|
||||
public DefaultHttpContext()
|
||||
: this(new FeatureCollection())
|
||||
{
|
||||
_features.Set<IHttpRequestFeature>(new HttpRequestFeature());
|
||||
_features.Set<IHttpResponseFeature>(new HttpResponseFeature());
|
||||
((IFeatureCache)this).SetFeaturesRevision();
|
||||
Features.Set<IHttpRequestFeature>(new HttpRequestFeature());
|
||||
Features.Set<IHttpResponseFeature>(new HttpResponseFeature());
|
||||
}
|
||||
|
||||
public DefaultHttpContext(IFeatureCollection features)
|
||||
{
|
||||
_features = features;
|
||||
_request = new DefaultHttpRequest(this, features);
|
||||
_response = new DefaultHttpResponse(this, features);
|
||||
((IFeatureCache)this).SetFeaturesRevision();
|
||||
Initialize(features);
|
||||
}
|
||||
|
||||
void IFeatureCache.CheckFeaturesRevision()
|
||||
public virtual void Initialize(IFeatureCollection features)
|
||||
{
|
||||
if (_cachedFeaturesRevision !=_features.Revision)
|
||||
_features = new FeatureReferences<FeatureInterfaces>(features);
|
||||
_request = InitializeHttpRequest();
|
||||
_response = InitializeHttpResponse();
|
||||
}
|
||||
|
||||
public virtual void Uninitialize()
|
||||
{
|
||||
_features = default(FeatureReferences<FeatureInterfaces>);
|
||||
if (_request != null)
|
||||
{
|
||||
ResetFeatures();
|
||||
UninitializeHttpRequest(_request);
|
||||
_request = null;
|
||||
}
|
||||
}
|
||||
|
||||
void IFeatureCache.SetFeaturesRevision()
|
||||
{
|
||||
_cachedFeaturesRevision = _features.Revision;
|
||||
}
|
||||
|
||||
public void UpdateFeatures(IFeatureCollection features)
|
||||
{
|
||||
_features = features;
|
||||
ResetFeatures();
|
||||
|
||||
_request.UpdateFeatures(features);
|
||||
_response.UpdateFeatures(features);
|
||||
|
||||
_authenticationManager?.UpdateFeatures(features);
|
||||
_connection?.UpdateFeatures(features);
|
||||
_websockets?.UpdateFeatures(features);
|
||||
}
|
||||
|
||||
private void ResetFeatures()
|
||||
{
|
||||
_items = null;
|
||||
_serviceProviders = null;
|
||||
_authentication = null;
|
||||
_lifetime = null;
|
||||
_session = null;
|
||||
|
||||
((IFeatureCache)this).SetFeaturesRevision();
|
||||
}
|
||||
|
||||
IItemsFeature ItemsFeature
|
||||
{
|
||||
get
|
||||
if (_response != null)
|
||||
{
|
||||
return FeatureHelpers.GetOrCreateAndCache(
|
||||
this,
|
||||
_features,
|
||||
() => new ItemsFeature(),
|
||||
ref _items);
|
||||
UninitializeHttpResponse(_response);
|
||||
_response = null;
|
||||
}
|
||||
}
|
||||
|
||||
IServiceProvidersFeature ServiceProvidersFeature
|
||||
{
|
||||
get
|
||||
if (_authenticationManager != null)
|
||||
{
|
||||
return FeatureHelpers.GetOrCreateAndCache(
|
||||
this,
|
||||
_features,
|
||||
() => new ServiceProvidersFeature(),
|
||||
ref _serviceProviders);
|
||||
UninitializeAuthenticationManager(_authenticationManager);
|
||||
_authenticationManager = null;
|
||||
}
|
||||
}
|
||||
|
||||
private IHttpAuthenticationFeature HttpAuthenticationFeature
|
||||
{
|
||||
get
|
||||
if (_connection != null)
|
||||
{
|
||||
return FeatureHelpers.GetOrCreateAndCache(
|
||||
this,
|
||||
_features,
|
||||
() => new HttpAuthenticationFeature(),
|
||||
ref _authentication);
|
||||
UninitializeConnectionInfo(_connection);
|
||||
_connection = null;
|
||||
}
|
||||
}
|
||||
|
||||
private IHttpRequestLifetimeFeature LifetimeFeature
|
||||
{
|
||||
get
|
||||
if (_websockets != null)
|
||||
{
|
||||
return FeatureHelpers.GetOrCreateAndCache(
|
||||
this,
|
||||
_features,
|
||||
() => new HttpRequestLifetimeFeature(),
|
||||
ref _lifetime);
|
||||
UninitializeWebSocketManager(_websockets);
|
||||
_websockets = null;
|
||||
}
|
||||
}
|
||||
|
||||
private IItemsFeature ItemsFeature =>
|
||||
_features.Fetch(ref _features.Cache.Items, f => new ItemsFeature());
|
||||
|
||||
private ISessionFeature SessionFeature
|
||||
{
|
||||
get { return FeatureHelpers.GetAndCache(this, _features, ref _session); }
|
||||
set
|
||||
{
|
||||
_features.Set(value);
|
||||
_session = value;
|
||||
}
|
||||
}
|
||||
private IServiceProvidersFeature ServiceProvidersFeature =>
|
||||
_features.Fetch(ref _features.Cache.ServiceProviders, f => new ServiceProvidersFeature());
|
||||
|
||||
private IHttpRequestIdentifierFeature RequestIdentifierFeature
|
||||
{
|
||||
get {
|
||||
return FeatureHelpers.GetOrCreate<IHttpRequestIdentifierFeature>(
|
||||
_features,
|
||||
() => new HttpRequestIdentifierFeature());
|
||||
}
|
||||
}
|
||||
private IHttpAuthenticationFeature HttpAuthenticationFeature =>
|
||||
_features.Fetch(ref _features.Cache.Authentication, f => new HttpAuthenticationFeature());
|
||||
|
||||
public override IFeatureCollection Features { get { return _features; } }
|
||||
private IHttpRequestLifetimeFeature LifetimeFeature =>
|
||||
_features.Fetch(ref _features.Cache.Lifetime, f => new HttpRequestLifetimeFeature());
|
||||
|
||||
public override HttpRequest Request { get { return _request; } }
|
||||
private ISessionFeature SessionFeature =>
|
||||
_features.Fetch(ref _features.Cache.Session, f => new DefaultSessionFeature());
|
||||
|
||||
public override HttpResponse Response { get { return _response; } }
|
||||
private ISessionFeature SessionFeatureOrNull =>
|
||||
_features.Fetch(ref _features.Cache.Session, f => null);
|
||||
|
||||
public override ConnectionInfo Connection
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_connection == null)
|
||||
{
|
||||
_connection = new DefaultConnectionInfo(_features);
|
||||
}
|
||||
return _connection;
|
||||
}
|
||||
}
|
||||
|
||||
public override AuthenticationManager Authentication
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_authenticationManager == null)
|
||||
{
|
||||
_authenticationManager = new DefaultAuthenticationManager(_features);
|
||||
}
|
||||
return _authenticationManager;
|
||||
}
|
||||
}
|
||||
private IHttpRequestIdentifierFeature RequestIdentifierFeature =>
|
||||
_features.Fetch(ref _features.Cache.RequestIdentifier, f => new HttpRequestIdentifierFeature());
|
||||
|
||||
public override IFeatureCollection Features => _features.Collection;
|
||||
|
||||
public override HttpRequest Request => _request;
|
||||
|
||||
public override HttpResponse Response => _response;
|
||||
|
||||
public override ConnectionInfo Connection => _connection ?? (_connection = InitializeConnectionInfo());
|
||||
|
||||
public override AuthenticationManager Authentication => _authenticationManager ?? (_authenticationManager = InitializeAuthenticationManager());
|
||||
|
||||
public override WebSocketManager WebSockets => _websockets ?? (_websockets = InitializeWebSocketManager());
|
||||
|
||||
|
||||
public override ClaimsPrincipal User
|
||||
{
|
||||
|
|
@ -225,7 +151,7 @@ namespace Microsoft.AspNet.Http.Internal
|
|||
{
|
||||
get
|
||||
{
|
||||
var feature = SessionFeature;
|
||||
var feature = SessionFeatureOrNull;
|
||||
if (feature == null)
|
||||
{
|
||||
throw new InvalidOperationException("Session has not been configured for this application " +
|
||||
|
|
@ -235,31 +161,41 @@ namespace Microsoft.AspNet.Http.Internal
|
|||
}
|
||||
set
|
||||
{
|
||||
var feature = SessionFeature;
|
||||
if (feature == null)
|
||||
{
|
||||
feature = new DefaultSessionFeature();
|
||||
SessionFeature = feature;
|
||||
}
|
||||
feature.Session = value;
|
||||
SessionFeature.Session = value;
|
||||
}
|
||||
}
|
||||
|
||||
public override WebSocketManager WebSockets
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_websockets == null)
|
||||
{
|
||||
_websockets = new DefaultWebSocketManager(_features);
|
||||
}
|
||||
return _websockets;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public override void Abort()
|
||||
{
|
||||
LifetimeFeature.Abort();
|
||||
}
|
||||
|
||||
|
||||
protected virtual HttpRequest InitializeHttpRequest() => new DefaultHttpRequest(this, Features);
|
||||
protected virtual void UninitializeHttpRequest(HttpRequest instance) { }
|
||||
|
||||
protected virtual HttpResponse InitializeHttpResponse() => new DefaultHttpResponse(this, Features);
|
||||
protected virtual void UninitializeHttpResponse(HttpResponse instance) { }
|
||||
|
||||
protected virtual ConnectionInfo InitializeConnectionInfo() => new DefaultConnectionInfo(Features);
|
||||
protected virtual void UninitializeConnectionInfo(ConnectionInfo instance) { }
|
||||
|
||||
protected virtual AuthenticationManager InitializeAuthenticationManager() => new DefaultAuthenticationManager(Features);
|
||||
protected virtual void UninitializeAuthenticationManager(AuthenticationManager instance) { }
|
||||
|
||||
protected virtual WebSocketManager InitializeWebSocketManager() => new DefaultWebSocketManager(Features);
|
||||
protected virtual void UninitializeWebSocketManager(WebSocketManager instance) { }
|
||||
|
||||
struct FeatureInterfaces
|
||||
{
|
||||
public IItemsFeature Items;
|
||||
public IServiceProvidersFeature ServiceProviders;
|
||||
public IHttpAuthenticationFeature Authentication;
|
||||
public IHttpRequestLifetimeFeature Lifetime;
|
||||
public ISessionFeature Session;
|
||||
public IHttpRequestIdentifierFeature RequestIdentifier;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,96 +11,41 @@ using Microsoft.Net.Http.Headers;
|
|||
|
||||
namespace Microsoft.AspNet.Http.Internal
|
||||
{
|
||||
public class DefaultHttpRequest : HttpRequest, IFeatureCache
|
||||
public class DefaultHttpRequest : HttpRequest
|
||||
{
|
||||
private readonly DefaultHttpContext _context;
|
||||
private IFeatureCollection _features;
|
||||
private int _cachedFeaturesRevision = -1;
|
||||
private HttpContext _context;
|
||||
private FeatureReferences<FeatureInterfaces> _features;
|
||||
|
||||
private IHttpRequestFeature _request;
|
||||
private IQueryFeature _query;
|
||||
private IFormFeature _form;
|
||||
private IRequestCookiesFeature _cookies;
|
||||
public DefaultHttpRequest(HttpContext context, IFeatureCollection features)
|
||||
{
|
||||
Initialize(context, features);
|
||||
}
|
||||
|
||||
public DefaultHttpRequest(DefaultHttpContext context, IFeatureCollection features)
|
||||
public virtual void Initialize(HttpContext context, IFeatureCollection features)
|
||||
{
|
||||
_context = context;
|
||||
_features = features;
|
||||
((IFeatureCache)this).SetFeaturesRevision();
|
||||
_features = new FeatureReferences<FeatureInterfaces>(features);
|
||||
}
|
||||
|
||||
void IFeatureCache.CheckFeaturesRevision()
|
||||
public virtual void Uninitialize()
|
||||
{
|
||||
if (_cachedFeaturesRevision != _features.Revision)
|
||||
{
|
||||
ResetFeatures();
|
||||
}
|
||||
_context = null;
|
||||
_features = default(FeatureReferences<FeatureInterfaces>);
|
||||
}
|
||||
|
||||
void IFeatureCache.SetFeaturesRevision()
|
||||
{
|
||||
_cachedFeaturesRevision = _features.Revision;
|
||||
}
|
||||
public override HttpContext HttpContext => _context;
|
||||
|
||||
public void UpdateFeatures(IFeatureCollection features)
|
||||
{
|
||||
_features = features;
|
||||
ResetFeatures();
|
||||
}
|
||||
private IHttpRequestFeature HttpRequestFeature =>
|
||||
_features.Fetch(ref _features.Cache.Request, f => null);
|
||||
|
||||
private void ResetFeatures()
|
||||
{
|
||||
_request = null;
|
||||
_query = null;
|
||||
_form = null;
|
||||
_cookies = null;
|
||||
private IQueryFeature QueryFeature =>
|
||||
_features.Fetch(ref _features.Cache.Query, f => new QueryFeature(f));
|
||||
|
||||
((IFeatureCache)this).SetFeaturesRevision();
|
||||
}
|
||||
private IFormFeature FormFeature =>
|
||||
_features.Fetch(ref _features.Cache.Form, this, f => new FormFeature(f));
|
||||
|
||||
private IHttpRequestFeature HttpRequestFeature
|
||||
{
|
||||
get { return FeatureHelpers.GetAndCache(this, _features, ref _request); }
|
||||
}
|
||||
|
||||
private IQueryFeature QueryFeature
|
||||
{
|
||||
get
|
||||
{
|
||||
return FeatureHelpers.GetOrCreateAndCache(
|
||||
this,
|
||||
_features,
|
||||
(f) => new QueryFeature(f),
|
||||
ref _query);
|
||||
}
|
||||
}
|
||||
|
||||
private IFormFeature FormFeature
|
||||
{
|
||||
get
|
||||
{
|
||||
return FeatureHelpers.GetOrCreateAndCache(
|
||||
this,
|
||||
_features,
|
||||
this,
|
||||
(r) => new FormFeature(r),
|
||||
ref _form);
|
||||
}
|
||||
}
|
||||
|
||||
private IRequestCookiesFeature RequestCookiesFeature
|
||||
{
|
||||
get
|
||||
{
|
||||
return FeatureHelpers.GetOrCreateAndCache(
|
||||
this,
|
||||
_features,
|
||||
(f) => new RequestCookiesFeature(f),
|
||||
ref _cookies);
|
||||
}
|
||||
}
|
||||
|
||||
public override HttpContext HttpContext { get { return _context; } }
|
||||
private IRequestCookiesFeature RequestCookiesFeature =>
|
||||
_features.Fetch(ref _features.Cache.Cookies, f => new RequestCookiesFeature(f));
|
||||
|
||||
public override PathString PathBase
|
||||
{
|
||||
|
|
@ -206,5 +151,13 @@ namespace Microsoft.AspNet.Http.Internal
|
|||
{
|
||||
return FormFeature.ReadFormAsync(cancellationToken);
|
||||
}
|
||||
|
||||
struct FeatureInterfaces
|
||||
{
|
||||
public IHttpRequestFeature Request;
|
||||
public IQueryFeature Query;
|
||||
public IFormFeature Form;
|
||||
public IRequestCookiesFeature Cookies;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -10,65 +10,34 @@ using Microsoft.Net.Http.Headers;
|
|||
|
||||
namespace Microsoft.AspNet.Http.Internal
|
||||
{
|
||||
public class DefaultHttpResponse : HttpResponse, IFeatureCache
|
||||
public class DefaultHttpResponse : HttpResponse
|
||||
{
|
||||
private readonly DefaultHttpContext _context;
|
||||
private IFeatureCollection _features;
|
||||
private int _cachedFeaturesRevision = -1;
|
||||
private HttpContext _context;
|
||||
private FeatureReferences<FeatureInterfaces> _features;
|
||||
|
||||
private IHttpResponseFeature _response;
|
||||
private IResponseCookiesFeature _cookies;
|
||||
public DefaultHttpResponse(HttpContext context, IFeatureCollection features)
|
||||
{
|
||||
Initialize(context, features);
|
||||
}
|
||||
|
||||
public DefaultHttpResponse(DefaultHttpContext context, IFeatureCollection features)
|
||||
public virtual void Initialize(HttpContext context, IFeatureCollection features)
|
||||
{
|
||||
_context = context;
|
||||
_features = features;
|
||||
((IFeatureCache)this).SetFeaturesRevision();
|
||||
_features = new FeatureReferences<FeatureInterfaces>(features);
|
||||
}
|
||||
|
||||
void IFeatureCache.CheckFeaturesRevision()
|
||||
public virtual void Uninitialize()
|
||||
{
|
||||
if (_cachedFeaturesRevision != _features.Revision)
|
||||
{
|
||||
ResetFeatures();
|
||||
}
|
||||
_context = null;
|
||||
_features = default(FeatureReferences<FeatureInterfaces>);
|
||||
}
|
||||
|
||||
void IFeatureCache.SetFeaturesRevision()
|
||||
{
|
||||
_cachedFeaturesRevision = _features.Revision;
|
||||
}
|
||||
private IHttpResponseFeature HttpResponseFeature =>
|
||||
_features.Fetch(ref _features.Cache.Response, f => null);
|
||||
|
||||
public void UpdateFeatures(IFeatureCollection features)
|
||||
{
|
||||
_features = features;
|
||||
ResetFeatures();
|
||||
}
|
||||
|
||||
private void ResetFeatures()
|
||||
{
|
||||
_response = null;
|
||||
_cookies = null;
|
||||
|
||||
((IFeatureCache)this).SetFeaturesRevision();
|
||||
}
|
||||
|
||||
private IHttpResponseFeature HttpResponseFeature
|
||||
{
|
||||
get { return FeatureHelpers.GetAndCache(this, _features, ref _response); }
|
||||
}
|
||||
|
||||
private IResponseCookiesFeature ResponseCookiesFeature
|
||||
{
|
||||
get
|
||||
{
|
||||
return FeatureHelpers.GetOrCreateAndCache(
|
||||
this,
|
||||
_features,
|
||||
(f) => new ResponseCookiesFeature(f),
|
||||
ref _cookies);
|
||||
}
|
||||
}
|
||||
private IResponseCookiesFeature ResponseCookiesFeature =>
|
||||
_features.Fetch(ref _features.Cache.Cookies, f => new ResponseCookiesFeature(f));
|
||||
|
||||
|
||||
public override HttpContext HttpContext { get { return _context; } }
|
||||
|
||||
|
|
@ -163,5 +132,11 @@ namespace Microsoft.AspNet.Http.Internal
|
|||
|
||||
Headers[HeaderNames.Location] = location;
|
||||
}
|
||||
|
||||
struct FeatureInterfaces
|
||||
{
|
||||
public IHttpResponseFeature Response;
|
||||
public IResponseCookiesFeature Cookies;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -10,56 +10,30 @@ using Microsoft.Net.Http.Headers;
|
|||
|
||||
namespace Microsoft.AspNet.Http.Internal
|
||||
{
|
||||
public class DefaultWebSocketManager : WebSocketManager, IFeatureCache
|
||||
public class DefaultWebSocketManager : WebSocketManager
|
||||
{
|
||||
private IFeatureCollection _features;
|
||||
private int _cachedFeaturesRevision = -1;
|
||||
|
||||
private IHttpRequestFeature _request;
|
||||
private IHttpWebSocketFeature _webSockets;
|
||||
private FeatureReferences<FeatureInterfaces> _features;
|
||||
|
||||
public DefaultWebSocketManager(IFeatureCollection features)
|
||||
{
|
||||
_features = features;
|
||||
((IFeatureCache)this).SetFeaturesRevision();
|
||||
Initialize(features);
|
||||
}
|
||||
|
||||
void IFeatureCache.CheckFeaturesRevision()
|
||||
public virtual void Initialize(IFeatureCollection features)
|
||||
{
|
||||
if (_cachedFeaturesRevision != _features.Revision)
|
||||
{
|
||||
ResetFeatures();
|
||||
}
|
||||
_features = new FeatureReferences<FeatureInterfaces>(features);
|
||||
}
|
||||
|
||||
void IFeatureCache.SetFeaturesRevision()
|
||||
public virtual void Uninitialize()
|
||||
{
|
||||
_cachedFeaturesRevision = _features.Revision;
|
||||
_features = default(FeatureReferences<FeatureInterfaces>);
|
||||
}
|
||||
|
||||
public void UpdateFeatures(IFeatureCollection features)
|
||||
{
|
||||
_features = features;
|
||||
ResetFeatures();
|
||||
}
|
||||
private IHttpRequestFeature HttpRequestFeature =>
|
||||
_features.Fetch(ref _features.Cache.Request, f => null);
|
||||
|
||||
private void ResetFeatures()
|
||||
{
|
||||
_request = null;
|
||||
_webSockets = null;
|
||||
|
||||
((IFeatureCache)this).SetFeaturesRevision();
|
||||
}
|
||||
|
||||
private IHttpRequestFeature HttpRequestFeature
|
||||
{
|
||||
get { return FeatureHelpers.GetAndCache(this, _features, ref _request); }
|
||||
}
|
||||
|
||||
private IHttpWebSocketFeature WebSocketFeature
|
||||
{
|
||||
get { return FeatureHelpers.GetAndCache(this, _features, ref _webSockets); }
|
||||
}
|
||||
private IHttpWebSocketFeature WebSocketFeature =>
|
||||
_features.Fetch(ref _features.Cache.WebSockets, f => null);
|
||||
|
||||
public override bool IsWebSocketRequest
|
||||
{
|
||||
|
|
@ -85,5 +59,11 @@ namespace Microsoft.AspNet.Http.Internal
|
|||
}
|
||||
return WebSocketFeature.AcceptAsync(new WebSocketAcceptContext() { SubProtocol = subProtocol });
|
||||
}
|
||||
|
||||
struct FeatureInterfaces
|
||||
{
|
||||
public IHttpRequestFeature Request;
|
||||
public IHttpWebSocketFeature WebSockets;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,116 +0,0 @@
|
|||
// 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;
|
||||
|
||||
namespace Microsoft.AspNet.Http.Features
|
||||
{
|
||||
internal static class FeatureHelpers
|
||||
{
|
||||
public static T GetAndCache<T>(
|
||||
IFeatureCache cache,
|
||||
IFeatureCollection features,
|
||||
ref T cachedObject)
|
||||
where T : class
|
||||
{
|
||||
cache.CheckFeaturesRevision();
|
||||
|
||||
T obj = cachedObject;
|
||||
if (obj == null)
|
||||
{
|
||||
obj = features.Get<T>();
|
||||
cachedObject = obj;
|
||||
}
|
||||
return obj;
|
||||
}
|
||||
|
||||
public static T GetOrCreate<T>(
|
||||
IFeatureCollection features,
|
||||
Func<T> factory)
|
||||
where T : class
|
||||
{
|
||||
T obj = features.Get<T>();
|
||||
if (obj == null)
|
||||
{
|
||||
obj = factory();
|
||||
features.Set(obj);
|
||||
}
|
||||
|
||||
return obj;
|
||||
}
|
||||
|
||||
|
||||
public static T GetOrCreateAndCache<T>(
|
||||
IFeatureCache cache,
|
||||
IFeatureCollection features,
|
||||
Func<T> factory,
|
||||
ref T cachedObject)
|
||||
where T : class
|
||||
{
|
||||
cache.CheckFeaturesRevision();
|
||||
|
||||
T obj = cachedObject;
|
||||
if (obj == null)
|
||||
{
|
||||
obj = features.Get<T>();
|
||||
if (obj == null)
|
||||
{
|
||||
obj = factory();
|
||||
}
|
||||
cachedObject = obj;
|
||||
features.Set(obj);
|
||||
cache.SetFeaturesRevision();
|
||||
}
|
||||
return obj;
|
||||
}
|
||||
|
||||
public static T GetOrCreateAndCache<T>(
|
||||
IFeatureCache cache,
|
||||
IFeatureCollection features,
|
||||
Func<IFeatureCollection, T> factory,
|
||||
ref T cachedObject)
|
||||
where T : class
|
||||
{
|
||||
cache.CheckFeaturesRevision();
|
||||
|
||||
T obj = cachedObject;
|
||||
if (obj == null)
|
||||
{
|
||||
obj = features.Get<T>();
|
||||
if (obj == null)
|
||||
{
|
||||
obj = factory(features);
|
||||
}
|
||||
cachedObject = obj;
|
||||
features.Set(obj);
|
||||
cache.SetFeaturesRevision();
|
||||
}
|
||||
return obj;
|
||||
}
|
||||
|
||||
public static T GetOrCreateAndCache<T>(
|
||||
IFeatureCache cache,
|
||||
IFeatureCollection features,
|
||||
HttpRequest request,
|
||||
Func<HttpRequest, T> factory,
|
||||
ref T cachedObject)
|
||||
where T : class
|
||||
{
|
||||
cache.CheckFeaturesRevision();
|
||||
|
||||
T obj = cachedObject;
|
||||
if (obj == null)
|
||||
{
|
||||
obj = features.Get<T>();
|
||||
if (obj == null)
|
||||
{
|
||||
obj = factory(request);
|
||||
}
|
||||
cachedObject = obj;
|
||||
features.Set(obj);
|
||||
cache.SetFeaturesRevision();
|
||||
}
|
||||
return obj;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,11 +0,0 @@
|
|||
// 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.
|
||||
|
||||
namespace Microsoft.AspNet.Http.Features
|
||||
{
|
||||
internal interface IFeatureCache
|
||||
{
|
||||
void CheckFeaturesRevision();
|
||||
void SetFeaturesRevision();
|
||||
}
|
||||
}
|
||||
|
|
@ -7,12 +7,9 @@ using Microsoft.AspNet.WebUtilities;
|
|||
|
||||
namespace Microsoft.AspNet.Http.Features.Internal
|
||||
{
|
||||
public class QueryFeature : IQueryFeature, IFeatureCache
|
||||
public class QueryFeature : IQueryFeature
|
||||
{
|
||||
private readonly IFeatureCollection _features;
|
||||
private int _cachedFeaturesRevision = -1;
|
||||
|
||||
private IHttpRequestFeature _request;
|
||||
private FeatureReferences<IHttpRequestFeature> _features;
|
||||
|
||||
private string _original;
|
||||
private IQueryCollection _parsedValues;
|
||||
|
|
@ -34,34 +31,17 @@ namespace Microsoft.AspNet.Http.Features.Internal
|
|||
throw new ArgumentNullException(nameof(features));
|
||||
}
|
||||
|
||||
_features = features;
|
||||
((IFeatureCache)this).SetFeaturesRevision();
|
||||
_features = new FeatureReferences<IHttpRequestFeature>(features);
|
||||
}
|
||||
|
||||
void IFeatureCache.CheckFeaturesRevision()
|
||||
{
|
||||
if (_cachedFeaturesRevision != _features.Revision)
|
||||
{
|
||||
_request = null;
|
||||
((IFeatureCache)this).SetFeaturesRevision();
|
||||
}
|
||||
}
|
||||
|
||||
void IFeatureCache.SetFeaturesRevision()
|
||||
{
|
||||
_cachedFeaturesRevision = _features.Revision;
|
||||
}
|
||||
|
||||
private IHttpRequestFeature HttpRequestFeature
|
||||
{
|
||||
get { return FeatureHelpers.GetAndCache(this, _features, ref _request); }
|
||||
}
|
||||
private IHttpRequestFeature HttpRequestFeature =>
|
||||
_features.Fetch(ref _features.Cache, f => null);
|
||||
|
||||
public IQueryCollection Query
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_features == null)
|
||||
if (_features.Collection == null)
|
||||
{
|
||||
if (_parsedValues == null)
|
||||
{
|
||||
|
|
@ -91,7 +71,7 @@ namespace Microsoft.AspNet.Http.Features.Internal
|
|||
set
|
||||
{
|
||||
_parsedValues = value;
|
||||
if (_features != null)
|
||||
if (_features.Collection != null)
|
||||
{
|
||||
if (value == null)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -9,13 +9,9 @@ using Microsoft.Net.Http.Headers;
|
|||
|
||||
namespace Microsoft.AspNet.Http.Features.Internal
|
||||
{
|
||||
public class RequestCookiesFeature : IRequestCookiesFeature, IFeatureCache
|
||||
public class RequestCookiesFeature : IRequestCookiesFeature
|
||||
{
|
||||
private readonly IFeatureCollection _features;
|
||||
private int _cachedFeaturesRevision = -1;
|
||||
|
||||
private IHttpRequestFeature _request;
|
||||
|
||||
private FeatureReferences<IHttpRequestFeature> _features;
|
||||
private StringValues _original;
|
||||
private IRequestCookieCollection _parsedValues;
|
||||
|
||||
|
|
@ -36,34 +32,17 @@ namespace Microsoft.AspNet.Http.Features.Internal
|
|||
throw new ArgumentNullException(nameof(features));
|
||||
}
|
||||
|
||||
_features = features;
|
||||
((IFeatureCache)this).SetFeaturesRevision();
|
||||
_features = new FeatureReferences<IHttpRequestFeature>(features);
|
||||
}
|
||||
|
||||
void IFeatureCache.CheckFeaturesRevision()
|
||||
{
|
||||
if (_cachedFeaturesRevision != _features.Revision)
|
||||
{
|
||||
_request = null;
|
||||
((IFeatureCache)this).SetFeaturesRevision();
|
||||
}
|
||||
}
|
||||
|
||||
void IFeatureCache.SetFeaturesRevision()
|
||||
{
|
||||
_cachedFeaturesRevision = _features.Revision;
|
||||
}
|
||||
|
||||
private IHttpRequestFeature HttpRequestFeature
|
||||
{
|
||||
get { return FeatureHelpers.GetAndCache(this, _features, ref _request); }
|
||||
}
|
||||
private IHttpRequestFeature HttpRequestFeature =>
|
||||
_features.Fetch(ref _features.Cache, f => null);
|
||||
|
||||
public IRequestCookieCollection Cookies
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_features == null)
|
||||
if (_features.Collection == null)
|
||||
{
|
||||
if (_parsedValues == null)
|
||||
{
|
||||
|
|
@ -91,7 +70,7 @@ namespace Microsoft.AspNet.Http.Features.Internal
|
|||
{
|
||||
_parsedValues = value;
|
||||
_original = StringValues.Empty;
|
||||
if (_features != null)
|
||||
if (_features.Collection != null)
|
||||
{
|
||||
if (_parsedValues == null || _parsedValues.Count == 0)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -5,38 +5,18 @@ using Microsoft.AspNet.Http.Internal;
|
|||
|
||||
namespace Microsoft.AspNet.Http.Features.Internal
|
||||
{
|
||||
public class ResponseCookiesFeature : IResponseCookiesFeature, IFeatureCache
|
||||
public class ResponseCookiesFeature : IResponseCookiesFeature
|
||||
{
|
||||
private readonly IFeatureCollection _features;
|
||||
private int _cachedFeaturesRevision = -1;
|
||||
|
||||
private IHttpResponseFeature _response;
|
||||
private FeatureReferences<IHttpResponseFeature> _features;
|
||||
private IResponseCookies _cookiesCollection;
|
||||
|
||||
public ResponseCookiesFeature(IFeatureCollection features)
|
||||
{
|
||||
_features = features;
|
||||
((IFeatureCache)this).SetFeaturesRevision();
|
||||
_features = new FeatureReferences<IHttpResponseFeature>(features);
|
||||
}
|
||||
|
||||
void IFeatureCache.CheckFeaturesRevision()
|
||||
{
|
||||
if (_cachedFeaturesRevision != _features.Revision)
|
||||
{
|
||||
_response = null;
|
||||
((IFeatureCache)this).SetFeaturesRevision();
|
||||
}
|
||||
}
|
||||
|
||||
void IFeatureCache.SetFeaturesRevision()
|
||||
{
|
||||
_cachedFeaturesRevision = _features.Revision;
|
||||
}
|
||||
|
||||
private IHttpResponseFeature HttpResponseFeature
|
||||
{
|
||||
get { return FeatureHelpers.GetAndCache(this, _features, ref _response); }
|
||||
}
|
||||
private IHttpResponseFeature HttpResponseFeature =>
|
||||
_features.Fetch(ref _features.Cache, f => null);
|
||||
|
||||
public IResponseCookies Cookies
|
||||
{
|
||||
|
|
|
|||
|
|
@ -149,93 +149,88 @@ namespace Microsoft.AspNet.Http.Internal
|
|||
items["foo"] = item;
|
||||
Assert.Same(item, context.Items["foo"]);
|
||||
}
|
||||
|
||||
|
||||
[Fact]
|
||||
public void UpdateFeatures_ClearsCachedFeatures()
|
||||
{
|
||||
var features = new FeatureCollection();
|
||||
|
||||
var context = new DefaultHttpContext(features);
|
||||
|
||||
var request = (DefaultHttpRequest)context.Request;
|
||||
var response = (DefaultHttpResponse)context.Response;
|
||||
|
||||
var authentication = (DefaultAuthenticationManager)context.Authentication;
|
||||
var connection = (DefaultConnectionInfo)context.Connection;
|
||||
var websockets = (DefaultWebSocketManager)context.WebSockets;
|
||||
|
||||
Assert.Equal(0, features.Count());
|
||||
|
||||
TestCachedFeaturesAreNull(context.GetType(), context, features);
|
||||
TestCachedFeaturesAreNull(request.GetType(), request, features);
|
||||
TestCachedFeaturesAreNull(response.GetType(), response, features);
|
||||
TestCachedFeaturesAreNull(authentication.GetType(), authentication, features);
|
||||
TestCachedFeaturesAreNull(connection.GetType(), connection, features);
|
||||
TestCachedFeaturesAreNull(websockets.GetType(), websockets, features);
|
||||
|
||||
context.Session = new TestSession();
|
||||
features.Set<IHttpRequestFeature>(new HttpRequestFeature());
|
||||
features.Set<IHttpResponseFeature>(new HttpResponseFeature());
|
||||
features.Set<IHttpWebSocketFeature>(new TestHttpWebSocketFeature());
|
||||
|
||||
TestCachedFeaturesAreSet(context.GetType(), context, features);
|
||||
TestCachedFeaturesAreSet(request.GetType(), request, features);
|
||||
TestCachedFeaturesAreSet(response.GetType(), response, features);
|
||||
TestCachedFeaturesAreSet(authentication.GetType(), authentication, features);
|
||||
TestCachedFeaturesAreSet(connection.GetType(), connection, features);
|
||||
TestCachedFeaturesAreSet(websockets.GetType(), websockets, features);
|
||||
// featurecollection is set. all cached interfaces are null.
|
||||
var context = new DefaultHttpContext(features);
|
||||
TestAllCachedFeaturesAreNull(context, features);
|
||||
Assert.Equal(3, features.Count());
|
||||
|
||||
// getting feature properties populates feature collection with defaults
|
||||
TestAllCachedFeaturesAreSet(context, features);
|
||||
Assert.NotEqual(3, features.Count());
|
||||
|
||||
// featurecollection is null. and all cached interfaces are null.
|
||||
// only top level is tested because child objects are inaccessible.
|
||||
context.Uninitialize();
|
||||
TestCachedFeaturesAreNull(context, null);
|
||||
|
||||
Assert.NotEqual(0, features.Count());
|
||||
|
||||
var newFeatures = new FeatureCollection();
|
||||
context.UpdateFeatures(newFeatures);
|
||||
|
||||
Assert.Equal(0, newFeatures.Count());
|
||||
|
||||
TestCachedFeaturesAreNull(context.GetType(), context, newFeatures);
|
||||
TestCachedFeaturesAreNull(request.GetType(), request, newFeatures);
|
||||
TestCachedFeaturesAreNull(response.GetType(), response, newFeatures);
|
||||
TestCachedFeaturesAreNull(authentication.GetType(), authentication, newFeatures);
|
||||
TestCachedFeaturesAreNull(connection.GetType(), connection, newFeatures);
|
||||
TestCachedFeaturesAreNull(websockets.GetType(), websockets, newFeatures);
|
||||
|
||||
context.Session = new TestSession();
|
||||
newFeatures.Set<IHttpRequestFeature>(new HttpRequestFeature());
|
||||
newFeatures.Set<IHttpResponseFeature>(new HttpResponseFeature());
|
||||
newFeatures.Set<IHttpWebSocketFeature>(new TestHttpWebSocketFeature());
|
||||
|
||||
TestCachedFeaturesAreSet(context.GetType(), context, newFeatures);
|
||||
TestCachedFeaturesAreSet(request.GetType(), request, newFeatures);
|
||||
TestCachedFeaturesAreSet(response.GetType(), response, newFeatures);
|
||||
TestCachedFeaturesAreSet(authentication.GetType(), authentication, newFeatures);
|
||||
TestCachedFeaturesAreSet(connection.GetType(), connection, newFeatures);
|
||||
TestCachedFeaturesAreSet(websockets.GetType(), websockets, newFeatures);
|
||||
// featurecollection is set to newFeatures. all cached interfaces are null.
|
||||
context.Initialize(newFeatures);
|
||||
TestAllCachedFeaturesAreNull(context, newFeatures);
|
||||
Assert.Equal(3, newFeatures.Count());
|
||||
|
||||
Assert.NotEqual(0, newFeatures.Count());
|
||||
// getting feature properties populates new feature collection with defaults
|
||||
TestAllCachedFeaturesAreSet(context, newFeatures);
|
||||
Assert.NotEqual(3, newFeatures.Count());
|
||||
}
|
||||
|
||||
void TestCachedFeaturesAreNull(Type type, object value, IFeatureCollection features)
|
||||
void TestAllCachedFeaturesAreNull(HttpContext context, IFeatureCollection features)
|
||||
{
|
||||
TestCachedFeaturesAreNull(context, features);
|
||||
TestCachedFeaturesAreNull(context.Request, features);
|
||||
TestCachedFeaturesAreNull(context.Response, features);
|
||||
TestCachedFeaturesAreNull(context.Authentication, features);
|
||||
TestCachedFeaturesAreNull(context.Connection, features);
|
||||
TestCachedFeaturesAreNull(context.WebSockets, features);
|
||||
}
|
||||
|
||||
var fields = type
|
||||
void TestCachedFeaturesAreNull(object value, IFeatureCollection features)
|
||||
{
|
||||
var type = value.GetType();
|
||||
|
||||
var field = type
|
||||
.GetFields(BindingFlags.NonPublic | BindingFlags.Instance)
|
||||
.Where(f => f.FieldType.GetTypeInfo().IsInterface);
|
||||
.Single(f =>
|
||||
f.FieldType.GetTypeInfo().IsGenericType &&
|
||||
f.FieldType.GetGenericTypeDefinition() == typeof(FeatureReferences<>));
|
||||
|
||||
foreach (var field in fields)
|
||||
{
|
||||
if (field.FieldType == typeof(IFeatureCollection))
|
||||
{
|
||||
Assert.Same(features, field.GetValue(value));
|
||||
}
|
||||
else
|
||||
{
|
||||
Assert.Null(field.GetValue(value));
|
||||
}
|
||||
}
|
||||
var boxedExpectedStruct = features == null ?
|
||||
Activator.CreateInstance(field.FieldType) :
|
||||
Activator.CreateInstance(field.FieldType, features);
|
||||
|
||||
var boxedActualStruct = field.GetValue(value);
|
||||
|
||||
Assert.Equal(boxedExpectedStruct, boxedActualStruct);
|
||||
}
|
||||
|
||||
void TestCachedFeaturesAreSet(Type type, object value, IFeatureCollection features)
|
||||
void TestAllCachedFeaturesAreSet(HttpContext context, IFeatureCollection features)
|
||||
{
|
||||
TestCachedFeaturesAreSet(context, features);
|
||||
TestCachedFeaturesAreSet(context.Request, features);
|
||||
TestCachedFeaturesAreSet(context.Response, features);
|
||||
TestCachedFeaturesAreSet(context.Authentication, features);
|
||||
TestCachedFeaturesAreSet(context.Connection, features);
|
||||
TestCachedFeaturesAreSet(context.WebSockets, features);
|
||||
}
|
||||
|
||||
void TestCachedFeaturesAreSet(object value, IFeatureCollection features)
|
||||
{
|
||||
var type = value.GetType();
|
||||
|
||||
var properties = type
|
||||
.GetProperties(BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance)
|
||||
.Where(p => p.PropertyType.GetTypeInfo().IsInterface);
|
||||
|
|
|
|||
Loading…
Reference in New Issue