#c# #asp.net #model-view-controller #.net-core
#c# #asp.net #модель-представление-контроллер #.net-ядро
Вопрос:
Я вызываю ту же функцию параллельно, используя Task.Whenall().Я И пытаюсь добавить функциональность для остановки выполнения с помощью CancellationTokenSource . CancellationTokenSource возвращает значение true при вызове токена.Cancel() но впоследствии оно изменяется на false и, следовательно, токен.IsCancellationRequested всегда имеет значение false.
CancellationTokenSource _tokenSource = new CancellationTokenSource();
[HttpPost]
public async Task<IActionResult> Runcase(List<string> products,string runnumber,string button)
{
var token = _tokenSource.Token;
try
{
if (ModelState.IsValid)
{
var productinfo = products;
List<string> productids = new List<string>(productinfo);
var runnum = runnumber;
string runid = "";
int count = productids.Count();
List<Task> tasks = new List<Task>();
int rawid = 0;
for (int i = 0; i < count; i )
{
tasks.Add(RunServiceAsync(productids[i], runnum,rawid,token));
}
await Task.WhenAll(tasks);
ViewBag.completed = "Success";
return View();
}
else
{
ViewBag.productinfo = new MultiSelectList(_context.inputValuesConfigurations, "ProductID", "ProductName");
ModelState.AddModelError(string.Empty, "Please enter a valid data...");
return View();
}
}
catch(Exception ex)
{
return View();
}
}
Когда я вызываю эту функцию, токен возвращает значение true
public void Stopexecution()
{
_tokenSource.Cancel();
}
Но в приведенном ниже коде это всегда false
public async Task RunServiceAsync(string productids,string runnumber,int rawid,CancellationToken token)
{
using(var dbscope = _service.CreateScope())
{
var dbcontext = dbscope.ServiceProvider.GetRequiredService<AppDbContext>();
var productid = Convert.ToInt32(productids);
var inputvals = dbcontext.inputValuesConfigurations.FirstOrDefault(m => m.ProductID == productid);
var run = runnumber '_' inputvals.ProductID;
int count = 0;
bool completion1 = false; // for j
int totalCount = CountProductvalues(inputvals);
while (!completion1) //
{
var errorrun = dbcontext.errorlogs.Select(m => m.ProductID == productid).ToList().Count();
totalCount = completion == true ? errorrun : totalCount;
for (int j = rawid; j < totalCount; j )
{
if(token.IsCancellationRequested)
{
token.ThrowIfCancellationRequested();
}
if(!completion) // Stop if First run complete
{
Inputvalues c1 = new Inputvalues(j, inputvals);
InputValuesViewmodel inputValues = new InputValuesViewmodel()
{
ProductID = productid,
STATE = c1.State,
AGE1 = c1.AGE1,
SEX1 = c1.SEX1,
UND_CLASS1 = c1.UND_CLASS1,
FACE_OPTIONS = 1,
FACE_SCHEDULE = "1ü" c1.SOLVE_TARGET_YEAR "0ü" c1.FACE_SCHEDULE,
PREM_OPTIONS = premoption,
PAY_PREM_TARGET_ID = c1.PAY_PREM_TARGET_ID,
PAY_PREM_TARGET_YEAR = c1.PAY_PREM_TARGET_YEAR,
SOLVE_TARGET_ID = 1,
SOLVE_TARGET_YEAR = c1.SOLVE_TARGET_YEAR
};
await RecieveResponseasync(inputValues, run, j,productid);
//completion = j == totalCount ? true : false;
}
}
};
}
}
Вызов Stopexecution()
$("#btnstop").click(function (e) {
$("#btnstart span").text("Rerun");
let btnstartval = $("#btnstart").val('Rerun');
e.preventDefault();
$.ajax({
url: "@Url.Action("Stopexecution", "CallService")",
type: "POST",
dataType: "json",
});
});
});
Комментарии:
1. Куда вы звоните
StopExecution()
?2. Пожалуйста, покажите, где вы берете токен из _tokenSource и передаете его методу.
3. Я только что обновил свой код. Не могли бы вы взглянуть на это еще раз? Спасибо
4. @insane_developer Я вызываю StopExecution() из представления, используя вызов ajax.
5. @Neu я думаю, что одним из способов было бы сделать его статичным, но тогда вы должны посмотреть, влияет ли это на другие вызовы, которые могут использовать токен. В любом случае, это, вероятно, не очень хороший подход, контроллер со статическим свойством. Почему вы должны отменить токен, основываясь на чем?
Ответ №1:
Итак, первая проблема здесь заключается в том, что у вас есть CancellationTokenSource
в качестве члена контроллера. Контроллеры являются временными, то есть они создаются каждый раз, когда к нему поступает запрос. Итак, вы создаете новый источник токена каждый раз, когда вызывается этот контроллер.
Чтобы исправить это, вы могли бы сделать это статическим:
static CancellationTokenSource _tokenSource = new CancellationTokenSource();
Не забывайте сбрасывать этот источник каждый раз, когда выполняется запрос … потому что, как только он отменяется, он отменяется навсегда. Кроме того, что произойдет, если эта конечная точка будет вызвана два или более раз одновременно. У вас будет состояние гонки.
Вторая проблема: это не очень «подобный контроллеру» шаблон. Вам следует переосмыслить, как вы генерируете данные. Если вызов конечной точки занимает больше 100 мс, то вы столкнетесь с проблемами нехватки потоков / сокетов, если ваша служба перегреется.
Комментарии:
1. Спасибо @Andy. Это сработало, и я рассмотрю рекомендованный вами подход.
2. @Neu — нет проблем… Надеюсь, вы сможете разобраться с этим, чтобы вам не нужно было отменять ожидающий запрос 🙂 Удачи вам.