19

My old code looks like this:

public static class DbHelper {
    // One conection per request
    public static Database CurrentDb() {
        if (HttpContext.Current.Items["CurrentDb"] == null) {
            var retval = new DatabaseWithMVCMiniProfiler("MainConnectionString");
            HttpContext.Current.Items["CurrentDb"] = retval;
            return retval;
        }
        return (Database)HttpContext.Current.Items["CurrentDb"];
    }
}

Since we don't have HttpContext anymore easily accesible in core, how can I achieve the same thing?

I need to access CurrentDb() easily from everywhere

Would like to use something like MemoryCache, but with Request lifetime. DI it's not an option for this project

Uwe Keim
  • 39,551
  • 56
  • 175
  • 291
Eduardo Molteni
  • 38,786
  • 23
  • 141
  • 206

2 Answers2

25

There are at least 3 options to store an object per-request in ASP.NET Core:

1. Dependency Injection

You could totally re-design that old code: use the built-in DI and register a Database instance as scoped (per web-request) with the following factory method:

public void ConfigureServices(IServiceCollection services)
{
    services.AddScoped<Database>((provider) =>
    {
        return new DatabaseWithMVCMiniProfiler("MainConnectionString");
    });
}

Introduction to Dependency Injection in ASP.NET Core

.NET Core Dependency Injection Lifetimes Explained

2. HttpContext.Items

This collection is available from the start of an HttpRequest and is discarded at the end of each request.

Working with HttpContext.Items

3. AsyncLocal<T>

Store a value per a current async context (a kind of [ThreadStatic] with async support). This is how HttpContext is actually stored: HttpContextAccessor.

What's the effect of AsyncLocal<T> in non async/await code?

ThreadStatic in asynchronous ASP.NET Web API

Pang
  • 9,564
  • 146
  • 81
  • 122
Ilya Chumakov
  • 23,161
  • 9
  • 86
  • 114
  • Yes, I've explored using DI, but it adds too many boilerplate code, not to mention having to rewrite too much already existing code. DI it's a no go for this project – Eduardo Molteni Jun 03 '17 at 21:05
  • @EduardoMolteni sometimes it's better to stay on full .NET =) Look at this "pure evil" solution to bring back `HttpContext.Current`: https://stackoverflow.com/a/40028901/5112433 – Ilya Chumakov Jun 04 '17 at 08:57
  • Yes, I'm also trying to avoid these kind of monsters, would like to use something like MemoryCache, but with Request lifetime – Eduardo Molteni Jun 05 '17 at 13:33
  • 1
    @EduardoMolteni have you considered `HttpContext.Items`? This collection is available from the start of an HttpRequest and is discarded at the end of each request. You just need to pass it as parameter to your non-controller classes. https://learn.microsoft.com/en-us/aspnet/core/fundamentals/app-state#working-with-httpcontextitems – Ilya Chumakov Jun 07 '17 at 19:19
  • I'm trying to avoid the "You just need to pass it as parameter" because will need to add this parameter everywhere – Eduardo Molteni Jun 07 '17 at 19:31
  • But didn't know I could access ´HttpContext.Items´ so easily. Thanks for that, new place to start exploring. – Eduardo Molteni Jun 07 '17 at 19:33
  • @EduardoMolteni one more option is `AsyncLocal`, I added some details to the answer. – Ilya Chumakov Jun 07 '17 at 20:39
  • 1
    `AsyncLocal` is a bit nicer than `HttpContext` because the code using `AsyncLocal` is more general purpose and doesn't have a dependency on knowing it is in the context of an HTTP call. – Brandon Jun 07 '17 at 20:48
0

Will not the database or connection string would be same across the requests?

If so then you could do it by a static variable and middleware.

The middleware would check and set the info on each request start and static variable would store the value then your method could read it from the static variable.

Other simpler approach would be to inject/pass the IHttpContextAccessor as parameter. With this you could do with minimal changes but you have the pass the IHttpContextAccessor service from each calling method.

Satyajit
  • 2,150
  • 2
  • 15
  • 28