Skip to content

Commit e795ec7

Browse files
Fix nullref when getting struct from feature collection and it isn't present (#47795)
1 parent 6349fc5 commit e795ec7

File tree

2 files changed

+70
-0
lines changed

2 files changed

+70
-0
lines changed

src/Extensions/Features/src/FeatureCollection.cs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,17 @@ public IEnumerator<KeyValuePair<Type, object>> GetEnumerator()
117117
/// <inheritdoc />
118118
public TFeature? Get<TFeature>()
119119
{
120+
if (typeof(TFeature).IsValueType)
121+
{
122+
var feature = this[typeof(TFeature)];
123+
if (feature is null && Nullable.GetUnderlyingType(typeof(TFeature)) is null)
124+
{
125+
throw new InvalidOperationException(
126+
$"{typeof(TFeature).FullName} does not exist in the feature collection " +
127+
$"and because it is a struct the method can't return null. Use 'featureCollection[typeof({typeof(TFeature).FullName})] is not null' to check if the feature exists.");
128+
}
129+
return (TFeature?)feature;
130+
}
120131
return (TFeature?)this[typeof(TFeature)];
121132
}
122133

src/Extensions/Features/test/FeatureCollectionTests.cs

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
// Licensed to the .NET Foundation under one or more agreements.
22
// The .NET Foundation licenses this file to you under the MIT license.
33

4+
using System;
45
using Xunit;
56

67
namespace Microsoft.AspNetCore.Http.Features;
@@ -44,4 +45,62 @@ public void SetNullValueRemoves()
4445
var thing2 = interfaces[typeof(IThing)];
4546
Assert.Null(thing2);
4647
}
48+
49+
[Fact]
50+
public void GetMissingStructFeatureThrows()
51+
{
52+
var interfaces = new FeatureCollection();
53+
54+
// Regression test: Used to throw NullReferenceException because it tried to unbox a null object to a struct
55+
var ex = Assert.Throws<InvalidOperationException>(() => interfaces.Get<int>());
56+
Assert.Equal("System.Int32 does not exist in the feature collection and because it is a struct the method can't return null. Use 'featureCollection[typeof(System.Int32)] is not null' to check if the feature exists.", ex.Message);
57+
}
58+
59+
[Fact]
60+
public void GetMissingFeatureReturnsNull()
61+
{
62+
var interfaces = new FeatureCollection();
63+
64+
Assert.Null(interfaces.Get<Thing>());
65+
}
66+
67+
[Fact]
68+
public void GetStructFeature()
69+
{
70+
var interfaces = new FeatureCollection();
71+
var value = 20;
72+
interfaces.Set(value);
73+
74+
Assert.Equal(value, interfaces.Get<int>());
75+
}
76+
77+
[Fact]
78+
public void GetNullableStructFeatureWhenSetWithNonNullableStruct()
79+
{
80+
var interfaces = new FeatureCollection();
81+
var value = 20;
82+
interfaces.Set(value);
83+
84+
Assert.Null(interfaces.Get<int?>());
85+
}
86+
87+
[Fact]
88+
public void GetNullableStructFeatureWhenSetWithNullableStruct()
89+
{
90+
var interfaces = new FeatureCollection();
91+
var value = 20;
92+
interfaces.Set<int?>(value);
93+
94+
Assert.Equal(value, interfaces.Get<int?>());
95+
}
96+
97+
[Fact]
98+
public void GetFeature()
99+
{
100+
var interfaces = new FeatureCollection();
101+
var thing = new Thing();
102+
interfaces.Set(thing);
103+
104+
Assert.Equal(thing, interfaces.Get<Thing>());
105+
}
47106
}

0 commit comments

Comments
 (0)