Должен ли я всегда добавлять CancellationToken к действиям моего контроллера?

Это хорошая практика - всегда добавлять CancellationToken в свои действия, независимо от того, долгая операция или нет?

В настоящее время я добавляю его к каждому действию и не знаю, правильно это или неправильно.

[ApiController]
[Route("api/[controller]")]
public class DummiesController : ControllerBase
{
    private readonly AppDbContext _dbContext;

    public DummyController(AppDbContext dbContext)
    {
        _dbContext = dbContext;
    }

    [HttpGet("{id}")]
    public async Task<ActionResult<Dummy>> GetAsync(int id, CancellationToken ct) // <<----- should I always do this?
    {
        var dummy = await _dbContext.Dummies.AsNoTracking().SingleOrDefaultAsync(e=>e.Id == id, ct);
        if (dummy == null) return NotFound();
        return dummy;
    }
}

Также необходимо ли добавить CancellationToken ct = default(CancellationToken)?

Добавьте его, если собираетесь его использовать ... Если вы не планируете отменять операцию, зачем вам это добавлять?

FCin 14.05.2018 13:57

@FCin я не знаю. Может быть, повысится производительность, если пользователь обновит страницу до того, как сервер сможет получить ее из базы данных? Или отменить будет слишком быстро?

Konrad 14.05.2018 14:51

Передача объекта CancellationToken сама по себе ничего не отменяет волшебным образом. Вы должны сами его отменить.

FCin 14.05.2018 14:54

@FCin в действиях контроллера ASP.NET Core, которые он выполняет: andrewlock.net/…

Konrad 14.05.2018 14:55

«ASP.NET Core обеспечивает механизм для веб-сервера (например, Kestrel), чтобы сигнализировать об отмене запроса с помощью CancellationToken. Он отображается как HttpContext.RequestAborted, но вы также можете автоматически вводить его в свои действия с помощью привязки модели. "

Konrad 14.05.2018 14:57

"MVC автоматически привяжет любые параметры CancellationToken в методе действия к токену HttpContext.RequestAborted с помощью CancellationTokenModelBinder. Этот связыватель модели регистрируется автоматически, когда вы вызываете services.AddMvc () (или services.AddMvcCore ()) в Startup.ConfigureServices ( ). "

Konrad 14.05.2018 14:58

Хорошо, я этого не знал. Было бы разумно добавить его в давно работающие методы. Если ваш метод занимает ~ 50 мс, то это не добавляет никакой пользы.

FCin 14.05.2018 14:59

Я не понимаю. На чем основано это мнение? Первые два ответа дают отличное понимание с несколькими ссылками. Второй лучший ответ объясняет, почему всегда использовать жетоны отмены для действий - плохая идея, а это очень важно в некоторых сценариях.

Alexei - check Codidact 29.01.2020 09:59

@Alexei Тогда проголосуйте, чтобы снова открыть его, пожалуйста

Alireza 05.09.2020 12:41

@Alireza Уже сделал это.

Alexei - check Codidact 05.09.2020 17:42

@Alexei Я вижу только одно повторное голосование, хотя я тоже проголосовал

Alireza 05.09.2020 18:13

@Alireza Я думаю, что срок действия моей первоначальной истек. Проголосовал снова.

Alexei - check Codidact 05.09.2020 18:20

@Alireza На этот раз он был закрыт, и вы можете опубликовать свой ответ. Я также разместил упрощенную версию этого вопроса на Codidact, которая более терпима к этому типу вопросов (то есть к выбору дизайна, который также может зависеть от вашего мнения).

Alexei - check Codidact 06.09.2020 15:45
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
36
13
13 942
3

Ответы 3

Стоит добавить, если у вас есть зависимость от внешнего ресурса.

Допустим, ваша база данных занята или у вас есть временные политики обработки ошибок / повторных попыток для подключения к базе данных. Если конечный пользователь нажимает кнопку «Стоп» в своем браузере, токен отмены поможет корректно отменить любые ожидающие операции (в вашем коде).

Думайте об этом не столько о длительной природе при нормальных обстоятельствах, сколько о длительной природе в менее чем идеальных обстоятельствах, например. если работает в Azure и ваша база данных SQL проходит плановое обслуживание, а структура сущности настроена на повторную попытку (предполагается, что инфраструктура сущности разумно реагирует на токены отмены).

В качестве примечания: инфраструктура устойчивости Polly имеет отличную поддержку внешних токенов отмены для координации отмены повторных попыток из внешней отмены. Их вики стоит прочитать, поскольку это отличное средство для координации отмены: https://github.com/App-vNext/Polly/wiki

Что касается CancellationToken ct = default(CancellationToken), это, вероятно, более целесообразно для кода библиотеки, чем для действия контроллера. Но это удобно, если вы напрямую тестируете свой контроллер, но не хотите передавать токен отмены. Тем не менее, в наши дни легче протестировать WebHostBuilder testframework ядра .net, чем напрямую тестировать действия контроллера.

Что касается модульного тестирования кода метода действия, который принимает CancellationToken, если вы не тестируете саму отмену каким-либо образом, просто передайте CancellationToken.None.

bytedev 22.01.2020 09:17

Это правда, что модульное тестирование не должно быть единственной причиной, по которой должен присутствовать default(CancellationToken).

Alex KeySmith 22.01.2020 13:20

Рассмотрите возможность интеграционного тестирования вместо модульного тестирования ваших контроллеров. ASP.NET Core имеет отличную функциональность для интеграционного тестирования (которое проверяет маршрутизацию, привязку модели, авторизацию и т. д.).

