diff --git a/src/Microsoft.AspNet.Http.Abstractions/HttpContext.cs b/src/Microsoft.AspNet.Http.Abstractions/HttpContext.cs index c7a63c83..4e89caed 100644 --- a/src/Microsoft.AspNet.Http.Abstractions/HttpContext.cs +++ b/src/Microsoft.AspNet.Http.Abstractions/HttpContext.cs @@ -12,6 +12,8 @@ namespace Microsoft.AspNet.Http { public abstract class HttpContext : IDisposable { + public abstract IFeatureCollection Features { get; } + public abstract HttpRequest Request { get; } public abstract HttpResponse Response { get; } diff --git a/src/Microsoft.AspNet.Http.Extensions/SendFileResponseExtensions.cs b/src/Microsoft.AspNet.Http.Extensions/SendFileResponseExtensions.cs index 3c5f183c..b60f1aca 100644 --- a/src/Microsoft.AspNet.Http.Extensions/SendFileResponseExtensions.cs +++ b/src/Microsoft.AspNet.Http.Extensions/SendFileResponseExtensions.cs @@ -22,7 +22,7 @@ public static class SendFileResponseExtensions /// True if sendfile feature exists in the response. public static bool SupportsSendFile([NotNull] this HttpResponse response) { - return response.HttpContext.GetFeature() != null; + return response.HttpContext.Features.Get() != null; } /// @@ -47,7 +47,7 @@ public static Task SendFileAsync([NotNull] this HttpResponse response, [NotNull] /// public static Task SendFileAsync([NotNull] this HttpResponse response, [NotNull] string fileName, long offset, long? count, CancellationToken cancellationToken) { - var sendFile = response.HttpContext.GetFeature(); + var sendFile = response.HttpContext.Features.Get(); if (sendFile == null) { throw new NotSupportedException(Resources.Exception_SendFileNotSupported); diff --git a/src/Microsoft.AspNet.Http.Features/FeatureCollectionExtensions.cs b/src/Microsoft.AspNet.Http.Features/FeatureCollectionExtensions.cs new file mode 100644 index 00000000..86681fde --- /dev/null +++ b/src/Microsoft.AspNet.Http.Features/FeatureCollectionExtensions.cs @@ -0,0 +1,30 @@ +// 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/DefaultHttpContext.cs b/src/Microsoft.AspNet.Http/DefaultHttpContext.cs index c3caf8ec..fd9ad194 100644 --- a/src/Microsoft.AspNet.Http/DefaultHttpContext.cs +++ b/src/Microsoft.AspNet.Http/DefaultHttpContext.cs @@ -32,8 +32,8 @@ public class DefaultHttpContext : HttpContext public DefaultHttpContext() : this(new FeatureCollection()) { - SetFeature(new HttpRequestFeature()); - SetFeature(new HttpResponseFeature()); + _features.Set(new HttpRequestFeature()); + _features.Set(new HttpResponseFeature()); } public DefaultHttpContext(IFeatureCollection features) @@ -76,6 +76,8 @@ private ISessionFeature SessionFeature get { return _session.Fetch(_features); } } + public override IFeatureCollection Features { get { return _features; } } + public override HttpRequest Request { get { return _request; } } public override HttpResponse Response { get { return _response; } } diff --git a/src/Microsoft.AspNet.Owin/OwinEnvironment.cs b/src/Microsoft.AspNet.Owin/OwinEnvironment.cs index 62ca09b8..c6cdd639 100644 --- a/src/Microsoft.AspNet.Owin/OwinEnvironment.cs +++ b/src/Microsoft.AspNet.Owin/OwinEnvironment.cs @@ -37,11 +37,11 @@ public class OwinEnvironment : IDictionary public OwinEnvironment(HttpContext context) { - if (context.GetFeature() == null) + if (context.Features.Get() == null) { throw new ArgumentException("Missing required feature: " + nameof(IHttpRequestFeature) + ".", nameof(context)); } - if (context.GetFeature() == null) + if (context.Features.Get() == null) { throw new ArgumentException("Missing required feature: " + nameof(IHttpResponseFeature) + ".", nameof(context)); } @@ -100,7 +100,7 @@ public OwinEnvironment(HttpContext context) }; // owin.CallCancelled is required but the feature may not be present. - if (context.GetFeature() != null) + if (context.Features.Get() != null) { _entries[OwinConstants.CallCancelled] = new FeatureMap(feature => feature.RequestAborted); } @@ -334,7 +334,7 @@ public bool CanSet internal bool TryGet(HttpContext context, out object value) { - object featureInstance = context.GetFeature(FeatureInterface); + object featureInstance = context.Features[FeatureInterface]; if (featureInstance == null) { value = null; @@ -350,7 +350,7 @@ internal bool TryGet(HttpContext context, out object value) internal void Set(HttpContext context, object value) { - var feature = context.GetFeature(FeatureInterface); + var feature = context.Features[FeatureInterface]; if (feature == null) { if (FeatureFactory == null) @@ -360,7 +360,7 @@ internal void Set(HttpContext context, object value) else { feature = FeatureFactory(); - context.SetFeature(FeatureInterface, feature); + context.Features[FeatureInterface] = feature; } } Setter(feature, value); diff --git a/src/Microsoft.AspNet.Owin/OwinExtensions.cs b/src/Microsoft.AspNet.Owin/OwinExtensions.cs index 770f02fb..3f31ce59 100644 --- a/src/Microsoft.AspNet.Owin/OwinExtensions.cs +++ b/src/Microsoft.AspNet.Owin/OwinExtensions.cs @@ -39,7 +39,7 @@ public static AddMiddleware UseOwin(this IApplicationBuilder builder) { // Use the existing OWIN env if there is one. IDictionary env; - var owinEnvFeature = httpContext.GetFeature(); + var owinEnvFeature = httpContext.Features.Get(); if (owinEnvFeature != null) { env = owinEnvFeature.Environment; @@ -87,7 +87,7 @@ private static CreateMiddleware CreateMiddlewareFactory(Func { - return next(httpContext.GetFeature().Environment); + return next(httpContext.Features.Get().Environment); }); return env => @@ -98,7 +98,7 @@ private static CreateMiddleware CreateMiddlewareFactory(Func(new OwinEnvironmentFeature() { Environment = env }); + context.Features.Set(new OwinEnvironmentFeature() { Environment = env }); } else { diff --git a/test/Microsoft.AspNet.Http.Extensions.Tests/SendFileResponseExtensionsTests.cs b/test/Microsoft.AspNet.Http.Extensions.Tests/SendFileResponseExtensionsTests.cs index ef8aa04c..cd16acb0 100644 --- a/test/Microsoft.AspNet.Http.Extensions.Tests/SendFileResponseExtensionsTests.cs +++ b/test/Microsoft.AspNet.Http.Extensions.Tests/SendFileResponseExtensionsTests.cs @@ -17,7 +17,7 @@ public void SendFileSupport() var context = new DefaultHttpContext(); var response = context.Response; Assert.False(response.SupportsSendFile()); - context.SetFeature(new FakeSendFileFeature()); + context.Features.Set(new FakeSendFileFeature()); Assert.True(response.SupportsSendFile()); } @@ -34,7 +34,7 @@ public async Task SendFileWorks() var context = new DefaultHttpContext(); var response = context.Response; var fakeFeature = new FakeSendFileFeature(); - context.SetFeature(fakeFeature); + context.Features.Set(fakeFeature); await response.SendFileAsync("bob", 1, 3, CancellationToken.None); diff --git a/test/Microsoft.AspNet.Http.Tests/Authentication/DefaultAuthenticationManagerTests.cs b/test/Microsoft.AspNet.Http.Tests/Authentication/DefaultAuthenticationManagerTests.cs index 3430382e..db7e1f7f 100644 --- a/test/Microsoft.AspNet.Http.Tests/Authentication/DefaultAuthenticationManagerTests.cs +++ b/test/Microsoft.AspNet.Http.Tests/Authentication/DefaultAuthenticationManagerTests.cs @@ -4,6 +4,7 @@ using System; using System.Security.Claims; using System.Threading.Tasks; +using Microsoft.AspNet.Http.Features; using Microsoft.AspNet.Http.Features.Authentication; using Microsoft.AspNet.Http.Features.Authentication.Internal; using Microsoft.AspNet.Http.Internal; @@ -50,7 +51,7 @@ public async Task SignInOutIn() { var context = CreateContext(); var handler = new AuthHandler(); - context.SetFeature(new HttpAuthenticationFeature() { Handler = handler }); + context.Features.Set(new HttpAuthenticationFeature() { Handler = handler }); var user = new ClaimsPrincipal(); await context.Authentication.SignInAsync("ignored", user); Assert.True(handler.SignedIn); diff --git a/test/Microsoft.AspNet.Http.Tests/DefaultHttpContextTests.cs b/test/Microsoft.AspNet.Http.Tests/DefaultHttpContextTests.cs index f24035e6..b8c9691e 100644 --- a/test/Microsoft.AspNet.Http.Tests/DefaultHttpContextTests.cs +++ b/test/Microsoft.AspNet.Http.Tests/DefaultHttpContextTests.cs @@ -35,7 +35,7 @@ public void GetOnSessionProperty_ReturnsAvailableSession() session.Set("key2", null); var feature = new BlahSessionFeature(); feature.Session = session; - context.SetFeature(feature); + context.Features.Set(feature); // Act & Assert Assert.Same(session, context.Session); @@ -67,7 +67,7 @@ public void SettingSession_OverridesAvailableSession() session.Set("key2", null); var feature = new BlahSessionFeature(); feature.Session = session; - context.SetFeature(feature); + context.Features.Set(feature); // Act context.Session = new TestSession(); @@ -109,9 +109,9 @@ public void EmptyUserIsNeverNull() public void GetItems_DefaultCollectionProvided() { var context = new DefaultHttpContext(new FeatureCollection()); - Assert.Null(context.GetFeature()); + Assert.Null(context.Features.Get()); var items = context.Items; - Assert.NotNull(context.GetFeature()); + Assert.NotNull(context.Features.Get()); Assert.NotNull(items); Assert.Same(items, context.Items); var item = new object(); @@ -123,10 +123,10 @@ public void GetItems_DefaultCollectionProvided() public void SetItems_NewCollectionUsed() { var context = new DefaultHttpContext(new FeatureCollection()); - Assert.Null(context.GetFeature()); + Assert.Null(context.Features.Get()); var items = new Dictionary(); context.Items = items; - Assert.NotNull(context.GetFeature()); + Assert.NotNull(context.Features.Get()); Assert.Same(items, context.Items); var item = new object(); items["foo"] = item; diff --git a/test/Microsoft.AspNet.Http.Tests/DefaultHttpRequestTests.cs b/test/Microsoft.AspNet.Http.Tests/DefaultHttpRequestTests.cs index 16ac23f6..4a767821 100644 --- a/test/Microsoft.AspNet.Http.Tests/DefaultHttpRequestTests.cs +++ b/test/Microsoft.AspNet.Http.Tests/DefaultHttpRequestTests.cs @@ -136,7 +136,7 @@ public void IsHttps_CorrectlyReflectsScheme() public void Query_GetAndSet() { var request = new DefaultHttpContext().Request; - var requestFeature = request.HttpContext.GetFeature(); + var requestFeature = request.HttpContext.Features.Get(); Assert.Equal(string.Empty, requestFeature.QueryString); Assert.Equal(QueryString.Empty, request.QueryString); var query0 = request.Query; @@ -191,7 +191,7 @@ public void Cookies_GetAndSet() private static HttpRequest CreateRequest(IDictionary headers) { var context = new DefaultHttpContext(); - context.GetFeature().Headers = headers; + context.Features.Get().Headers = headers; return context.Request; } diff --git a/test/Microsoft.AspNet.Http.Tests/FormFeatureTests.cs b/test/Microsoft.AspNet.Http.Tests/FormFeatureTests.cs index 61dfda82..6f3eb261 100644 --- a/test/Microsoft.AspNet.Http.Tests/FormFeatureTests.cs +++ b/test/Microsoft.AspNet.Http.Tests/FormFeatureTests.cs @@ -23,7 +23,7 @@ public async Task ReadFormAsync_SimpleData_ReturnsParsedFormCollection() context.Request.Body = new MemoryStream(formContent); // Not cached yet - var formFeature = context.GetFeature(); + var formFeature = context.Features.Get(); Assert.Null(formFeature); // Act @@ -34,7 +34,7 @@ public async Task ReadFormAsync_SimpleData_ReturnsParsedFormCollection() Assert.Equal("2", formCollection["baz"]); // Cached - formFeature = context.GetFeature(); + formFeature = context.Features.Get(); Assert.NotNull(formFeature); Assert.NotNull(formFeature.Form); Assert.Same(formFeature.Form, formCollection); @@ -132,7 +132,7 @@ public async Task ReadForm_EmptyMultipart_ReturnsParsedFormCollection() context.Request.Body = new MemoryStream(formContent); // Not cached yet - var formFeature = context.GetFeature(); + var formFeature = context.Features.Get(); Assert.Null(formFeature); var formCollection = context.Request.Form; @@ -140,7 +140,7 @@ public async Task ReadForm_EmptyMultipart_ReturnsParsedFormCollection() Assert.NotNull(formCollection); // Cached - formFeature = context.GetFeature(); + formFeature = context.Features.Get(); Assert.NotNull(formFeature); Assert.NotNull(formFeature.Form); Assert.Same(formCollection, formFeature.Form); @@ -161,7 +161,7 @@ public async Task ReadForm_MultipartWithField_ReturnsParsedFormCollection() context.Request.Body = new MemoryStream(formContent); // Not cached yet - var formFeature = context.GetFeature(); + var formFeature = context.Features.Get(); Assert.Null(formFeature); var formCollection = context.Request.Form; @@ -169,7 +169,7 @@ public async Task ReadForm_MultipartWithField_ReturnsParsedFormCollection() Assert.NotNull(formCollection); // Cached - formFeature = context.GetFeature(); + formFeature = context.Features.Get(); Assert.NotNull(formFeature); Assert.NotNull(formFeature.Form); Assert.Same(formCollection, formFeature.Form); @@ -192,7 +192,7 @@ public async Task ReadFormAsync_MultipartWithFile_ReturnsParsedFormCollection() context.Request.Body = new MemoryStream(formContent); // Not cached yet - var formFeature = context.GetFeature(); + var formFeature = context.Features.Get(); Assert.Null(formFeature); var formCollection = await context.Request.ReadFormAsync(); @@ -200,7 +200,7 @@ public async Task ReadFormAsync_MultipartWithFile_ReturnsParsedFormCollection() Assert.NotNull(formCollection); // Cached - formFeature = context.GetFeature(); + formFeature = context.Features.Get(); Assert.NotNull(formFeature); Assert.NotNull(formFeature.Form); Assert.Same(formFeature.Form, formCollection); @@ -232,7 +232,7 @@ public async Task ReadFormAsync_MultipartWithFieldAndFile_ReturnsParsedFormColle context.Request.Body = new MemoryStream(formContent); // Not cached yet - var formFeature = context.GetFeature(); + var formFeature = context.Features.Get(); Assert.Null(formFeature); var formCollection = await context.Request.ReadFormAsync(); @@ -240,7 +240,7 @@ public async Task ReadFormAsync_MultipartWithFieldAndFile_ReturnsParsedFormColle Assert.NotNull(formCollection); // Cached - formFeature = context.GetFeature(); + formFeature = context.Features.Get(); Assert.NotNull(formFeature); Assert.NotNull(formFeature.Form); Assert.Same(formFeature.Form, formCollection);