dotnet / dotnet/aspnetcore

Throw a better exception when the HttpContext is accessed concurrently and will result in a null ref

Open
#42,040 8 comments 12 reactions 0 assignees View on GitHub
area-networking
Dominant language
C#
Stars
38.4k
Forks
10.9k
Avg merge
2d 6h
Merged PRs (30d)
290

Description

We've had issues over the the years about random null refs that occur when accessing the HttpContext:

- https://github.com/dotnet/aspnetcore/issues/17085
- https://github.com/dotnet/aspnetcore/issues/25454
- https://github.com/dotnet/aspnetcore/issues/3219
- https://github.com/dotnet/aspnetcore/issues/2799
- https://github.com/dotnet/aspnetcore/issues/2806
- https://github.com/dotnet/aspnetcore/issues/41924
- https://github.com/microsoft/ApplicationInsights-dotnet/issues/1524
- https://github.com/dotnet/aspnetcore/issues/42100
- https://github.com/dotnet/aspnetcore/issues/43155
- https://github.com/dotnet/aspnetcore/issues/43339
- https://github.com/dotnet/aspnetcore/issues/47573

There are examples of concurrent access to the HttpContext. This usually happens because the [internal feature references cache](https://github.com/dotnet/aspnetcore/blob/b806844373440a538192181652d466b621a14494/src/Extensions/Features/src/FeatureReferences.cs#L117) can be cleared after a new feature has been set. This happens on reading some properties (because it's lazily evaluated).

Instead, we should handle this case by throwing an exception saying that there was concurrent modification.

Here's a simple example that illustrates why there's a null ref:

```C#

var references = new Reference();

var myfeature = references.Fetch(ref references.Cache.NameFeature, () => new MyNameRequestFeature { Name = "New Feature" });

// This blows up with a null ref
var name = myfeature.Name;

Console.WriteLine(name);

struct Reference
{
public T? Cache;

public R Fetch(ref R? item, Func factory)
{
item = factory();

// Clear the cache
Cache = default;

return item;
}
}

struct ReferenceHolder
{
public MyNameRequestFeature? NameFeature;
}

class MyNameRequestFeature
{
public string Name { get; init; } = default!;
}
```

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.