Я столкнулся с проблемой, когда задача, выполняемая ниже, выполняется асинхронно, но не может быть отменена, когда сериализатор считывает поток памяти. Когда пользователь делает запрос на отмену (нажав кнопку отмены), выполняется отмена (метод cancel () вызывается из токена), но задача продолжается.
Класс обслуживания:
Асинхронный метод, вызываемый из LoadHelper () в основном классе
public async void StartTask(Action callback, CancellationToken token)
{
await Task.Run(callback, token);
}
Основной класс:
private void LoadHelper()
{
_services.GetInstance<IThreadService>().StartTask(
() => LoadHelperAsync(), _cancelService.Token);
}
Метод выполняется асинхронно
private void LoadHelperAsync()
{
var serializer = new DataContractSerializer(typeof(UserDatabase));
string selectedDir;
ComparisonResult = null;
_services.GetInstance<IOpenFileService>().DisplayOpenFileDialog(
"Select a saved comparison",
"Comparison File(*.xml; *.cmp)|*.xml;*.cmp",
Environment.GetFolderPath(Environment.SpecialFolder.Desktop),
out selectedDir);
if (!string.IsNullOrEmpty(selectedDir))
{
_dispatchService.BeginInvoke(() => IsExecuting = true);
using (FileStream fileStream = new FileStream(selectedDir, FileMode.Open, FileAccess.Read))
using (DeflateStream compressedStream = new DeflateStream(fileStream, CompressionMode.Decompress))
using (BufferedStream regularStream = new BufferedStream(fileStream))
{
Stream memoryStream;
//Use filename to determine compression
if (selectedDir.EndsWith(".cmp", true, null))
{
memoryStream = compressedStream;
}
else
{
memoryStream = regularStream;
}
Report("Loading comparison");
Report(0);
IsExecuting = true;
ComparisonResult = (UserDatabase)serializer.ReadObject(memoryStream);
memoryStream.Close();
fileStream.Close();
IsExecuting = false;
Report("Comparison loaded");
}
_dispatchService.BeginInvoke(() => IsExecuting = false);
_dispatchService.BeginInvoke(() => ViewResults.ExecuteIfAble());
}
else
{
Report("No comparison loaded");
}
Код отмены:
Эта команда привязана к кнопке «отменить» в представлении.
CancelCompare = new Command(o => _cancelService.Cancel(), o => IsExecuting);
Из класса CancellationService
public class CancellationService : ICancellationService, IDisposable
{
private CancellationTokenSource _tokenSource;
public CancellationService()
{
Reset();
}
public CancellationToken Token { get; private set; }
public void Cancel()
{
_tokenSource.Cancel();
}
public void Reset()
{
_tokenSource = new CancellationTokenSource();
Token = _tokenSource.Token;
}
protected virtual void Dispose(bool disposing)
{
if (disposing)
{
_tokenSource.Cancel();
_tokenSource.Dispose();
}
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
}
LoadHelperAsync
с суффиксом -Async, если это не async? - person mason   schedule 30.07.2018.Cancel()
не прерывает поток, он сигнализирует токену. Ваше действие должно получить токен и проверить его поднятие. Если вы хотите отменить десериализацию, вы должны использовать асинхронные методы внутриLoadHelperAsync
и также передать им токен. Не BeginInvoke, это, по сути,Thread.Start
или прямой вызов другого потока, в зависимости от того, что_dispatchService
- person Panagiotis Kanavos   schedule 30.07.2018async void
доставит вам массу неприятностей. И вы должны соответствующим образом переименовать свой метод. - person mason   schedule 30.07.2018await
, он позволяет вам работать с потоком пользовательского интерфейса до и после вызоваawait
. Отчеты о ходе выполнения должны использоватьIProgress<T>
интерфейс. Проверьте Включение выполнения и отмены в асинхронных API - person Panagiotis Kanavos   schedule 30.07.2018LoadHelperAsync
. Вам не нужноBeginInvoke
, когда вы используетеawait
. Единственное, что должно быть асинхронным, - это вызовserializer.ReadObject
и его поток. - person Panagiotis Kanavos   schedule 30.07.2018