19

What is the differences between these two Properties?

I can use HttpContext.Items instead of HttpContext.Features to share data between middlewares. The only difference I see is that I tell Items for a key and it gives me an object and I have to cast it. This casting can be done in Features automatically.

Is there something else behind them?

Mohammad Barbast
  • 1,753
  • 3
  • 17
  • 28

2 Answers2

23

The biggest difference is that the HttpContext.Items is designed to store Key-Value-Pair, while the HttpContext.Features is designed to store Type-Instance-Pair.

To be more clear, HttpContext.Items is designed to share items within the scope of current request, while the HttpContext.Features, which is an instance of IFeatureCollection, is by no means to be used like that .

The IFeatureCollection interface represents a collection of HTTP features, such as:

  1. IAuthenticationFeature which stores original PathBase and original Path.
  2. ISessionFeature which stores current Session.
  3. IHttpConnectionFeature which stores the underlying connection.
  4. and so on.

To help store and retrieve a Type-Instance-Pair, the interface has three important methods:

public interface IFeatureCollection : IEnumerable<KeyValuePair<Type, object>>{
    // ...
    object this[Type key] { get; set; }
    TFeature Get<TFeature>();
    void Set<TFeature>(TFeature instance);
}

and the implementation (FeatureCollection) will simply cast the value into required type:

public class FeatureCollection : IFeatureCollection
{
    // ... get the required type of feature
    public TFeature Get<TFeature>()
    {
        return (TFeature)this[typeof(TFeature)];    // note: cast here!
    }

    public void Set<TFeature>(TFeature instance)
    {
        this[typeof(TFeature)] = instance;          // note!
    }
}

This is by design. Because there's no need to store two IHttpConnectionFeature instances or two ISession instances.

While you can store some Type-Value pairs with FeatureCollection, you'd better not . As you see, the Set<TFeature>(TFeature instance) will simply replace the old one if the some type already exists in the collection; it also means there will be a bug if you have two of the same type.

BanksySan
  • 27,362
  • 33
  • 117
  • 216
itminus
  • 23,772
  • 2
  • 53
  • 88
  • 1
    You said `HttpContext.Items` is short-lived per request, So what is the life-time for a `HttpContext.Features`s member? – Mohammad Barbast Aug 26 '18 at 06:08
  • 1
    @MohammadBarbast Well , the exact lifetime is related to the implementation of the `IServer` interface . Actually , the `Features` Collection itself and some features like `ServerAddressFeature` are created by the server implemenation even before the `HttpContext`. See [Kestrel](https://github.com/aspnet/KestrelHttpServer/blob/release/2.2/src/Kestrel.Core/KestrelServer.cs#L50) here . – itminus Aug 27 '18 at 05:32
8

HttpContext.Items is designed to share short-lived per-request data, as you mentioned.

HttpContext.Features is designed to share various HTTP features that allow middleware to create or modify the application's hosting pipeline. It's already filled with several features from .NET, such as IHttpSendFileFeature.

You should use HttpContext.Items to store data, and HttpContext.Features to add any new HTTP features that another middleware class might need.

Will Ray
  • 10,621
  • 3
  • 46
  • 61
  • 1
    So what is the life-time for `HttpContext.Features`? – Mohammad Barbast Aug 24 '18 at 08:58
  • 1
    @MohammadBarbast it's per-request, same as `HttpContext.Items`. There's a bit more information on this topic in [this GitHub question](https://github.com/aspnet/Mvc/issues/7833). – Will Ray Aug 26 '18 at 22:20