Better way of storing Per-Request data across middlewares in ASP.NET Core
Published: 2020-06-11 14:39:02

Hi developers who loves to work from home like me, for those who doesn't enjoy working from home, please skip this post. warning!

As you can guess from title, this post is about "How to not use HttpContext.Items"

To be honest, I'm the one who is still using `HttpContext.Items` because why not, right?--It's static! easy to write.

But no, collectively, it gives me tremendous amount of issues.

First, it's static! forget about mocking it.
Second, it's static! forget about testing it.
Third, it allows me to modify any variables I want!, brilliant !!, why is that a bad thing? because I can't control them. I can perform any add/delete/modify operations to any objects.

aight, anyways, I will show you how to use HttpContext.Items first, I know it's boring, just bear with me once. coz I don't have many things to make my blog longer. haha.. oops.

aight, let's go
`HttpContext.Current.Items` is a Key-Value-Pair, key and value both are type object.
You can access anywhere in your middlewares.

to store
```csharp
HttpContext.Current.Items["myobject"] = new MyObject();
```

to read
```csharp
var myObject = (IMyObject)HttpContext.Current.Items["myobject"];
```

to modify
```csharp
var myObject = (IMyObject)HttpContext.Current.Items["myobject"];
myObject.Hime = "Hime Hime~";
```

easy peasy!

now let's have a look into this code one bit

```csharp
app.Use(next => async context =>
{
    context.Items["DogSays"] = "Henlo hooman";
    await next(context);
    
    sexyMailer.Post((string)context.Items["DogSays"]);
});

app.Use(next => async context =>
{
    context.Items["DogSays"] = "Kwakkkkk!";
    await next(context);
});
```
now you can imagine if you work with 1500+ developers, how troublesome to maintain your calm, when you're assigned to find who changes our dog to says "Kwakkkkk!".

enough playing with time.

I found 2 elegant ways

[1.] use IHttpContextAccessor this interface is to read HttpContext through DI, simply you can register it by 
`services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();`
// this has to be registerd as singleton as per this announcement [ref.](https://github.com/aspnet/Hosting/issues/793)
or in ASP.NET Core 2.1 or above, you can use extension method `services.AddHttpContextAccessor();`

now in your class, you can access context via DI 
for example,
```csharp
public class HomeService{
    private readonly IHttpContextAccessor _httpContextAccessor;
    public HomeSerivce(IHttpContextAccessor httpContextAccessor){
        _httpContextAccessor = httpContextAccessor;
    }
    public DoWork(){
        var says = (string)_httpContextAccessor.HttpContext.Items["DogSays"]
        Log.Rock(says);
    }
}
```
now you can mock your IHttpContextAccessor quite easily! and live a happy life.


[2.] Create a Class to handle the modification of this shared objects, and register it as Scoped (created once per client request (connection) [ref.](https://docs.microsoft.com/en-us/aspnet/core/fundamentals/dependency-injection?view=aspnetcore-3.1#scoped)) then you can use it through DI, also it's a class! you can do a typed properties

so do speak, here is the code.
```csharp
public interface IVaultAccessor<T> {
    void AddToVault(T t);
    T GetFromVault(T t);
}

public class VaultAccessor<MyDog> : IVaultAccessor<MyDog> {
    private MyDog _myDog { get; set; }

    public void AddToVault(MyDog myDog) {
        _myDog = myDog;
    }

    public MyDog GetFromVault() {
        return _myDog;
    }
}

public class MyDog {
    public string WhatDoesTheDogSay { get; set; }
}

// register as Scoped
services.AddScoped<IVaultAccessor<MyDog>>(sp => new VaultAccessor<MyDog>());


// Usage in any random class
public class Tea: ITea {
    private readonly IVaultAccessor<MyDog> _myDogAccessor;
    public Tea(IVaultAccessor<MyDog> myDogAccessor) {
        _myDogAccessor = myDogAccessor;
    }

    public void RandomName() {
        var myDog = _myDogAccessor.GetFromVault();
        Log.Rock($"What a relief you are still my dog, {myDog.WhatDoesTheDogSay}");
    }
}
```
You can make IVaultAccessor fancy to the extent. And live a happy life.

Whoaaa! that's it for today.
How was it guys, hope you enjoy being chubbier.

See you around.