Я только что столкнулся с очень странной проблемой, связанной с cancelToken. Веб-API разработан с использованием .Net Core, а интерфейс — на Angular. 1 час назад я пытаюсь разработать дополнительную функцию и перед запуском запускаю ее еще раз, и вдруг отметка Token становится истинной. Такого никогда не происходит раньше. Я не вносил никаких изменений в бэкэнд и фронтенд.
Функция контроллера:
[HttpDelete("dqc")]
[AllowAnonymous]
public async Task<IActionResult> DeleteDQCAsync([FromBody] IEnumerable<DqcDto> dqcs, CancellationToken cancellationToken)
{
try
{
var response = await _managerService.DeleteDqcAsync(dqcs, cancellationToken);
if (response)
{
return Ok(new { message = "DQC codes have been deleted successfully" });
}
else
{
return BadRequest(new { message = "Delete selected DQC codes failed." });
}
}
catch (Exception)
{
throw;
}
}
Даже странно, что когда я добавляю точку останова и отлаживаю код, функция вызывается, а отмена оказывается ложной. Через секунду отметкаToken становится истинной, но я ничего не нажимаю. Иногда, когда я нажимаю кнопку во внешнем интерфейсе, функция даже не вызывается. Только когда я добавляю точку останова в браузере и выполняю построчно, токен отмены всегда имеет значение false.
Похоже, что интерфейс отправляет сигнал на автоматическую отмену запроса, но я понятия не имею, почему, поскольку этого никогда не происходит даже до сегодняшнего дня.
Может ли кто-нибудь дать мне подсказку, как я могу понять, почему это происходит?
Обновлять: После нескольких часов исследования я обнаружил, что код Angular ведет себя странно. Например:
deleteItems(): void {
let isDelete: boolean = false;
const itemsToDelete = this.checkitems.map((item) => ({
uicp: item.uicp,
dqcCode: item.dqcCode,
dqcDescription: item.dqcDescription,
task: Object.keys(item.tasks)
.filter((task) => item.tasks[task])
.join(','),
remark: item.remark,
timestamp: item.lastUpdate,
}));
console.info(itemsToDelete);
// Assuming there's a method in DataService to handle deletion
this.dataService.deleteData(itemsToDelete).subscribe((response) => {
console.info('Items deleted:', response);
if (response.status === 200) {
// Remove the deleted items from tableData
this.tableData = this.tableData.filter(
(item) => !this.checkitems.includes(item)
);
this.checkitems = [];
isDelete = true;
}
});
if (isDelete) {
location.reload();
}
}
saveItems(): void {
let isAdd: boolean = false;
let isUpdate: boolean = false;
const newItems = this.checkitems
.filter((item) => item.isNew)
.map((item) => ({
uicp: item.uicp,
dqcCode: item.dqcCode,
dqcDescription: item.dqcDescription,
task: Object.keys(item.tasks)
.filter((task) => item.tasks[task])
.join(','),
remark: item.remark,
}));
console.info('finish new items');
const updatedItems = this.checkitems
.filter((item) => !item.isNew)
.map((item) => ({
uicp: item.uicp,
dqcCode: item.dqcCode,
dqcDescription: item.dqcDescription,
task: Object.keys(item.tasks)
.filter((task) => item.tasks[task])
.join(','),
remark: item.remark,
timestamp: item.lastUpdate,
}));
console.info('finish update item');
console.info('New Items:', newItems);
console.info('Updated Items:', updatedItems);
if (newItems.length > 0) {
console.info('start to add');
this.dataService.addData(newItems).subscribe(
(response) => {
console.info('wait for response');
if (response.status === 200) {
isAdd = true;
console.info('New items added:', response.body);
} else {
console.error('Unexpected response:', response);
}
this.checkitems.forEach((item) => {
item.isNew = false;
item.selected = false;
});
this.checkitems = [];
//this.updateSavedItems();
},
(error: HttpErrorResponse) => {
console.error('Error adding new items:', error.message);
}
);
}
if (updatedItems.length > 0) {
console.info('start to update');
this.dataService.updateData(updatedItems).subscribe(
(response) => {
console.info('wait for response');
if (response.status === 200) {
isUpdate = true;
console.info('Items updated:', response.body);
} else {
console.error('Unexpected response:', response);
}
this.checkitems.forEach((item) => {
item.isNew = false;
item.selected = false;
});
this.checkitems = [];
//this.updateSavedItems();
},
(error: HttpErrorResponse) => {
console.error('Error updating items:', error.message);
}
);
}
if (isAdd || isUpdate) {
location.reload();
}
}
Функции сервиса:
deleteData(items: any[]): Observable<any> {
return this.http.delete(`${this.apiUrl}/dqc`, {'body':items});
}
addData(newItems: any[]): Observable<any> {
return this.http.post<any>(`${this.apiUrl}/dqc`, newItems);
}
updateData(updatedItems: any[]): Observable<any> {
return this.http.put<any>(`${this.apiUrl}/dqc`, updatedItems);
}
Существует две основные функции: одна — удаление элементов, а другая — обновление и/или добавление элементов. В этих двух функциях программа каким-то образом пропускает среднюю часть и сразу переходит к концу, чтобы обновить страницу, даже пропускает части, которые отправляют запросы на бэкэнд. Это приводит к тому, что для параметра cancelToken устанавливается значение true. Иногда эта проблема исчезает и все идет хорошо. Он действует так, что location.reload() является магнитом и заставляет программу выполнить эту строку первой.
Кто-нибудь знает, почему это происходит?
@decius Не могли бы вы рассказать мне, как проверить?
Вы можете открыть инструменты разработки в своем браузере, нажав F12. Там вы можете увидеть отмену. Установите точку останова. И подождите 120 секунд после достижения точки останова. Я думаю, это должно стать причиной отмены.
@decius Я нашел, как это происходит, но понятия не имею, почему. В конце функции удаления в Angular я обновляю страницу, используя location.reload() Но почему-то программа пропускает функцию отправки запроса, а непосредственно обновляет страницу. В этом случае отправляется запрос на отмену. Я не знаю, почему это происходит
Можете ли вы добавить этот код в свой вопрос? Если вы не ожидаете первого вызова вашего API, это может произойти, как я мог себе представить.
@decius Я добавил код в Обновление.
Я опубликовал ответ. Причина, по которой это происходит, мне ясна. проверьте это.





