Это хорошая практика - всегда добавлять 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 я не знаю. Может быть, повысится производительность, если пользователь обновит страницу до того, как сервер сможет получить ее из базы данных? Или отменить будет слишком быстро?
Передача объекта CancellationToken
сама по себе ничего не отменяет волшебным образом. Вы должны сами его отменить.
@FCin в действиях контроллера ASP.NET Core, которые он выполняет: andrewlock.net/…
«ASP.NET Core обеспечивает механизм для веб-сервера (например, Kestrel), чтобы сигнализировать об отмене запроса с помощью CancellationToken. Он отображается как HttpContext.RequestAborted, но вы также можете автоматически вводить его в свои действия с помощью привязки модели. "
"MVC автоматически привяжет любые параметры CancellationToken в методе действия к токену HttpContext.RequestAborted с помощью CancellationTokenModelBinder. Этот связыватель модели регистрируется автоматически, когда вы вызываете services.AddMvc () (или services.AddMvcCore ()) в Startup.ConfigureServices ( ). "
Хорошо, я этого не знал. Было бы разумно добавить его в давно работающие методы. Если ваш метод занимает ~ 50 мс, то это не добавляет никакой пользы.
Я не понимаю. На чем основано это мнение? Первые два ответа дают отличное понимание с несколькими ссылками. Второй лучший ответ объясняет, почему всегда использовать жетоны отмены для действий - плохая идея, а это очень важно в некоторых сценариях.
@Alexei Тогда проголосуйте, чтобы снова открыть его, пожалуйста
@Alireza Уже сделал это.
@Alexei Я вижу только одно повторное голосование, хотя я тоже проголосовал
@Alireza Я думаю, что срок действия моей первоначальной истек. Проголосовал снова.
@Alireza На этот раз он был закрыт, и вы можете опубликовать свой ответ. Я также разместил упрощенную версию этого вопроса на Codidact, которая более терпима к этому типу вопросов (то есть к выбору дизайна, который также может зависеть от вашего мнения).
Стоит добавить, если у вас есть зависимость от внешнего ресурса.
Допустим, ваша база данных занята или у вас есть временные политики обработки ошибок / повторных попыток для подключения к базе данных. Если конечный пользователь нажимает кнопку «Стоп» в своем браузере, токен отмены поможет корректно отменить любые ожидающие операции (в вашем коде).
Думайте об этом не столько о длительной природе при нормальных обстоятельствах, сколько о длительной природе в менее чем идеальных обстоятельствах, например. если работает в Azure и ваша база данных SQL проходит плановое обслуживание, а структура сущности настроена на повторную попытку (предполагается, что инфраструктура сущности разумно реагирует на токены отмены).
В качестве примечания: инфраструктура устойчивости Polly имеет отличную поддержку внешних токенов отмены для координации отмены повторных попыток из внешней отмены. Их вики стоит прочитать, поскольку это отличное средство для координации отмены: https://github.com/App-vNext/Polly/wiki
Что касается CancellationToken ct = default(CancellationToken)
, это, вероятно, более целесообразно для кода библиотеки, чем для действия контроллера. Но это удобно, если вы напрямую тестируете свой контроллер, но не хотите передавать токен отмены. Тем не менее, в наши дни легче протестировать WebHostBuilder testframework ядра .net, чем напрямую тестировать действия контроллера.
Что касается модульного тестирования кода метода действия, который принимает CancellationToken, если вы не тестируете саму отмену каким-либо образом, просто передайте CancellationToken.None.
Это правда, что модульное тестирование не должно быть единственной причиной, по которой должен присутствовать default(CancellationToken)
.
Рассмотрите возможность интеграционного тестирования вместо модульного тестирования ваших контроллеров. ASP.NET Core имеет отличную функциональность для интеграционного тестирования (которое проверяет маршрутизацию, привязку модели, авторизацию и т. д.).
Спасибо, Фред, да, я полностью согласен, в наши дни вряд ли вы захотите проводить модульное тестирование контроллера, это, вероятно, оговорка, я, вероятно, имел в виду тестирование в целом.
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. Таким образом, запрос все еще может быть отменен, если он занимает слишком много времени (и у клиента есть политики повтора / тайм-аута, настроенные для устойчивости), и транзакция будет отменена, оставляя вашу базу данных в согласованном состоянии.
Что делать, если вы вызываете сторонний API? Или делать ввод-вывод?
Тогда вы в любом случае не можете гарантировать согласованность, если у вас нет какой-либо межсервисной транзакционной системы (возможно, на основе событий / обратного вызова с откатами для каждой службы).
Тогда нет необходимости использовать для этого токен отмены. Просто беги до конца.
Если только это не ресурсоемкая операция, которую вы хотите отменить, когда никто не ждет ответа. Так что скажем так, это зависит от обстоятельств.
Ресурсоемкие операции должны быть поставлены в очередь и выполняться отдельными процессами.
Возможно, вызовы API сами по себе не являются ресурсоемкими, но их отмена может распространить событие отмены на второй API.
"Возможно". Это может быть услуга, которую вы не контролируете. Например, PayPal api, другая система оплаты / учета запасов, такая как Amazon и т. д.
Как я уже сказал, это зависит от обстоятельств. Но помните, что в этом случае нельзя гарантировать постоянство.
Не в этом суть ни вопроса, ни ответа.
Я добавил нюанс к вашему ответу, потому что вы сделали вид, что последовательность имеет значение, в то время как предлагаемое вами решение не гарантирует этого.
Вы все время вырываете обсуждение из контекста. Согласованность - сама по себе огромная тема, и ваше предложение против реляционных БД с транзакциями - просто капля в море. Я даже не упомянул о гарантиях. Я ссылался на статью с фиктивной аналогией.
Вы явно говорите о том, что инвентарь соответствует заказам. Как и статья, которую вы связали. Это не вне контекста
Отправьте еще один ответ, если вы думаете, что этого недостаточно. Мне очень хотелось бы увидеть и поучиться с вашей точки зрения. Я здесь не для того, чтобы обсуждать алгоритмы согласованности и их реализации, поэтому нам нужно будет проверить здесь все официальные документы. Спасибо!
К сожалению, вопрос закрыт (надеюсь, он скоро снова откроется), поэтому я не могу подробно раскрыть суть в комментарии. Вот идея: представьте, что пользователь вызвал ваш api, который запускает длительное обновление базы данных через EFCore, и вы передали метод контекста CancellationToken
в SaveChanges
. Если токен сигнализирует об отмене (происходит при завершении работы приложения, прерывании HTTP-соединения, закрытии вкладки и т. д.), Выполняется откат выполняющейся транзакции db и генерируется исключение. Теперь вы должны подумать, что вы должны делать в случае возникновения исключения из операции с БД.
Я думаю, что токен отмены следует использовать в основном для операций типа запроса. В качестве примера возьмем операцию CRUD (создание, чтение, обновление, удаление), разбив ее на CQRS (разделение ответственности за запросы команд).
Как видите, операцию запроса не составит труда отменить в любой момент. Но для Command вы, скорее всего, не захотите отменять какие-либо операции. Например, Create, представьте, что вы создаете данные для 2 отдельных баз данных, а затем были отменены на полпути, это приведет к несинхронизации данных.
Добавьте его, если собираетесь его использовать ... Если вы не планируете отменять операцию, зачем вам это добавлять?