diff --git a/src/Hosting/TestHost/src/ClientHandler.cs b/src/Hosting/TestHost/src/ClientHandler.cs index bb3d98105a9f..299b84bea6bd 100644 --- a/src/Hosting/TestHost/src/ClientHandler.cs +++ b/src/Hosting/TestHost/src/ClientHandler.cs @@ -184,7 +184,7 @@ protected override async Task SendAsync( // Copy trailers to the response message when the response stream is complete contextBuilder.RegisterResponseReadCompleteCallback(context => { - var responseTrailersFeature = context.Features.Get(); + var responseTrailersFeature = context.Features.Get()!; foreach (var trailer in responseTrailersFeature.Trailers) { @@ -196,7 +196,7 @@ protected override async Task SendAsync( var httpContext = await contextBuilder.SendAsync(cancellationToken); response.StatusCode = (HttpStatusCode)httpContext.Response.StatusCode; - response.ReasonPhrase = httpContext.Features.Get().ReasonPhrase; + response.ReasonPhrase = httpContext.Features.Get()!.ReasonPhrase; response.RequestMessage = request; response.Version = request.Version; diff --git a/src/Hosting/TestHost/src/HttpContextBuilder.cs b/src/Hosting/TestHost/src/HttpContextBuilder.cs index 8fb74385c1a7..ef9b6e5faee3 100644 --- a/src/Hosting/TestHost/src/HttpContextBuilder.cs +++ b/src/Hosting/TestHost/src/HttpContextBuilder.cs @@ -225,7 +225,7 @@ internal async Task ReturnResponseMessageAsync() { newFeatures[pair.Key] = pair.Value; } - var serverResponseFeature = _httpContext.Features.Get(); + var serverResponseFeature = _httpContext.Features.Get()!; // The client gets a deep copy of this so they can interact with the body stream independently of the server. var clientResponseFeature = new HttpResponseFeature() { diff --git a/src/Http/Http.Extensions/src/ResponseExtensions.cs b/src/Http/Http.Extensions/src/ResponseExtensions.cs index 5fe1614be4a2..46bb247944c3 100644 --- a/src/Http/Http.Extensions/src/ResponseExtensions.cs +++ b/src/Http/Http.Extensions/src/ResponseExtensions.cs @@ -16,7 +16,7 @@ public static void Clear(this HttpResponse response) throw new InvalidOperationException("The response cannot be cleared, it has already started sending."); } response.StatusCode = 200; - response.HttpContext.Features.Get().ReasonPhrase = null; + response.HttpContext.Features.Get()!.ReasonPhrase = null; response.Headers.Clear(); if (response.Body.CanSeek) { diff --git a/src/Http/Http.Extensions/src/SendFileResponseExtensions.cs b/src/Http/Http.Extensions/src/SendFileResponseExtensions.cs index a9fd30908b9a..a888c096112d 100644 --- a/src/Http/Http.Extensions/src/SendFileResponseExtensions.cs +++ b/src/Http/Http.Extensions/src/SendFileResponseExtensions.cs @@ -143,7 +143,7 @@ private static async Task SendFileAsyncCore(HttpResponse response, string fileNa { var useRequestAborted = !cancellationToken.CanBeCanceled; var localCancel = useRequestAborted ? response.HttpContext.RequestAborted : cancellationToken; - var sendFile = response.HttpContext.Features.Get(); + var sendFile = response.HttpContext.Features.Get()!; try { diff --git a/src/Http/Http.Features/src/FeatureCollection.cs b/src/Http/Http.Features/src/FeatureCollection.cs index d46a1e38e5bd..626277ee134f 100644 --- a/src/Http/Http.Features/src/FeatureCollection.cs +++ b/src/Http/Http.Features/src/FeatureCollection.cs @@ -98,7 +98,7 @@ public IEnumerator> GetEnumerator() return (TFeature?)this[typeof(TFeature)]; } - public void Set(TFeature instance) + public void Set(TFeature? instance) { this[typeof(TFeature)] = instance; } diff --git a/src/Http/Http.Features/src/IFeatureCollection.cs b/src/Http/Http.Features/src/IFeatureCollection.cs index 6d087df337d7..ff1f3ec69676 100644 --- a/src/Http/Http.Features/src/IFeatureCollection.cs +++ b/src/Http/Http.Features/src/IFeatureCollection.cs @@ -33,13 +33,13 @@ public interface IFeatureCollection : IEnumerable> /// /// The feature key. /// The requested feature, or null if it is not present. - TFeature Get(); + TFeature? Get(); /// /// Sets the given feature in the collection. /// /// The feature key. /// The feature value. - void Set(TFeature instance); + void Set(TFeature? instance); } } diff --git a/src/Http/Http.Features/src/PublicAPI.Shipped.txt b/src/Http/Http.Features/src/PublicAPI.Shipped.txt index 6c0b614457a9..18866d4bcb71 100644 --- a/src/Http/Http.Features/src/PublicAPI.Shipped.txt +++ b/src/Http/Http.Features/src/PublicAPI.Shipped.txt @@ -26,7 +26,7 @@ Microsoft.AspNetCore.Http.Features.FeatureCollection.FeatureCollection(Microsoft Microsoft.AspNetCore.Http.Features.FeatureCollection.Get() -> TFeature? Microsoft.AspNetCore.Http.Features.FeatureCollection.GetEnumerator() -> System.Collections.Generic.IEnumerator>! Microsoft.AspNetCore.Http.Features.FeatureCollection.IsReadOnly.get -> bool -Microsoft.AspNetCore.Http.Features.FeatureCollection.Set(TFeature instance) -> void +Microsoft.AspNetCore.Http.Features.FeatureCollection.Set(TFeature? instance) -> void Microsoft.AspNetCore.Http.Features.FeatureCollection.this[System.Type! key].get -> object? Microsoft.AspNetCore.Http.Features.FeatureCollection.this[System.Type! key].set -> void Microsoft.AspNetCore.Http.Features.FeatureReference @@ -46,10 +46,10 @@ Microsoft.AspNetCore.Http.Features.HttpsCompressionMode.Compress = 2 -> Microsof Microsoft.AspNetCore.Http.Features.HttpsCompressionMode.Default = 0 -> Microsoft.AspNetCore.Http.Features.HttpsCompressionMode Microsoft.AspNetCore.Http.Features.HttpsCompressionMode.DoNotCompress = 1 -> Microsoft.AspNetCore.Http.Features.HttpsCompressionMode Microsoft.AspNetCore.Http.Features.IFeatureCollection -Microsoft.AspNetCore.Http.Features.IFeatureCollection.Get() -> TFeature +Microsoft.AspNetCore.Http.Features.IFeatureCollection.Get() -> TFeature? Microsoft.AspNetCore.Http.Features.IFeatureCollection.IsReadOnly.get -> bool Microsoft.AspNetCore.Http.Features.IFeatureCollection.Revision.get -> int -Microsoft.AspNetCore.Http.Features.IFeatureCollection.Set(TFeature instance) -> void +Microsoft.AspNetCore.Http.Features.IFeatureCollection.Set(TFeature? instance) -> void Microsoft.AspNetCore.Http.Features.IFeatureCollection.this[System.Type! key].get -> object? Microsoft.AspNetCore.Http.Features.IFeatureCollection.this[System.Type! key].set -> void Microsoft.AspNetCore.Http.Features.IFormFeature diff --git a/src/Http/Http/src/Internal/DefaultHttpResponse.cs b/src/Http/Http/src/Internal/DefaultHttpResponse.cs index 6caa939444ee..554616bd7536 100644 --- a/src/Http/Http/src/Internal/DefaultHttpResponse.cs +++ b/src/Http/Http/src/Internal/DefaultHttpResponse.cs @@ -69,7 +69,7 @@ public override Stream Body get { return HttpResponseBodyFeature.Stream; } set { - var otherFeature = _features.Collection.Get(); + var otherFeature = _features.Collection.Get()!; if (otherFeature is StreamResponseBodyFeature streamFeature && streamFeature.PriorFeature != null diff --git a/src/Http/Http/src/Internal/ResponseCookies.cs b/src/Http/Http/src/Internal/ResponseCookies.cs index e6e582bfda0b..4a34b055d604 100644 --- a/src/Http/Http/src/Internal/ResponseCookies.cs +++ b/src/Http/Http/src/Internal/ResponseCookies.cs @@ -28,7 +28,7 @@ internal class ResponseCookies : IResponseCookies internal ResponseCookies(IFeatureCollection features) { _features = features; - Headers = _features.Get().Headers; + Headers = _features.Get()!.Headers; } private IHeaderDictionary Headers { get; set; } diff --git a/src/Middleware/ResponseCompression/src/ResponseCompressionMiddleware.cs b/src/Middleware/ResponseCompression/src/ResponseCompressionMiddleware.cs index 0d0715db213a..e37b39dde7d2 100644 --- a/src/Middleware/ResponseCompression/src/ResponseCompressionMiddleware.cs +++ b/src/Middleware/ResponseCompression/src/ResponseCompressionMiddleware.cs @@ -2,6 +2,7 @@ // Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. using System; +using System.Diagnostics; using System.Threading.Tasks; using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Http.Features; @@ -54,6 +55,8 @@ public async Task Invoke(HttpContext context) var originalBodyFeature = context.Features.Get(); var originalCompressionFeature = context.Features.Get(); + Debug.Assert(originalBodyFeature != null); + var compressionBody = new ResponseCompressionBody(context, _provider, originalBodyFeature); context.Features.Set(compressionBody); context.Features.Set(compressionBody); diff --git a/src/Middleware/Rewrite/src/UrlActions/CustomResponseAction.cs b/src/Middleware/Rewrite/src/UrlActions/CustomResponseAction.cs index ecd63fd32d6c..23fdfba6c105 100644 --- a/src/Middleware/Rewrite/src/UrlActions/CustomResponseAction.cs +++ b/src/Middleware/Rewrite/src/UrlActions/CustomResponseAction.cs @@ -26,7 +26,7 @@ public override void ApplyAction(RewriteContext context, BackReferenceCollection if (!string.IsNullOrEmpty(StatusReason)) { - context.HttpContext.Features.Get().ReasonPhrase = StatusReason; + context.HttpContext.Features.Get()!.ReasonPhrase = StatusReason; } if (!string.IsNullOrEmpty(StatusDescription)) diff --git a/src/Servers/Kestrel/Core/src/Internal/Http/HttpProtocol.Generated.cs b/src/Servers/Kestrel/Core/src/Internal/Http/HttpProtocol.Generated.cs index 28c832d27da8..f6420cc0c955 100644 --- a/src/Servers/Kestrel/Core/src/Internal/Http/HttpProtocol.Generated.cs +++ b/src/Servers/Kestrel/Core/src/Internal/Http/HttpProtocol.Generated.cs @@ -388,12 +388,12 @@ private void ExtraFeatureSet(Type key, object? value) } else { - ExtraFeatureSet(key, value!); // TODO: What happens if you set an extra feature with a null value? + ExtraFeatureSet(key, value); } } } - TFeature IFeatureCollection.Get() + TFeature? IFeatureCollection.Get() where TFeature : default { TFeature? feature = default; if (typeof(TFeature) == typeof(IHttpRequestFeature)) @@ -518,10 +518,10 @@ TFeature IFeatureCollection.Get() feature = ConnectionFeatures.Get(); } - return feature!; + return feature; } - void IFeatureCollection.Set(TFeature feature) + void IFeatureCollection.Set(TFeature? feature) where TFeature : default { _featureRevision++; if (typeof(TFeature) == typeof(IHttpRequestFeature)) @@ -638,7 +638,7 @@ void IFeatureCollection.Set(TFeature feature) } else { - ExtraFeatureSet(typeof(TFeature), feature!); // TODO: What happens if you set an extra feature with a null value? + ExtraFeatureSet(typeof(TFeature), feature); } } diff --git a/src/Servers/Kestrel/Core/src/Internal/Http3/Http3Connection.cs b/src/Servers/Kestrel/Core/src/Internal/Http3/Http3Connection.cs index fb8a6d9adef3..f640c274c14a 100644 --- a/src/Servers/Kestrel/Core/src/Internal/Http3/Http3Connection.cs +++ b/src/Servers/Kestrel/Core/src/Internal/Http3/Http3Connection.cs @@ -210,6 +210,7 @@ internal async Task InnerProcessRequestsAsync(IHttpApplication(); Debug.Assert(quicStreamFeature != null); + Debug.Assert(streamIdFeature != null); var httpConnectionContext = new Http3StreamContext( streamContext.ConnectionId, diff --git a/src/Servers/Kestrel/Core/src/Internal/Http3/Http3Stream.cs b/src/Servers/Kestrel/Core/src/Internal/Http3/Http3Stream.cs index 51f570acaa7a..46b3d6d9a942 100644 --- a/src/Servers/Kestrel/Core/src/Internal/Http3/Http3Stream.cs +++ b/src/Servers/Kestrel/Core/src/Internal/Http3/Http3Stream.cs @@ -62,8 +62,8 @@ public Http3Stream(Http3Connection http3Connection, Http3StreamContext context) _http3Connection = http3Connection; _context = context; - _errorCodeFeature = _context.ConnectionFeatures.Get(); - _streamIdFeature = _context.ConnectionFeatures.Get(); + _errorCodeFeature = _context.ConnectionFeatures.Get()!; + _streamIdFeature = _context.ConnectionFeatures.Get()!; _frameWriter = new Http3FrameWriter( context.Transport.Output, diff --git a/src/Servers/Kestrel/Transport.Quic/src/Internal/QuicConnectionContext.cs b/src/Servers/Kestrel/Transport.Quic/src/Internal/QuicConnectionContext.cs index 21da83c29c90..07b23d6c0969 100644 --- a/src/Servers/Kestrel/Transport.Quic/src/Internal/QuicConnectionContext.cs +++ b/src/Servers/Kestrel/Transport.Quic/src/Internal/QuicConnectionContext.cs @@ -96,7 +96,7 @@ public override ValueTask ConnectAsync(IFeatureCollection? fe if (features != null) { - var streamDirectionFeature = features.Get(); + var streamDirectionFeature = features.Get()!; if (streamDirectionFeature.CanRead) { quicStream = _connection.OpenBidirectionalStream(); diff --git a/src/Servers/Kestrel/shared/TransportConnection.Generated.cs b/src/Servers/Kestrel/shared/TransportConnection.Generated.cs index a6a1afb0d0e9..b35954bb6fa2 100644 --- a/src/Servers/Kestrel/shared/TransportConnection.Generated.cs +++ b/src/Servers/Kestrel/shared/TransportConnection.Generated.cs @@ -157,12 +157,12 @@ private void ExtraFeatureSet(Type key, object? value) } else { - ExtraFeatureSet(key, value!); // TODO: What happens if you set an extra feature with a null value? + ExtraFeatureSet(key, value); } } } - TFeature IFeatureCollection.Get() + TFeature? IFeatureCollection.Get() where TFeature : default { TFeature? feature = default; if (typeof(TFeature) == typeof(IConnectionIdFeature)) @@ -190,10 +190,10 @@ TFeature IFeatureCollection.Get() feature = (TFeature?)(ExtraFeatureGet(typeof(TFeature))); } - return feature!; + return feature; } - void IFeatureCollection.Set(TFeature feature) + void IFeatureCollection.Set(TFeature? feature) where TFeature : default { _featureRevision++; if (typeof(TFeature) == typeof(IConnectionIdFeature)) @@ -218,7 +218,7 @@ void IFeatureCollection.Set(TFeature feature) } else { - ExtraFeatureSet(typeof(TFeature), feature!); // TODO: What happens if you set an extra feature with a null value? + ExtraFeatureSet(typeof(TFeature), feature); } } diff --git a/src/Servers/Kestrel/shared/TransportMultiplexedConnection.Generated.cs b/src/Servers/Kestrel/shared/TransportMultiplexedConnection.Generated.cs index b2d399ed20bd..cdfc0bff16c3 100644 --- a/src/Servers/Kestrel/shared/TransportMultiplexedConnection.Generated.cs +++ b/src/Servers/Kestrel/shared/TransportMultiplexedConnection.Generated.cs @@ -157,12 +157,12 @@ private void ExtraFeatureSet(Type key, object? value) } else { - ExtraFeatureSet(key, value!); // TODO: What happens if you set an extra feature with a null value? + ExtraFeatureSet(key, value); } } } - TFeature IFeatureCollection.Get() + TFeature? IFeatureCollection.Get() where TFeature : default { TFeature? feature = default; if (typeof(TFeature) == typeof(IConnectionIdFeature)) @@ -190,10 +190,10 @@ TFeature IFeatureCollection.Get() feature = (TFeature?)(ExtraFeatureGet(typeof(TFeature))); } - return feature!; + return feature; } - void IFeatureCollection.Set(TFeature feature) + void IFeatureCollection.Set(TFeature? feature) where TFeature : default { _featureRevision++; if (typeof(TFeature) == typeof(IConnectionIdFeature)) @@ -218,7 +218,7 @@ void IFeatureCollection.Set(TFeature feature) } else { - ExtraFeatureSet(typeof(TFeature), feature!); // TODO: What happens if you set an extra feature with a null value? + ExtraFeatureSet(typeof(TFeature), feature); } } diff --git a/src/Servers/Kestrel/tools/CodeGenerator/FeatureCollectionGenerator.cs b/src/Servers/Kestrel/tools/CodeGenerator/FeatureCollectionGenerator.cs index 821058936f9d..3f75cd4e21e6 100644 --- a/src/Servers/Kestrel/tools/CodeGenerator/FeatureCollectionGenerator.cs +++ b/src/Servers/Kestrel/tools/CodeGenerator/FeatureCollectionGenerator.cs @@ -142,7 +142,7 @@ private void ExtraFeatureSet(Type key, object? value) }} }} - TFeature IFeatureCollection.Get() + TFeature? IFeatureCollection.Get() where TFeature : default {{ TFeature? feature = default;{Each(features, feature => $@" {(feature.Index != 0 ? "else " : "")}if (typeof(TFeature) == typeof({feature.Name})) @@ -159,10 +159,10 @@ TFeature IFeatureCollection.Get() feature = {fallbackFeatures}.Get(); }}")} - return feature!; + return feature; }} - void IFeatureCollection.Set(TFeature feature) + void IFeatureCollection.Set(TFeature? feature) where TFeature : default {{ _featureRevision++;{Each(features, feature => $@" {(feature.Index != 0 ? "else " : "")}if (typeof(TFeature) == typeof({feature.Name})) diff --git a/src/SignalR/common/Http.Connections/src/Internal/Transports/ServerSentEventsServerTransport.cs b/src/SignalR/common/Http.Connections/src/Internal/Transports/ServerSentEventsServerTransport.cs index b9bc12dbae5f..ffda642fa44a 100644 --- a/src/SignalR/common/Http.Connections/src/Internal/Transports/ServerSentEventsServerTransport.cs +++ b/src/SignalR/common/Http.Connections/src/Internal/Transports/ServerSentEventsServerTransport.cs @@ -39,7 +39,7 @@ public async Task ProcessRequestAsync(HttpContext context, CancellationToken tok context.Response.Headers[HeaderNames.Pragma] = "no-cache"; // Make sure we disable all response buffering for SSE - var bufferingFeature = context.Features.Get(); + var bufferingFeature = context.Features.Get()!; bufferingFeature.DisableBuffering(); context.Response.Headers[HeaderNames.ContentEncoding] = "identity";