Skip to content

Commit d4dbba8

Browse files
authored
Allow nullable with IFeatureCollection generic Get/Set (#28809)
1 parent be02e49 commit d4dbba8

File tree

19 files changed

+34
-30
lines changed

19 files changed

+34
-30
lines changed

src/Hosting/TestHost/src/ClientHandler.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -184,7 +184,7 @@ protected override async Task<HttpResponseMessage> SendAsync(
184184
// Copy trailers to the response message when the response stream is complete
185185
contextBuilder.RegisterResponseReadCompleteCallback(context =>
186186
{
187-
var responseTrailersFeature = context.Features.Get<IHttpResponseTrailersFeature>();
187+
var responseTrailersFeature = context.Features.Get<IHttpResponseTrailersFeature>()!;
188188

189189
foreach (var trailer in responseTrailersFeature.Trailers)
190190
{
@@ -196,7 +196,7 @@ protected override async Task<HttpResponseMessage> SendAsync(
196196
var httpContext = await contextBuilder.SendAsync(cancellationToken);
197197

198198
response.StatusCode = (HttpStatusCode)httpContext.Response.StatusCode;
199-
response.ReasonPhrase = httpContext.Features.Get<IHttpResponseFeature>().ReasonPhrase;
199+
response.ReasonPhrase = httpContext.Features.Get<IHttpResponseFeature>()!.ReasonPhrase;
200200
response.RequestMessage = request;
201201
response.Version = request.Version;
202202

src/Hosting/TestHost/src/HttpContextBuilder.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -225,7 +225,7 @@ internal async Task ReturnResponseMessageAsync()
225225
{
226226
newFeatures[pair.Key] = pair.Value;
227227
}
228-
var serverResponseFeature = _httpContext.Features.Get<IHttpResponseFeature>();
228+
var serverResponseFeature = _httpContext.Features.Get<IHttpResponseFeature>()!;
229229
// The client gets a deep copy of this so they can interact with the body stream independently of the server.
230230
var clientResponseFeature = new HttpResponseFeature()
231231
{

src/Http/Http.Extensions/src/ResponseExtensions.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ public static void Clear(this HttpResponse response)
1616
throw new InvalidOperationException("The response cannot be cleared, it has already started sending.");
1717
}
1818
response.StatusCode = 200;
19-
response.HttpContext.Features.Get<IHttpResponseFeature>().ReasonPhrase = null;
19+
response.HttpContext.Features.Get<IHttpResponseFeature>()!.ReasonPhrase = null;
2020
response.Headers.Clear();
2121
if (response.Body.CanSeek)
2222
{

src/Http/Http.Extensions/src/SendFileResponseExtensions.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -143,7 +143,7 @@ private static async Task SendFileAsyncCore(HttpResponse response, string fileNa
143143
{
144144
var useRequestAborted = !cancellationToken.CanBeCanceled;
145145
var localCancel = useRequestAborted ? response.HttpContext.RequestAborted : cancellationToken;
146-
var sendFile = response.HttpContext.Features.Get<IHttpResponseBodyFeature>();
146+
var sendFile = response.HttpContext.Features.Get<IHttpResponseBodyFeature>()!;
147147

148148
try
149149
{

src/Http/Http.Features/src/FeatureCollection.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -98,7 +98,7 @@ public IEnumerator<KeyValuePair<Type, object>> GetEnumerator()
9898
return (TFeature?)this[typeof(TFeature)];
9999
}
100100

101-
public void Set<TFeature>(TFeature instance)
101+
public void Set<TFeature>(TFeature? instance)
102102
{
103103
this[typeof(TFeature)] = instance;
104104
}

src/Http/Http.Features/src/IFeatureCollection.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,13 +33,13 @@ public interface IFeatureCollection : IEnumerable<KeyValuePair<Type, object>>
3333
/// </summary>
3434
/// <typeparam name="TFeature">The feature key.</typeparam>
3535
/// <returns>The requested feature, or null if it is not present.</returns>
36-
TFeature Get<TFeature>();
36+
TFeature? Get<TFeature>();
3737

3838
/// <summary>
3939
/// Sets the given feature in the collection.
4040
/// </summary>
4141
/// <typeparam name="TFeature">The feature key.</typeparam>
4242
/// <param name="instance">The feature value.</param>
43-
void Set<TFeature>(TFeature instance);
43+
void Set<TFeature>(TFeature? instance);
4444
}
4545
}

src/Http/Http.Features/src/PublicAPI.Shipped.txt

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ Microsoft.AspNetCore.Http.Features.FeatureCollection.FeatureCollection(Microsoft
2626
Microsoft.AspNetCore.Http.Features.FeatureCollection.Get<TFeature>() -> TFeature?
2727
Microsoft.AspNetCore.Http.Features.FeatureCollection.GetEnumerator() -> System.Collections.Generic.IEnumerator<System.Collections.Generic.KeyValuePair<System.Type!, object!>>!
2828
Microsoft.AspNetCore.Http.Features.FeatureCollection.IsReadOnly.get -> bool
29-
Microsoft.AspNetCore.Http.Features.FeatureCollection.Set<TFeature>(TFeature instance) -> void
29+
Microsoft.AspNetCore.Http.Features.FeatureCollection.Set<TFeature>(TFeature? instance) -> void
3030
Microsoft.AspNetCore.Http.Features.FeatureCollection.this[System.Type! key].get -> object?
3131
Microsoft.AspNetCore.Http.Features.FeatureCollection.this[System.Type! key].set -> void
3232
Microsoft.AspNetCore.Http.Features.FeatureReference<T>
@@ -46,10 +46,10 @@ Microsoft.AspNetCore.Http.Features.HttpsCompressionMode.Compress = 2 -> Microsof
4646
Microsoft.AspNetCore.Http.Features.HttpsCompressionMode.Default = 0 -> Microsoft.AspNetCore.Http.Features.HttpsCompressionMode
4747
Microsoft.AspNetCore.Http.Features.HttpsCompressionMode.DoNotCompress = 1 -> Microsoft.AspNetCore.Http.Features.HttpsCompressionMode
4848
Microsoft.AspNetCore.Http.Features.IFeatureCollection
49-
Microsoft.AspNetCore.Http.Features.IFeatureCollection.Get<TFeature>() -> TFeature
49+
Microsoft.AspNetCore.Http.Features.IFeatureCollection.Get<TFeature>() -> TFeature?
5050
Microsoft.AspNetCore.Http.Features.IFeatureCollection.IsReadOnly.get -> bool
5151
Microsoft.AspNetCore.Http.Features.IFeatureCollection.Revision.get -> int
52-
Microsoft.AspNetCore.Http.Features.IFeatureCollection.Set<TFeature>(TFeature instance) -> void
52+
Microsoft.AspNetCore.Http.Features.IFeatureCollection.Set<TFeature>(TFeature? instance) -> void
5353
Microsoft.AspNetCore.Http.Features.IFeatureCollection.this[System.Type! key].get -> object?
5454
Microsoft.AspNetCore.Http.Features.IFeatureCollection.this[System.Type! key].set -> void
5555
Microsoft.AspNetCore.Http.Features.IFormFeature

src/Http/Http/src/Internal/DefaultHttpResponse.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ public override Stream Body
6969
get { return HttpResponseBodyFeature.Stream; }
7070
set
7171
{
72-
var otherFeature = _features.Collection.Get<IHttpResponseBodyFeature>();
72+
var otherFeature = _features.Collection.Get<IHttpResponseBodyFeature>()!;
7373

7474
if (otherFeature is StreamResponseBodyFeature streamFeature
7575
&& streamFeature.PriorFeature != null

src/Http/Http/src/Internal/ResponseCookies.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ internal class ResponseCookies : IResponseCookies
2828
internal ResponseCookies(IFeatureCollection features)
2929
{
3030
_features = features;
31-
Headers = _features.Get<IHttpResponseFeature>().Headers;
31+
Headers = _features.Get<IHttpResponseFeature>()!.Headers;
3232
}
3333

3434
private IHeaderDictionary Headers { get; set; }

src/Middleware/ResponseCompression/src/ResponseCompressionMiddleware.cs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
33

44
using System;
5+
using System.Diagnostics;
56
using System.Threading.Tasks;
67
using Microsoft.AspNetCore.Http;
78
using Microsoft.AspNetCore.Http.Features;
@@ -54,6 +55,8 @@ public async Task Invoke(HttpContext context)
5455
var originalBodyFeature = context.Features.Get<IHttpResponseBodyFeature>();
5556
var originalCompressionFeature = context.Features.Get<IHttpsCompressionFeature>();
5657

58+
Debug.Assert(originalBodyFeature != null);
59+
5760
var compressionBody = new ResponseCompressionBody(context, _provider, originalBodyFeature);
5861
context.Features.Set<IHttpResponseBodyFeature>(compressionBody);
5962
context.Features.Set<IHttpsCompressionFeature>(compressionBody);

src/Middleware/Rewrite/src/UrlActions/CustomResponseAction.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ public override void ApplyAction(RewriteContext context, BackReferenceCollection
2626

2727
if (!string.IsNullOrEmpty(StatusReason))
2828
{
29-
context.HttpContext.Features.Get<IHttpResponseFeature>().ReasonPhrase = StatusReason;
29+
context.HttpContext.Features.Get<IHttpResponseFeature>()!.ReasonPhrase = StatusReason;
3030
}
3131

3232
if (!string.IsNullOrEmpty(StatusDescription))

src/Servers/Kestrel/Core/src/Internal/Http/HttpProtocol.Generated.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -393,7 +393,7 @@ private void ExtraFeatureSet(Type key, object? value)
393393
}
394394
}
395395

396-
TFeature IFeatureCollection.Get<TFeature>()
396+
TFeature? IFeatureCollection.Get<TFeature>() where TFeature : default
397397
{
398398
TFeature? feature = default;
399399
if (typeof(TFeature) == typeof(IHttpRequestFeature))
@@ -518,10 +518,10 @@ TFeature IFeatureCollection.Get<TFeature>()
518518
feature = ConnectionFeatures.Get<TFeature>();
519519
}
520520

521-
return feature!;
521+
return feature;
522522
}
523523

524-
void IFeatureCollection.Set<TFeature>(TFeature feature)
524+
void IFeatureCollection.Set<TFeature>(TFeature? feature) where TFeature : default
525525
{
526526
_featureRevision++;
527527
if (typeof(TFeature) == typeof(IHttpRequestFeature))

src/Servers/Kestrel/Core/src/Internal/Http3/Http3Connection.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -210,6 +210,7 @@ internal async Task InnerProcessRequestsAsync<TContext>(IHttpApplication<TContex
210210
var streamIdFeature = streamContext.Features.Get<IStreamIdFeature>();
211211

212212
Debug.Assert(quicStreamFeature != null);
213+
Debug.Assert(streamIdFeature != null);
213214

214215
var httpConnectionContext = new Http3StreamContext(
215216
streamContext.ConnectionId,

src/Servers/Kestrel/Core/src/Internal/Http3/Http3Stream.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -62,8 +62,8 @@ public Http3Stream(Http3Connection http3Connection, Http3StreamContext context)
6262
_http3Connection = http3Connection;
6363
_context = context;
6464

65-
_errorCodeFeature = _context.ConnectionFeatures.Get<IProtocolErrorCodeFeature>();
66-
_streamIdFeature = _context.ConnectionFeatures.Get<IStreamIdFeature>();
65+
_errorCodeFeature = _context.ConnectionFeatures.Get<IProtocolErrorCodeFeature>()!;
66+
_streamIdFeature = _context.ConnectionFeatures.Get<IStreamIdFeature>()!;
6767

6868
_frameWriter = new Http3FrameWriter(
6969
context.Transport.Output,

src/Servers/Kestrel/Transport.Quic/src/Internal/QuicConnectionContext.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -96,7 +96,7 @@ public override ValueTask<ConnectionContext> ConnectAsync(IFeatureCollection? fe
9696

9797
if (features != null)
9898
{
99-
var streamDirectionFeature = features.Get<IStreamDirectionFeature>();
99+
var streamDirectionFeature = features.Get<IStreamDirectionFeature>()!;
100100
if (streamDirectionFeature.CanRead)
101101
{
102102
quicStream = _connection.OpenBidirectionalStream();

src/Servers/Kestrel/shared/TransportConnection.Generated.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -162,7 +162,7 @@ private void ExtraFeatureSet(Type key, object? value)
162162
}
163163
}
164164

165-
TFeature IFeatureCollection.Get<TFeature>()
165+
TFeature? IFeatureCollection.Get<TFeature>() where TFeature : default
166166
{
167167
TFeature? feature = default;
168168
if (typeof(TFeature) == typeof(IConnectionIdFeature))
@@ -190,10 +190,10 @@ TFeature IFeatureCollection.Get<TFeature>()
190190
feature = (TFeature?)(ExtraFeatureGet(typeof(TFeature)));
191191
}
192192

193-
return feature!;
193+
return feature;
194194
}
195195

196-
void IFeatureCollection.Set<TFeature>(TFeature feature)
196+
void IFeatureCollection.Set<TFeature>(TFeature? feature) where TFeature : default
197197
{
198198
_featureRevision++;
199199
if (typeof(TFeature) == typeof(IConnectionIdFeature))

src/Servers/Kestrel/shared/TransportMultiplexedConnection.Generated.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -162,7 +162,7 @@ private void ExtraFeatureSet(Type key, object? value)
162162
}
163163
}
164164

165-
TFeature IFeatureCollection.Get<TFeature>()
165+
TFeature? IFeatureCollection.Get<TFeature>() where TFeature : default
166166
{
167167
TFeature? feature = default;
168168
if (typeof(TFeature) == typeof(IConnectionIdFeature))
@@ -190,10 +190,10 @@ TFeature IFeatureCollection.Get<TFeature>()
190190
feature = (TFeature?)(ExtraFeatureGet(typeof(TFeature)));
191191
}
192192

193-
return feature!;
193+
return feature;
194194
}
195195

196-
void IFeatureCollection.Set<TFeature>(TFeature feature)
196+
void IFeatureCollection.Set<TFeature>(TFeature? feature) where TFeature : default
197197
{
198198
_featureRevision++;
199199
if (typeof(TFeature) == typeof(IConnectionIdFeature))

src/Servers/Kestrel/tools/CodeGenerator/FeatureCollectionGenerator.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -142,7 +142,7 @@ private void ExtraFeatureSet(Type key, object? value)
142142
}}
143143
}}
144144

145-
TFeature IFeatureCollection.Get<TFeature>()
145+
TFeature? IFeatureCollection.Get<TFeature>() where TFeature : default
146146
{{
147147
TFeature? feature = default;{Each(features, feature => $@"
148148
{(feature.Index != 0 ? "else " : "")}if (typeof(TFeature) == typeof({feature.Name}))
@@ -159,10 +159,10 @@ TFeature IFeatureCollection.Get<TFeature>()
159159
feature = {fallbackFeatures}.Get<TFeature>();
160160
}}")}
161161

162-
return feature!;
162+
return feature;
163163
}}
164164

165-
void IFeatureCollection.Set<TFeature>(TFeature feature)
165+
void IFeatureCollection.Set<TFeature>(TFeature? feature) where TFeature : default
166166
{{
167167
_featureRevision++;{Each(features, feature => $@"
168168
{(feature.Index != 0 ? "else " : "")}if (typeof(TFeature) == typeof({feature.Name}))

src/SignalR/common/Http.Connections/src/Internal/Transports/ServerSentEventsServerTransport.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ public async Task ProcessRequestAsync(HttpContext context, CancellationToken tok
3939
context.Response.Headers[HeaderNames.Pragma] = "no-cache";
4040

4141
// Make sure we disable all response buffering for SSE
42-
var bufferingFeature = context.Features.Get<IHttpResponseBodyFeature>();
42+
var bufferingFeature = context.Features.Get<IHttpResponseBodyFeature>()!;
4343
bufferingFeature.DisableBuffering();
4444

4545
context.Response.Headers[HeaderNames.ContentEncoding] = "identity";

0 commit comments

Comments
 (0)