Проблема в том, что location.reload() выполняется непосредственно после subscibe(). Он работает параллельно — таким образом вызов вашего API не ожидается. Вот и причина отмены. Вам нужно поместить оператор location.reload() в subscribe() следующим образом:
this.dataService.deleteData(itemsToDelete).subscribe((response) => {
console.info('Items deleted:', response);
if (response.status === 200) {
// Remove the deleted items from tableData
this.tableData = this.tableData.filter(
(item) => !this.checkitems.includes(item)
);
this.checkitems = [];
location.reload();
}
});
}
И кстати: вместо использования location.reload() вам следует просто вызвать действие GET этого API после завершения вызова удаления.
Это не причина. isAdd и isUpdate являются ложными. Им присваивается значение true только после получения ответа. Вы правы насчет location.reload, который находится снаружи, но он не выполняется, поскольку оба условия ложны.
Я не говорил об обновлении или сохранении элементов. Первоначальный вопрос был о методе удаления. И тут явно причина, что перезагрузка происходит вне подписки. Флаги isAdd или isUpdate отсутствуют. Итак, я ответил на первоначальный вопрос перед редактированием поста. Я не вижу причин голосовать против.
В других методах могут быть другие проблемы. Затем напишите второй ответ и поговорите об этом, вместо того, чтобы голосовать против моего ответа.
Это та же идея для удаления. isDelete имеет значение true только после ответа и всегда имеет значение false, когда location.reload(); достигается.
Что тогда является причиной отмены? Это также не ваши логические флаги. Код был неправильным в части перезагрузки. И этот ответ правильный. Я не услышал от тебя ответа.
Я не знаю, в чем проблема с cancelToken, но ваше объяснение неверно, и вы, будучи умным парнем, понимаете, что в этот момент флаг является ложным и перезагрузка не вызывается. Вы — облачный архитектор, поэтому для вас это должно иметь смысл.
Позиция всех «если» также неверна. Именно это я и отметил. Благодаря моему решению эти флаги вам больше не нужны. Возможно, это не решит всей проблемы, но является первым шагом в правильном направлении. Ваше поведение неконструктивно с моей точки зрения.
@decius Ваше решение помогает решить проблему, чтобы избежать установки для параметра cancelToken значения true, поэтому я отмечаю его как полезное. Но я действительно не понимаю, почему location.relocate() выполняется раньше другого кода, даже если он находится в последней строке. Даже если код ответа не выполняется. Также я обнаружил, что мои функции отправляют запросы на серверную часть. Я должен использовать Observable<HttpResponse<string>> и добавить указание типа ответа, иначе возвращаемый ответ не будет иметь свойства Status. Я не знаю почему, но это также помогает избежать ошибок.
Это трудно сказать по этим строкам кода. Но, как я уже говорил, удалите все логические флаги и поместите перезагрузку в функцию subscribe(), а затем проверьте еще раз. Или еще лучше: вместо reload() выполните вызов GET к вашему API, чтобы получить новые данные. Если бы вы использовали, например, RxJS, было бы еще проще работать с этими Obserables, потому что тогда вы можете связывать различные вызовы один за другим.
@decius Спасибо за советы. Я новичок в Angular, поэтому развиваюсь во время обучения. Я это отмечу. Еще раз спасибо.
Пожалуйста. Конечно, вы учитесь. это нормально. удаление bools и установка перезагрузки в нужное место решили вашу проблему?
@decius да, так и было. Но я просто не знаю, почему эта строка выполняется заранее.
Из-за операторов if его фактически не следует выполнять. Но использовать этот оператор if также является плохой практикой, поскольку из-за некоторых проблем с параллелизмом во время отладки это может привести к выполнению в другом порядке. Основной вывод заключается в том, что ваш вызов удаления и вызов reload() (без if) выполняются параллельно, то есть одновременно, поскольку subscribe() не будет ждать, пока операция внутри (ваш вызов удаления) не завершится. .
Если теперь все стало яснее и мой ответ помог решить проблему, не стесняйтесь принять и ответ. Спасибо. :)
Может быть, тайм-аут запроса отправлен FE из-за сеанса отладки?