is HttpContext async safe in asp.net core?

According to documentation: https://learn.microsoft.com/en-us/aspnet/core/performance/performance-best-practices?view=aspnetcore-5.0#do-not-access-httpcontext-from-multiple-threads

HttpContext is NOT thread-safe. Accessing HttpContext from multiple threads in parallel can result in undefined behavior such as hangs, crashes, and data corruption.

Do not do this: The following example makes three parallel requests and logs the incoming request path before and after the outgoing HTTP request. The request path is accessed from multiple threads, potentially in parallel.

public class AsyncBadSearchController : Controller
{       
    [HttpGet("/search")]
    public async Task<SearchResults> Get(string query)
    {
       var query1 = SearchAsync(SearchEngine.Google, query);
       var query2 = SearchAsync(SearchEngine.Bing, query);
       var query3 = SearchAsync(SearchEngine.DuckDuckGo, query);

       await Task.WhenAll(query1, query2, query3);

       var results1 = await query1;
       var results2 = await query2;
       var results3 = await query3;

       return SearchResults.Combine(results1, results2, results3);
    }       

    private async Task<SearchResults> SearchAsync(SearchEngine engine, string query)
    {
        var searchResults = _searchService.Empty();
        try
        {
            _logger.LogInformation("Starting search query from {path}.", 
                                    HttpContext.Request.Path);
            searchResults = _searchService.Search(engine, query);
            _logger.LogInformation("Finishing search query from {path}.", 
                                    HttpContext.Request.Path);
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "Failed query from {path}", 
                             HttpContext.Request.Path);
        }

        return await searchResults;
    }
}

Do this: The following example copies all data from the incoming request before making the three parallel requests.

public class AsyncGoodSearchController : Controller
{       
    [HttpGet("/search")]
    public async Task<SearchResults> Get(string query)
    {
        string path = HttpContext.Request.Path;
        var query1 = SearchAsync(SearchEngine.Google, query,
                             path);
        var query2 = SearchAsync(SearchEngine.Bing, query, path);
        var query3 = SearchAsync(SearchEngine.DuckDuckGo, query, path);

        await Task.WhenAll(query1, query2, query3);

        var results1 = await query1;
        var results2 = await query2;
        var results3 = await query3;

        return SearchResults.Combine(results1, results2, results3);
    }

       private async Task<SearchResults> SearchAsync(SearchEngine engine, string query,
                                                  string path)
       {
        var searchResults = _searchService.Empty();
        try
        {
            _logger.LogInformation("Starting search query from {path}.",
                                   path);
            searchResults = await _searchService.SearchAsync(engine, query);
            _logger.LogInformation("Finishing search query from {path}.", path);
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "Failed query from {path}", path);
        }

        return await searchResults;
    }
}

So is HttpContext still safe to use in async methods? or is it possible to get a different context after the await call?

The whole problem with async and HttpContext and ASP.NET pre-Core was due to the fact that code usually got its HttpContext from HttpContext.Current. ASP.NET is a multithreaded server, and each await could resume on a different thread. So ASP.NET pre-Core had to have an AspNetSynchronizationContext that managed setting HttpContext.Current before the asynchronous code resumed.

The modern ASP.NET Core does not have a synchronization context. But that's fine, because it also doesn't have HttpContext.Current. The only way of getting the HttpContext instance is through a local property (e.g., HttpContext on your controller class) or dependency injection (IHttpContextAccessor).

(Pedantic note: the explanation above is a bit simplified - the ASP.NET pre-Core synchronization context did handle other things besides HttpContext.Current - but the same overall exaplanation holds for all of its other responsibilities - i.e., they are not necessary in the Core world)

So, it is not possible for the context to be different. They are the same property - the same object instance. The problem with ASP.NET pre-Core was a static property value HttpContext.Current, which has been removed in ASP.NET Core.