HttpContext 不是线程安全。并行从多个线程访问 HttpContext 可能会导致未定义的行为,例如挂起、崩溃和数据损坏。
请勿这样做:下面的示例进行三个并行请求,并记录传出 HTTP 请求之前和之后的传入请求路径。请求路径从多个线程进行访问(可能是并行访问)。.
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;}
请这样做:下面的示例在进行三个并行请求之前,从传入请求复制所有数据。
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;}