我正在尝试制作一个通用方法,该方法将取消异步Web请求以及与此相关的任何其他操作。我发现关于该如另一个问题本。
我编写了一个帮助程序类,可以完成此任务。我在下面介绍:
public static class Helpers
{
public static async Task<string> GetJson(string url,
CancellationTokenSource cancellationTokenSource,
bool useSynchronizationContext = true)
{
try
{
var request = (HttpWebRequest)WebRequest.Create(url);
string jsonStringResult;
using (WebResponse response = await request.GetResponseAsync()
.WithCancellation(cancellationTokenSource.Token,
request.Abort, useSynchronizationContext))
{
Stream dataStream = response.GetResponseStream();
StreamReader reader = new StreamReader(dataStream);
jsonStringResult = await reader.ReadToEndAsync();
reader.Close();
dataStream.Close();
}
cancellationTokenSource.Token.ThrowIfCancellationRequested();
return jsonStringResult;
}
catch (Exception ex) when (ex is OperationCanceledException
|| ex is TaskCanceledException)
{
}
catch (Exception ex) when (ex is WebException
&& ((WebException)ex).Status == WebExceptionStatus.RequestCanceled)
{
}
catch (Exception ex)
{
//Any other exception
}
finally
{
cancellationTokenSource.Dispose();
}
return default;
}
public static async Task<T> WithCancellation<T>(this Task<T> task,
CancellationToken cancellationToken, Action action,
bool useSynchronizationContext)
{
using (cancellationToken.Register(action, useSynchronizationContext))
{
return await task;
}
}
}
注意行
cancellationTokenSource.Token.ThrowIfCancellationRequested();
在返回JSON字符串之前。
当操作被取消并且执行流程在线时
StreamReader reader = new StreamReader(dataStream);
例如,reader.Close()
将执行下面的所有行(等),并且在执行时将引发异常ThrowIfCancelationRequested()
-是正确的吗?我想念什么吗?
如果是这样,是否有办法立即取消所有内容?
感谢大家的回应,
在提供答案和所有有用的注释之后,我更新了实现。我在链接中使用HttpClient和扩展方法,使一项任务实际上无法被取消,其行为类似于可以-readAsStringAsync实际上已执行,因为它不能接受取消令牌。
public static class Helpers
{
public static async Task<string> GetJson(string url,CancellationToken cancellationToken)
{
try
{
string jsonStringResult;
using (var client = new HttpClient())
{
cancellationToken.ThrowIfCancellationRequested();
using (var response = await client.GetAsync(url, cancellationToken))
{
jsonStringResult = await response.Content.ReadAsStringAsync().WithCancellation(cancellationToken);
}
}
return jsonStringResult;
}
catch (Exception ex) when (ex is OperationCanceledException)
{
}
catch (Exception ex) when (ex is WebException exception && exception.Status == WebExceptionStatus.RequestCanceled)
{
}
catch (Exception ex)
{
//LogException(ex);
}
return default;
}
public static Task<T> WithCancellation<T>(this Task<T> task, CancellationToken cancellationToken)
{
return task.IsCompleted
? task: task.ContinueWith(completedTask => completedTask.GetAwaiter().GetResult(),cancellationToken,TaskContinuationOptions.ExecuteSynchronously,TaskScheduler.Default);
}
}
下面的所有行(reader.Close()等)将被执行,并且在执行ThrowIfCancelationRequested()时将引发异常-是正确的吗?我想念什么吗?
如果是这样,是否有办法立即取消所有内容?
首先,要取消的操作必须明确支持取消。因此,您必须尽力使用代码以某种方式CancellationToken
作为参数来执行某些操作。如果不可能,那么您就没有其他机会了。
这就是为什么这个概念称为合作取消。因为几乎双方都应该意识到取消发生了。客户端应该知道该代码实际上已被取消,对于客户而言,仅知道取消请求是不够的。对于被调用者来说,重要的是要知道为完成其自身而要求取消的事实。
关于在和Close
方法执行时是否取消操作。如果要避免内存泄漏,则必须始终调用清除方法,无论操作是否被取消。当然,我建议您使用将自动执行该清理的语句。stream
reader
using
顺便说一句,要使某些功能可取消,您不必在执行每一行之前检查是否请求取消。您只需要在执行一些长时间运行的操作之前和之后检查是否请求取消即可。如果长期运行的操作支持通过取消标记属性进行取消,则传递取消标记。
另外,您还必须查看副作用。如果您已经产生副作用,即您的方法不准备在退出的途中恢复,这将使您处于不一致状态,请不要取消。
一些通用的代码块可能是这样的:
if(ct.IsCancellationRequested)
{
break; // or throw
}
await DoSomething(ct);
if (ct.IsCancellationRequested)
{
// if there is no side-effect
return; // or throw
// or, we already did something in `DoSomething` method
// do some rollback
}
作为解决方案,您可以使用一些不同的对象,例如HttpClient
或WebRequest
用于执行异步,可等待和可取消的Web请求。您可以查看该链接以获取实施细节。
本文收集自互联网,转载请注明来源。
如有侵权,请联系 [email protected] 删除。
我来说两句