Fred 09.07.2020 10:17

Спасибо, Фред, да, я полностью согласен, в наши дни вряд ли вы захотите проводить модульное тестирование контроллера, это, вероятно, оговорка, я, вероятно, имел в виду тестирование в целом.

Alex KeySmith 09.07.2020 16:18

Should I always add CancellationToken to my controller actions?

Нет. Ты не следует всегда.

Использование CancellationTokens в контроллерах MVC ASP.NET Core https://andrewlock.net/using-cancellationtokens-in-asp-net-core-mvc-controllers/

Whether this is correct behaviour will depend on your app. If therequest modifies state, then you may not want to halt execution mid-way through a method. On the other hand, if the request has no side-effects, then you probably want to stop the (presumably expensive) action as soon as you can.

Итак, если у вас есть метод / действие, как показано ниже (упрощено);

await ProcessOrder();
await UpdateInventory();

Вы не хотите отменять заказ во время его обработки, в этом случае заказ может быть выполнен, но вы не обновите инвентарь, если пользователь, проходящий через туннель, потеряет подключение к Интернету.

Это особенно важно, когда операции не могут быть включены в шаблон, подобный единице работы (например, распределенная система), и нужно попытаться свести к минимуму отмены.

Или вы можете использовать транзакцию, охватывающую как ProcessOrder, так и UpdateInventory. Таким образом, запрос все еще может быть отменен, если он занимает слишком много времени (и у клиента есть политики повтора / тайм-аута, настроенные для устойчивости), и транзакция будет отменена, оставляя вашу базу данных в согласованном состоянии.

Jorn Vanloofsvelt 24.01.2020 11:03

Что делать, если вы вызываете сторонний API? Или делать ввод-вывод?

Teoman shipahi 24.01.2020 15:31

Тогда вы в любом случае не можете гарантировать согласованность, если у вас нет какой-либо межсервисной транзакционной системы (возможно, на основе событий / обратного вызова с откатами для каждой службы).

Jorn Vanloofsvelt 24.01.2020 16:06

Тогда нет необходимости использовать для этого токен отмены. Просто беги до конца.

Teoman shipahi 24.01.2020 16:08

Если только это не ресурсоемкая операция, которую вы хотите отменить, когда никто не ждет ответа. Так что скажем так, это зависит от обстоятельств.

Jorn Vanloofsvelt 24.01.2020 19:49

Ресурсоемкие операции должны быть поставлены в очередь и выполняться отдельными процессами.

Teoman shipahi 24.01.2020 19:50

Возможно, вызовы API сами по себе не являются ресурсоемкими, но их отмена может распространить событие отмены на второй API.

Jorn Vanloofsvelt 24.01.2020 20:02

"Возможно". Это может быть услуга, которую вы не контролируете. Например, PayPal api, другая система оплаты / учета запасов, такая как Amazon и т. д.

Teoman shipahi 24.01.2020 21:33

Как я уже сказал, это зависит от обстоятельств. Но помните, что в этом случае нельзя гарантировать постоянство.

Jorn Vanloofsvelt 25.01.2020 17:25

Не в этом суть ни вопроса, ни ответа.

Teoman shipahi 25.01.2020 19:23

Я добавил нюанс к вашему ответу, потому что вы сделали вид, что последовательность имеет значение, в то время как предлагаемое вами решение не гарантирует этого.

Jorn Vanloofsvelt 25.01.2020 19:52

Вы все время вырываете обсуждение из контекста. Согласованность - сама по себе огромная тема, и ваше предложение против реляционных БД с транзакциями - просто капля в море. Я даже не упомянул о гарантиях. Я ссылался на статью с фиктивной аналогией.

Teoman shipahi 25.01.2020 20:02

Вы явно говорите о том, что инвентарь соответствует заказам. Как и статья, которую вы связали. Это не вне контекста

Jorn Vanloofsvelt 25.01.2020 20:10

Отправьте еще один ответ, если вы думаете, что этого недостаточно. Мне очень хотелось бы увидеть и поучиться с вашей точки зрения. Я здесь не для того, чтобы обсуждать алгоритмы согласованности и их реализации, поэтому нам нужно будет проверить здесь все официальные документы. Спасибо!

Teoman shipahi 25.01.2020 20:14

К сожалению, вопрос закрыт (надеюсь, он скоро снова откроется), поэтому я не могу подробно раскрыть суть в комментарии. Вот идея: представьте, что пользователь вызвал ваш api, который запускает длительное обновление базы данных через EFCore, и вы передали метод контекста CancellationToken в SaveChanges. Если токен сигнализирует об отмене (происходит при завершении работы приложения, прерывании HTTP-соединения, закрытии вкладки и т. д.), Выполняется откат выполняющейся транзакции db и генерируется исключение. Теперь вы должны подумать, что вы должны делать в случае возникновения исключения из операции с БД.

Alireza 05.09.2020 17:17

Я думаю, что токен отмены следует использовать в основном для операций типа запроса. В качестве примера возьмем операцию CRUD (создание, чтение, обновление, удаление), разбив ее на CQRS (разделение ответственности за запросы команд).

  • Команда: Создать, обновить, удалить
  • Запрос: Читать

Как видите, операцию запроса не составит труда отменить в любой момент. Но для Command вы, скорее всего, не захотите отменять какие-либо операции. Например, Create, представьте, что вы создаете данные для 2 отдельных баз данных, а затем были отменены на полпути, это приведет к несинхронизации данных.

Другие вопросы по теме