Jak správně přistupovat na HttpContext v ASP.NET Core

Miroslav Holec

Miroslav Holec

9. prosince. 2019

Potřebujete-li přistupovat v ASP.NET Core aplikacích na HttpContext, můžete tak snadno učinit v Controllerech, PageModelech nebo různých specifických místech (Filtry, Middlewares), kde je obvykle HttpContext součástí jiné třídy. Jak ale přistupovat na HttpContext mimo tato místa?

V controllerech musí být uklizeno

Vzhledem k tomu, že controllery nebo page modely nejsou dobrým kandidátem pro aplikační logiku, využití vlastnosti HttpContext na bázové třídě je prakticky nulové. Controllery jsou obvykle jen místem, odkud se provolávají různé services nebo fasády, které mají za úkol poskytnout data. Controllery pak rozhodují pouze o tom, zda tato data získají například JSON podobu nebo budou použitá v cshtml k vykreslení HTML stránky. Dále mohou controllery obsahovat jednoduchou logiku z pohledu aplikačního flow a v závislosti na výsledku práce připojených služeb se mohou rozhodnout, zda vrátí data, zobrazí stránku nebo například provedou redirect někam úplně jinam.

Nezřídka jsem viděl kód, ve kterém vývojář HttpContext předal z controlleru směrem do metody nějaké service. To není praktické jednak z hlediska testování, ale především to vytváří prostor k chybnému chování aplikace, zejména v multi thread kódu.

HttpContext

V ASP.NET Core není HttpContext registrován přímo v DI kontejneru. Je třeba pamatovat na to, že životní cyklus HttpContextu je managován mimo DI a samotný HttpContext není thread safe. Tyto dvě skutečnosti předurčují dva způsoby práce s HttpContextem. Prvním je přístup na context jako takový a druhým je práce s hodnotami contextu.

IHttpContextAccessor

Chcete-li získat aktuální HttpContext kdekoliv v aplikaci, je nutné registrovat do DI kontejneru singleton IHttpContextAccessor. Existuje na to i extension metoda:

public void ConfigureServices(IServiceCollection services)
{
     services.AddControllers();
     services.AddHttpContextAccessor();
}

Díky tomu si lze kamkoliv injectnout IHttpContextAccessor, který nám HttpContext zpřístupní.

public class EmailService : IEmailService
{
    private readonly IHttpContextAccessor _httpContextAccessor;

    public UserRepository(IHttpContextAccessor httpContextAccessor)
    {
        _httpContextAccessor = httpContextAccessor;
    }

    public void SendEmail(Email email)
    {
        var username = _httpContextAccessor.HttpContext.User.Identity.Name;
        // ...
    }
}

Je důležité poznamenat, že chceme-li pracovat s aktuálním stavem HttpContextu, nechceme za žádných okolností HttpContext někam odlévat. Zejména to platí v singletonech, kde by uložení hodnoty _httpContextAccessor.HttpContext znamenalo zmrazení aktuálního stavu (stal by součástí singleton instance). Občas to k tomu svádí a dokonce v některých místech to vyloženě nedává smysl. Příkladem budiž middleware konstruktor. Ten je proveden pouze při startu aplikace, kdy je HttpContext null.

Stav HttpContextu

Naopak jsou situace, kdy potřebujeme určitou hodnotu z HttpContextu a s tou pracujeme v našem kódu. Máme-li v kódu různá asynchronní volání nebo obecně vytváříme-li další vlákna, pak je nutné si uložit potřebné hodnoty do primitivní proměnné nebo struktury a pak s nimi pracovat. Platí to například při předávání hodnot do metod, které budou provádět zpracování na pozadí. Taková předná hodnota by neměla být nikdy HttpContext, ale výhradně hodnota z HttpContextu se kterou potřebujeme pracovat.

public class EmailController : Controller
{
    public ActionResult SendEmail(Email email)
    {
        var id = HttpContext.Request.Headers["TraceId"].ToString();
        Process(id);
        return View();
    }

    private async Task Process(string id)
    {
        // ...
    }
}

A to je pro tentokrát všechno. Chcete-li si tedy zpřístupnit HttpContext, stačí si registrovat do DI IHttpContextAccessor a poté jej správně používat. HttpContext je nicméně sám o sobě tajemný a ke způsobům jeho správného použití a best practices se ještě vrátím.

TOP Termíny školení

ASP.NET Core se dočkal již své třetí verze a nabízí řadu možností pro vývoj webových aplikací a služeb. I v roce 2020 mám vypsané termíny na nejrůznější témata od základů .NET Core přes vývoj REST API až po mikroslužby pomocí gRPC.

Termín Místo
🍀 Novinky a změny v ASP.NET Core 3.x leden 2020 Praha více
🍀 Vývoj REST API v .NET Core (třídenní) leden 2020 Praha více
🍀 Vývoj aplikací v ASP.NET Core březen 2020 Praha více
🍀 Microservices v ASP.NET Core gRPC březen 2020 Praha více
🍀 Vývoj REST API v .NET Core (dvoudenní) březen 2020 Praha více
🍀 Tipy a triky pro ASP.NET Core březen 2020 Praha více

👨‍🎓 Čerstvá školení 2020
👍 Vývoj aplikací v ASP.NET Core
👍 Vývoj REST služeb v .NET Core
👍 Microservices v ASP.NET Core gRPC
👍 Tipy a triky v ASP.NET Core
👍 Změny v ASP.NET Core 3.x