diff --git a/src/Microsoft.AspNet.Http.Abstractions/IReusable.cs b/src/Microsoft.AspNet.Http.Abstractions/IReusable.cs new file mode 100644 index 00000000..980f2306 --- /dev/null +++ b/src/Microsoft.AspNet.Http.Abstractions/IReusable.cs @@ -0,0 +1,10 @@ +// 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 +{ + public interface IReusable + { + void Reset(); + } +} diff --git a/src/Microsoft.AspNet.Http.Features/FeatureCollection.cs b/src/Microsoft.AspNet.Http.Features/FeatureCollection.cs index 16b4d6fb..25a87c9f 100644 --- a/src/Microsoft.AspNet.Http.Features/FeatureCollection.cs +++ b/src/Microsoft.AspNet.Http.Features/FeatureCollection.cs @@ -12,15 +12,27 @@ namespace Microsoft.AspNet.Http.Features public class FeatureCollection : IFeatureCollection { private static KeyComparer FeatureKeyComparer = new FeatureCollection.KeyComparer(); - private readonly IFeatureCollection _defaults; + private IFeatureCollection _defaults; private IDictionary _features; private volatile int _containerRevision; + private Action _onDisposing; public FeatureCollection() { } + public FeatureCollection(IFeatureCollection defaults, Action onDisposing) + : this(defaults) + { + _onDisposing = onDisposing; + } + public FeatureCollection(IFeatureCollection defaults) + { + Reset(defaults); + } + + public void Reset(IFeatureCollection defaults) { _defaults = defaults; } @@ -86,7 +98,16 @@ public IEnumerator> GetEnumerator() public virtual void Dispose() { + // REVIEW: is this necessary? is the environment "owned" by the context? _defaults?.Dispose(); + + _defaults = null; + + _features?.Clear(); + + _containerRevision = 0; + + _onDisposing?.Invoke(this); } private class KeyComparer : IEqualityComparer> diff --git a/src/Microsoft.AspNet.Http.Features/FeatureReference.cs b/src/Microsoft.AspNet.Http.Features/FeatureReference.cs index 538297a3..3fee6169 100644 --- a/src/Microsoft.AspNet.Http.Features/FeatureReference.cs +++ b/src/Microsoft.AspNet.Http.Features/FeatureReference.cs @@ -34,5 +34,11 @@ public T Update(IFeatureCollection features, T feature) _revision = features.Revision; return feature; } + + public void Reset() + { + _feature = default(T); + _revision = -1; + } } } \ No newline at end of file diff --git a/src/Microsoft.AspNet.Http/Authentication/DefaultAuthenticationManager.cs b/src/Microsoft.AspNet.Http/Authentication/DefaultAuthenticationManager.cs index 821a6739..63f28d2a 100644 --- a/src/Microsoft.AspNet.Http/Authentication/DefaultAuthenticationManager.cs +++ b/src/Microsoft.AspNet.Http/Authentication/DefaultAuthenticationManager.cs @@ -13,13 +13,18 @@ namespace Microsoft.AspNet.Http.Authentication.Internal { - public class DefaultAuthenticationManager : AuthenticationManager + public class DefaultAuthenticationManager : AuthenticationManager, IReusable { - private readonly IFeatureCollection _features; + private IFeatureCollection _features; private FeatureReference _authentication = FeatureReference.Default; private FeatureReference _response = FeatureReference.Default; public DefaultAuthenticationManager(IFeatureCollection features) + { + Initalize(features); + } + + public void Initalize(IFeatureCollection features) { _features = features; } @@ -109,5 +114,13 @@ public override async Task SignOutAsync([NotNull] string authenticationScheme, A throw new InvalidOperationException($"The following authentication scheme was not accepted: {authenticationScheme}"); } } + + public void Reset() + { + _features = null; + + _authentication.Reset(); + _response.Reset(); + } } } diff --git a/src/Microsoft.AspNet.Http/DefaultConnectionInfo.cs b/src/Microsoft.AspNet.Http/DefaultConnectionInfo.cs index 30a7ace3..a0e97345 100644 --- a/src/Microsoft.AspNet.Http/DefaultConnectionInfo.cs +++ b/src/Microsoft.AspNet.Http/DefaultConnectionInfo.cs @@ -1,6 +1,7 @@ // 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.Net; using System.Security.Cryptography.X509Certificates; using System.Threading; @@ -10,14 +11,19 @@ namespace Microsoft.AspNet.Http.Internal { - public class DefaultConnectionInfo : ConnectionInfo + public class DefaultConnectionInfo : ConnectionInfo, IReusable { - private readonly IFeatureCollection _features; + private IFeatureCollection _features; private FeatureReference _connection = FeatureReference.Default; private FeatureReference _tlsConnection = FeatureReference.Default; public DefaultConnectionInfo(IFeatureCollection features) + { + Initalize(features); + } + + internal void Initalize(IFeatureCollection features) { _features = features; } @@ -72,5 +78,13 @@ public override X509Certificate2 ClientCertificate { return TlsConnectionFeature.GetClientCertificateAsync(cancellationToken); } + + public void Reset() + { + _features = null; + + _connection.Reset(); + _tlsConnection.Reset(); + } } } \ No newline at end of file diff --git a/src/Microsoft.AspNet.Http/DefaultHttpContext.cs b/src/Microsoft.AspNet.Http/DefaultHttpContext.cs index db0a4d27..0765a554 100644 --- a/src/Microsoft.AspNet.Http/DefaultHttpContext.cs +++ b/src/Microsoft.AspNet.Http/DefaultHttpContext.cs @@ -16,10 +16,10 @@ namespace Microsoft.AspNet.Http.Internal { public class DefaultHttpContext : HttpContext { - private readonly HttpRequest _request; - private readonly HttpResponse _response; - private readonly ConnectionInfo _connection; - private readonly AuthenticationManager _authenticationManager; + private readonly DefaultHttpRequest _request; + private readonly DefaultHttpResponse _response; + private readonly DefaultConnectionInfo _connection; + private readonly DefaultAuthenticationManager _authenticationManager; private FeatureReference _items; private FeatureReference _serviceProviders; @@ -28,6 +28,7 @@ public class DefaultHttpContext : HttpContext private FeatureReference _session; private WebSocketManager _websockets; private IFeatureCollection _features; + private Action _onDisposing; public DefaultHttpContext() : this(new FeatureCollection()) @@ -36,6 +37,12 @@ public DefaultHttpContext() _features.Set(new HttpResponseFeature()); } + public DefaultHttpContext(IFeatureCollection features, Action onDisposing) + : this(features) + { + _onDisposing = onDisposing; + } + public DefaultHttpContext(IFeatureCollection features) { _features = features; @@ -51,6 +58,16 @@ public DefaultHttpContext(IFeatureCollection features) _session = FeatureReference.Default; } + public void Initalize(IFeatureCollection features) + { + _features = features; + + _request.Initalize(this, features); + _response.Initalize(this, features); + _connection.Initalize(features); + _authenticationManager.Initalize(features); + } + IItemsFeature ItemsFeature { get { return _items.Fetch(_features) ?? _items.Update(_features, new ItemsFeature()); } @@ -168,8 +185,26 @@ public override void Abort() public override void Dispose() { - // REVIEW: is this necessary? is the environment "owned" by the context? _features.Dispose(); + _features = null; + + _request.Reset(); + _response.Reset(); + _connection.Reset(); + _authenticationManager.Reset(); + + _items.Reset(); + _serviceProviders.Reset(); + _authentication.Reset(); + _lifetime.Reset(); + _session.Reset(); + + _websockets = null; + + if(_onDisposing != null) + { + _onDisposing(this); + } } } } \ No newline at end of file diff --git a/src/Microsoft.AspNet.Http/DefaultHttpRequest.cs b/src/Microsoft.AspNet.Http/DefaultHttpRequest.cs index 479ead6e..ad598d16 100644 --- a/src/Microsoft.AspNet.Http/DefaultHttpRequest.cs +++ b/src/Microsoft.AspNet.Http/DefaultHttpRequest.cs @@ -11,10 +11,10 @@ namespace Microsoft.AspNet.Http.Internal { - public class DefaultHttpRequest : HttpRequest + public class DefaultHttpRequest : HttpRequest, IReusable { - private readonly DefaultHttpContext _context; - private readonly IFeatureCollection _features; + private DefaultHttpContext _context; + private IFeatureCollection _features; private FeatureReference _request = FeatureReference.Default; private FeatureReference _query = FeatureReference.Default; @@ -22,11 +22,16 @@ public class DefaultHttpRequest : HttpRequest private FeatureReference _cookies = FeatureReference.Default; public DefaultHttpRequest(DefaultHttpContext context, IFeatureCollection features) + { + Initalize(context, features); + } + + internal void Initalize(DefaultHttpContext context, IFeatureCollection features) { _context = context; _features = features; } - + private IHttpRequestFeature HttpRequestFeature { get { return _request.Fetch(_features); } @@ -153,5 +158,16 @@ public override Task ReadFormAsync(CancellationToken cancellati { return FormFeature.ReadFormAsync(cancellationToken); } + + public void Reset() + { + _context = null; + _features = null; + + _request.Reset(); + _query.Reset(); + _form.Reset(); + _cookies.Reset(); + } } -} \ No newline at end of file +} diff --git a/src/Microsoft.AspNet.Http/DefaultHttpResponse.cs b/src/Microsoft.AspNet.Http/DefaultHttpResponse.cs index b47279bf..16d55169 100644 --- a/src/Microsoft.AspNet.Http/DefaultHttpResponse.cs +++ b/src/Microsoft.AspNet.Http/DefaultHttpResponse.cs @@ -10,14 +10,19 @@ namespace Microsoft.AspNet.Http.Internal { - public class DefaultHttpResponse : HttpResponse + public class DefaultHttpResponse : HttpResponse, IReusable { - private readonly DefaultHttpContext _context; - private readonly IFeatureCollection _features; + private DefaultHttpContext _context; + private IFeatureCollection _features; private FeatureReference _response = FeatureReference.Default; private FeatureReference _cookies = FeatureReference.Default; public DefaultHttpResponse(DefaultHttpContext context, IFeatureCollection features) + { + Initalize(context, features); + } + + internal void Initalize(DefaultHttpContext context, IFeatureCollection features) { _context = context; _features = features; @@ -116,5 +121,14 @@ public override void Redirect(string location, bool permanent) Headers[HeaderNames.Location] = location; } + + public void Reset() + { + _context = null; + _features = null; + + _response.Reset(); + _cookies.Reset(); + } } } \ No newline at end of file