diff --git a/src/Microsoft.AspNet.Http.Features/FeatureCollection.cs b/src/Microsoft.AspNet.Http.Features/FeatureCollection.cs index 246af4d1..bfaf5ee5 100644 --- a/src/Microsoft.AspNet.Http.Features/FeatureCollection.cs +++ b/src/Microsoft.AspNet.Http.Features/FeatureCollection.cs @@ -5,6 +5,7 @@ using System.Collections; using System.Collections.Generic; using System.Linq; +using System.Reflection; namespace Microsoft.AspNet.Http.Features { @@ -93,6 +94,21 @@ public IEnumerator> GetEnumerator() } } + public TFeature Get() + { + var type = typeof(TFeature); + if (type.GetTypeInfo().IsValueType) + { + return default(TFeature); + } + return (TFeature)this[type]; + } + + public void Set(TFeature instance) + { + this[typeof(TFeature)] = instance; + } + private class KeyComparer : IEqualityComparer> { public bool Equals(KeyValuePair x, KeyValuePair y) diff --git a/src/Microsoft.AspNet.Http.Features/FeatureCollectionExtensions.cs b/src/Microsoft.AspNet.Http.Features/FeatureCollectionExtensions.cs deleted file mode 100644 index 86681fde..00000000 --- a/src/Microsoft.AspNet.Http.Features/FeatureCollectionExtensions.cs +++ /dev/null @@ -1,30 +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 -{ - public static class FeatureCollectionExtensions - { - /// - /// Retrieves the requested feature from the collection. - /// - /// The feature key. - /// The collection. - /// The requested feature, or null if it is not present. - public static TFeature Get(this IFeatureCollection features) - { - return (TFeature)features[typeof(TFeature)]; - } - - /// - /// Sets the given feature in the collection. - /// - /// The feature key. - /// The collection. - /// The feature value. - public static void Set(this IFeatureCollection features, TFeature instance) - { - features[typeof(TFeature)] = instance; - } - } -} diff --git a/src/Microsoft.AspNet.Http.Features/FeatureReferences.cs b/src/Microsoft.AspNet.Http.Features/FeatureReferences.cs index 30d7c363..e8e5ebf5 100644 --- a/src/Microsoft.AspNet.Http.Features/FeatureReferences.cs +++ b/src/Microsoft.AspNet.Http.Features/FeatureReferences.cs @@ -25,6 +25,7 @@ public FeatureReferences(IFeatureCollection collection) public TFeature Fetch( ref TFeature cached, + Func recheckCache, TState state, Func factory) { @@ -32,11 +33,20 @@ public TFeature Fetch( if (Revision != Collection.Revision) { cleared = true; - Cache = default(TCache); + Cache = recheckCache != null ? Collection.Get() : default(TCache); Revision = Collection.Revision; } - var feature = cached; + TFeature feature; + if (recheckCache != null && cleared) + { + feature = recheckCache(); + } + else + { + feature = cached; + } + if (feature == null) { feature = Collection.Get(); @@ -45,10 +55,6 @@ public TFeature Fetch( feature = factory(state); Collection.Set(feature); - if (!cleared) - { - Cache = default(TCache); - } Revision = Collection.Revision; } cached = feature; @@ -56,7 +62,10 @@ public TFeature Fetch( return feature; } + public TFeature Fetch(ref TFeature cached, Func recheckCache, Func factory) => + Fetch(ref cached, recheckCache, Collection, factory); + public TFeature Fetch(ref TFeature cached, Func factory) => - Fetch(ref cached, Collection, factory); + Fetch(ref cached, null, Collection, factory); } } \ No newline at end of file diff --git a/src/Microsoft.AspNet.Http.Features/IFeatureCollection.cs b/src/Microsoft.AspNet.Http.Features/IFeatureCollection.cs index c7ad165c..454cafa3 100644 --- a/src/Microsoft.AspNet.Http.Features/IFeatureCollection.cs +++ b/src/Microsoft.AspNet.Http.Features/IFeatureCollection.cs @@ -27,5 +27,19 @@ public interface IFeatureCollection : IEnumerable> /// /// The requested feature, or null if it is not present. object this[Type key] { get; set; } + + /// + /// Retrieves the requested feature from the collection. + /// + /// The feature key. + /// The requested feature, or null if it is not present. + TFeature Get(); + + /// + /// Sets the given feature in the collection. + /// + /// The feature key. + /// The feature value. + void Set(TFeature instance); } } diff --git a/src/Microsoft.AspNet.Http/DefaultConnectionInfo.cs b/src/Microsoft.AspNet.Http/DefaultConnectionInfo.cs index dd19f7d2..cd2d0eab 100644 --- a/src/Microsoft.AspNet.Http/DefaultConnectionInfo.cs +++ b/src/Microsoft.AspNet.Http/DefaultConnectionInfo.cs @@ -12,7 +12,7 @@ namespace Microsoft.AspNet.Http.Internal { public class DefaultConnectionInfo : ConnectionInfo { - private FeatureReferences _features; + private FeatureReferences _features; public DefaultConnectionInfo(IFeatureCollection features) { @@ -21,19 +21,19 @@ public DefaultConnectionInfo(IFeatureCollection features) public virtual void Initialize( IFeatureCollection features) { - _features = new FeatureReferences(features); + _features = new FeatureReferences(features); } public virtual void Uninitialize() { - _features = default(FeatureReferences); + _features = default(FeatureReferences); } private IHttpConnectionFeature HttpConnectionFeature => - _features.Fetch(ref _features.Cache.Connection, f => new HttpConnectionFeature()); + _features.Fetch(ref _features.Cache.Connection, () => _features.Cache.Connection, f => new HttpConnectionFeature()); private ITlsConnectionFeature TlsConnectionFeature=> - _features.Fetch(ref _features.Cache.TlsConnection, f => new TlsConnectionFeature()); + _features.Fetch(ref _features.Cache.TlsConnection, () => _features.Cache.TlsConnection, f => new TlsConnectionFeature()); public override IPAddress RemoteIpAddress { @@ -75,11 +75,5 @@ public override X509Certificate2 ClientCertificate { return TlsConnectionFeature.GetClientCertificateAsync(cancellationToken); } - - struct FeatureInterfaces - { - public IHttpConnectionFeature Connection; - public ITlsConnectionFeature TlsConnection; - } } } \ No newline at end of file diff --git a/src/Microsoft.AspNet.Http/DefaultHttpContext.cs b/src/Microsoft.AspNet.Http/DefaultHttpContext.cs index 9cc4211c..19400645 100644 --- a/src/Microsoft.AspNet.Http/DefaultHttpContext.cs +++ b/src/Microsoft.AspNet.Http/DefaultHttpContext.cs @@ -16,7 +16,7 @@ namespace Microsoft.AspNet.Http.Internal { public class DefaultHttpContext : HttpContext { - private FeatureReferences _features; + private FeatureReferences _features; private HttpRequest _request; private HttpResponse _response; @@ -38,14 +38,14 @@ public DefaultHttpContext(IFeatureCollection features) public virtual void Initialize(IFeatureCollection features) { - _features = new FeatureReferences(features); + _features = new FeatureReferences(features); _request = InitializeHttpRequest(); _response = InitializeHttpResponse(); } public virtual void Uninitialize() { - _features = default(FeatureReferences); + _features = default(FeatureReferences); if (_request != null) { UninitializeHttpRequest(_request); @@ -74,26 +74,25 @@ public virtual void Uninitialize() } private IItemsFeature ItemsFeature => - _features.Fetch(ref _features.Cache.Items, f => new ItemsFeature()); + _features.Fetch(ref _features.Cache.Items, () => _features.Cache.Items, f => new ItemsFeature()); private IServiceProvidersFeature ServiceProvidersFeature => - _features.Fetch(ref _features.Cache.ServiceProviders, f => new ServiceProvidersFeature()); + _features.Fetch(ref _features.Cache.ServiceProviders, () => _features.Cache.ServiceProviders, f => new ServiceProvidersFeature()); private IHttpAuthenticationFeature HttpAuthenticationFeature => - _features.Fetch(ref _features.Cache.Authentication, f => new HttpAuthenticationFeature()); + _features.Fetch(ref _features.Cache.Authentication, () => _features.Cache.Authentication, f => new HttpAuthenticationFeature()); private IHttpRequestLifetimeFeature LifetimeFeature => - _features.Fetch(ref _features.Cache.Lifetime, f => new HttpRequestLifetimeFeature()); + _features.Fetch(ref _features.Cache.Lifetime, () => _features.Cache.Lifetime, f => new HttpRequestLifetimeFeature()); private ISessionFeature SessionFeature => - _features.Fetch(ref _features.Cache.Session, f => new DefaultSessionFeature()); + _features.Fetch(ref _features.Cache.Session, () => _features.Cache.Session, f => new DefaultSessionFeature()); private ISessionFeature SessionFeatureOrNull => - _features.Fetch(ref _features.Cache.Session, f => null); - + _features.Fetch(ref _features.Cache.Session, () => _features.Cache.Session, f => null); private IHttpRequestIdentifierFeature RequestIdentifierFeature => - _features.Fetch(ref _features.Cache.RequestIdentifier, f => new HttpRequestIdentifierFeature()); + _features.Fetch(ref _features.Cache.RequestIdentifier, () => _features.Cache.RequestIdentifier, f => new HttpRequestIdentifierFeature()); public override IFeatureCollection Features => _features.Collection; @@ -187,15 +186,5 @@ protected virtual void UninitializeAuthenticationManager(AuthenticationManager i 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; - } } } diff --git a/src/Microsoft.AspNet.Http/DefaultHttpRequest.cs b/src/Microsoft.AspNet.Http/DefaultHttpRequest.cs index 5d3a2875..f1512fde 100644 --- a/src/Microsoft.AspNet.Http/DefaultHttpRequest.cs +++ b/src/Microsoft.AspNet.Http/DefaultHttpRequest.cs @@ -14,7 +14,7 @@ namespace Microsoft.AspNet.Http.Internal public class DefaultHttpRequest : HttpRequest { private HttpContext _context; - private FeatureReferences _features; + private FeatureReferences _features; public DefaultHttpRequest(HttpContext context, IFeatureCollection features) { @@ -24,28 +24,28 @@ public DefaultHttpRequest(HttpContext context, IFeatureCollection features) public virtual void Initialize(HttpContext context, IFeatureCollection features) { _context = context; - _features = new FeatureReferences(features); + _features = new FeatureReferences(features); } public virtual void Uninitialize() { _context = null; - _features = default(FeatureReferences); + _features = default(FeatureReferences); } public override HttpContext HttpContext => _context; private IHttpRequestFeature HttpRequestFeature => - _features.Fetch(ref _features.Cache.Request, f => null); + _features.Fetch(ref _features.Cache.Request, () => _features.Cache.Request, f => null); private IQueryFeature QueryFeature => - _features.Fetch(ref _features.Cache.Query, f => new QueryFeature(f)); + _features.Fetch(ref _features.Cache.Query, () => _features.Cache.Query, f => new QueryFeature(f)); private IFormFeature FormFeature => - _features.Fetch(ref _features.Cache.Form, this, f => new FormFeature(f)); + _features.Fetch(ref _features.Cache.Form, () => _features.Cache.Form, this, f => new FormFeature(f)); private IRequestCookiesFeature RequestCookiesFeature => - _features.Fetch(ref _features.Cache.Cookies, f => new RequestCookiesFeature(f)); + _features.Fetch(ref _features.Cache.Cookies, () => _features.Cache.Cookies, f => new RequestCookiesFeature(f)); public override PathString PathBase { @@ -151,13 +151,5 @@ public override Task ReadFormAsync(CancellationToken cancellati { return FormFeature.ReadFormAsync(cancellationToken); } - - struct FeatureInterfaces - { - public IHttpRequestFeature Request; - public IQueryFeature Query; - public IFormFeature Form; - public IRequestCookiesFeature Cookies; - } } } \ No newline at end of file diff --git a/src/Microsoft.AspNet.Http/DefaultHttpResponse.cs b/src/Microsoft.AspNet.Http/DefaultHttpResponse.cs index a9cb49cb..1fa6c001 100644 --- a/src/Microsoft.AspNet.Http/DefaultHttpResponse.cs +++ b/src/Microsoft.AspNet.Http/DefaultHttpResponse.cs @@ -13,7 +13,7 @@ namespace Microsoft.AspNet.Http.Internal public class DefaultHttpResponse : HttpResponse { private HttpContext _context; - private FeatureReferences _features; + private FeatureReferences _features; public DefaultHttpResponse(HttpContext context, IFeatureCollection features) { @@ -23,20 +23,20 @@ public DefaultHttpResponse(HttpContext context, IFeatureCollection features) public virtual void Initialize(HttpContext context, IFeatureCollection features) { _context = context; - _features = new FeatureReferences(features); + _features = new FeatureReferences(features); } public virtual void Uninitialize() { _context = null; - _features = default(FeatureReferences); + _features = default(FeatureReferences); } private IHttpResponseFeature HttpResponseFeature => - _features.Fetch(ref _features.Cache.Response, f => null); + _features.Fetch(ref _features.Cache.Response, () => _features.Cache.Response, f => null); private IResponseCookiesFeature ResponseCookiesFeature => - _features.Fetch(ref _features.Cache.Cookies, f => new ResponseCookiesFeature(f)); + _features.Fetch(ref _features.Cache.Cookies, () => _features.Cache.Cookies, f => new ResponseCookiesFeature(f)); public override HttpContext HttpContext { get { return _context; } } @@ -132,11 +132,5 @@ public override void Redirect(string location, bool permanent) Headers[HeaderNames.Location] = location; } - - struct FeatureInterfaces - { - public IHttpResponseFeature Response; - public IResponseCookiesFeature Cookies; - } } } \ No newline at end of file diff --git a/src/Microsoft.AspNet.Http/DefaultWebSocketManager.cs b/src/Microsoft.AspNet.Http/DefaultWebSocketManager.cs index 8beff4db..55bf0d3c 100644 --- a/src/Microsoft.AspNet.Http/DefaultWebSocketManager.cs +++ b/src/Microsoft.AspNet.Http/DefaultWebSocketManager.cs @@ -12,7 +12,7 @@ namespace Microsoft.AspNet.Http.Internal { public class DefaultWebSocketManager : WebSocketManager { - private FeatureReferences _features; + private FeatureReferences _features; public DefaultWebSocketManager(IFeatureCollection features) { @@ -21,19 +21,19 @@ public DefaultWebSocketManager(IFeatureCollection features) public virtual void Initialize(IFeatureCollection features) { - _features = new FeatureReferences(features); + _features = new FeatureReferences(features); } public virtual void Uninitialize() { - _features = default(FeatureReferences); + _features = default(FeatureReferences); } private IHttpRequestFeature HttpRequestFeature => - _features.Fetch(ref _features.Cache.Request, f => null); + _features.Fetch(ref _features.Cache.Request, () => _features.Cache.Request, f => null); private IHttpWebSocketFeature WebSocketFeature => - _features.Fetch(ref _features.Cache.WebSockets, f => null); + _features.Fetch(ref _features.Cache.WebSockets, () => _features.Cache.WebSockets, f => null); public override bool IsWebSocketRequest { @@ -59,11 +59,5 @@ public override Task AcceptWebSocketAsync(string subProtocol) } return WebSocketFeature.AcceptAsync(new WebSocketAcceptContext() { SubProtocol = subProtocol }); } - - struct FeatureInterfaces - { - public IHttpRequestFeature Request; - public IHttpWebSocketFeature WebSockets; - } } } diff --git a/src/Microsoft.AspNet.Http/Internal/ConnectionFeatures.cs b/src/Microsoft.AspNet.Http/Internal/ConnectionFeatures.cs new file mode 100644 index 00000000..d84659f3 --- /dev/null +++ b/src/Microsoft.AspNet.Http/Internal/ConnectionFeatures.cs @@ -0,0 +1,13 @@ +// 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; + +namespace Microsoft.AspNet.Http.Internal +{ + public struct ConnectionFeatures + { + public IHttpConnectionFeature Connection; + public ITlsConnectionFeature TlsConnection; + } +} diff --git a/src/Microsoft.AspNet.Http/Internal/ContextFeatures.cs b/src/Microsoft.AspNet.Http/Internal/ContextFeatures.cs new file mode 100644 index 00000000..961cf745 --- /dev/null +++ b/src/Microsoft.AspNet.Http/Internal/ContextFeatures.cs @@ -0,0 +1,19 @@ +// 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; +using Microsoft.AspNet.Http.Features.Authentication; +using Microsoft.AspNet.Http.Features.Internal; + +namespace Microsoft.AspNet.Http.Internal +{ + public struct ContextFeatures + { + public IItemsFeature Items; + public IServiceProvidersFeature ServiceProviders; + public IHttpAuthenticationFeature Authentication; + public IHttpRequestLifetimeFeature Lifetime; + public ISessionFeature Session; + public IHttpRequestIdentifierFeature RequestIdentifier; + } +} diff --git a/src/Microsoft.AspNet.Http/Internal/RequestFeatures.cs b/src/Microsoft.AspNet.Http/Internal/RequestFeatures.cs new file mode 100644 index 00000000..d5c77716 --- /dev/null +++ b/src/Microsoft.AspNet.Http/Internal/RequestFeatures.cs @@ -0,0 +1,16 @@ +// 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; +using Microsoft.AspNet.Http.Features.Internal; + +namespace Microsoft.AspNet.Http.Internal +{ + public struct RequestFeatures + { + public IHttpRequestFeature Request; + public IQueryFeature Query; + public IFormFeature Form; + public IRequestCookiesFeature Cookies; + } +} diff --git a/src/Microsoft.AspNet.Http/Internal/ResponseFeatures.cs b/src/Microsoft.AspNet.Http/Internal/ResponseFeatures.cs new file mode 100644 index 00000000..2784dd1d --- /dev/null +++ b/src/Microsoft.AspNet.Http/Internal/ResponseFeatures.cs @@ -0,0 +1,14 @@ +// 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; +using Microsoft.AspNet.Http.Features.Internal; + +namespace Microsoft.AspNet.Http.Internal +{ + public struct ResponseFeatures + { + public IHttpResponseFeature Response; + public IResponseCookiesFeature Cookies; + } +} diff --git a/src/Microsoft.AspNet.Http/Internal/WebsocketFeatures.cs b/src/Microsoft.AspNet.Http/Internal/WebsocketFeatures.cs new file mode 100644 index 00000000..c6546c9b --- /dev/null +++ b/src/Microsoft.AspNet.Http/Internal/WebsocketFeatures.cs @@ -0,0 +1,13 @@ +// 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; + +namespace Microsoft.AspNet.Http.Internal +{ + public struct WebsocketFeatures + { + public IHttpRequestFeature Request; + public IHttpWebSocketFeature WebSockets; + } +} diff --git a/src/Microsoft.AspNet.Owin/OwinFeatureCollection.cs b/src/Microsoft.AspNet.Owin/OwinFeatureCollection.cs index acf3e221..0aede9ce 100644 --- a/src/Microsoft.AspNet.Owin/OwinFeatureCollection.cs +++ b/src/Microsoft.AspNet.Owin/OwinFeatureCollection.cs @@ -388,6 +388,21 @@ public IEnumerator> GetEnumerator() } } + public TFeature Get() + { + var type = typeof(TFeature); + if (type.GetTypeInfo().IsValueType) + { + return default(TFeature); + } + return (TFeature)this[type]; + } + + public void Set(TFeature instance) + { + this[typeof(TFeature)] = instance; + } + public void Dispose() { }