#.net #multithreading #asp.net-core #.net-core
#.net #многопоточность #asp.net-core #.net-core
Вопрос:
Я использую ASP.NET Ядро 3.1, и мне нужно найти способ запустить фоновую задачу / поток / таймер, который не подключен к текущему HttpContext.
Например, рассмотрим следующий код:
public class MyController : ApiControllerBase
{
private readonly IHttpContextAccessor _contextAccessor;
public MyController(IHttpContextAccessor contextAccessor)
{
this._contextAccessor = contextAccessor;
}
[HttpGet]
public IActionResult DoSomething()
{
// Start a task on another thread.
Task.Run(this.TaskAction);
// Start a background thread.
var thread = new Thread(this.ThreadAction);
thread.IsBackground = true;
thread.Start();
thread.Join();
// Start a timer.
var timer = new System.Timers.Timer();
timer.Interval = 1;
timer.Elapsed = this.Timer_Elapsed;
timer.AutoReset = false;
timer.Start();
Thread.Sleep(3000);
return this.StatusCode(200);
}
private void TaskAction()
{
if (this._contextAccessor.HttpContext != null)
Debug.WriteLine("Oh no! We have an HttpContext in the task action");
}
private void ThreadAction() {
if (this._contextAccessor.HttpContext != null)
Debug.WriteLine("Oh no! We have an HttpContext in the thread action");
}
private void Timer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
{
if (this._contextAccessor.HttpContext != null)
Debug.WriteLine("Oh no! We have an HttpContext in the timer action");
}
}
Моя проблема в том, что в каждой из этих фоновых операций HttpContext
есть. Однако в некоторых случаях (поскольку фоновые операции являются длительными задачами и из-за текущей архитектуры приложения) у нас не должно быть контекста в новых потоках. Именно так все работало в .NET Framework.
Мой вопрос: каков правильный способ добиться этого? Я хочу, чтобы все мои фоновые операции не имели контекста HTTP.
Единственный способ, который я нашел на данный момент, — это временно приостановить поток контекста выполнения потока при создании фоновой задачи. Например:
// Start a task on another thread.
using (var flowContext = ExecutionContext.SuppressFlow())
{
Task.Run(this.TaskAction);
}
Это нормально, или я собираюсь как-то себя обмануть?
Комментарии:
1. Почему вас волнует HttpContext? Если вы этого не хотите, не обращайтесь к нему. Вы пытаетесь решить какую-то другую проблему и предполагаете, что HttpContext как-то связан? Кроме того, это был .NET Old, который повсюду сохранял статический HttpContext. В .NET Core вы должны запросить это явно. То
HttpContext
, что вы используете в контроллере, является свойством экземпляра, а не статическим объектом2. В любом случае,
DoSomething
глючит. Все параметры,Task.Run
, необработанный поток и таймер, были небезопасны и в .NET Old. Все это может привести к неожиданным ошибкам, поскольку запрос завершится до того, как любой из них получит возможность завершить. Все они (особенно таймер) могут легко привести кObjectDisposedException
исключениям или NRE, поскольку даже контроллер будет собирать мусор после завершения запроса3. Я подозреваю, что вам нужен BackgroundService — что -то, что запускается при запуске хоста и вообще не связано с контроллерами и запросами
4. @PanagiotisKanavos Да — в конце концов, я думаю, вы правы — BackgroundService, вероятно, то, что мне нужно. Что касается других ваших комментариев, причина в том, что часть кода, вызываемого фоновыми потоками, ведет себя по-разному в зависимости от того, доступен ли an
HttpContext
. Я понимаю, что doSomething глючит по причинам, которые вы упомянули, но это всего лишь пример кода, призванный проиллюстрировать мою проблему.5. В чем проблема? Это больше похоже на проблему с кодом / инверсией контроля. По какой-то причине неуказанное фоновое задание получило HttpContextAccessor, когда ему действительно нужен HttpContext. Или два разных метода были объединены в один, в зависимости от глобального состояния, чтобы контролировать их поведение