Как правильно отсоединить fom HttpContect в фоновом потоке?

#.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. Или два разных метода были объединены в один, в зависимости от глобального состояния, чтобы контролировать их поведение