在我的WCF服务中,我必须调用一个API,在那里我想做一个即发即弃的实现。如果可能的话,捕获错误。(如果不是选项,也可以)
我计划做以下的实现,它可能导致什么问题?通过这样做,下面的实现将留下大量打开的连接。或者是什么问题呢?请帮助理解如何以更好的方式实现这一点。
void SendRequest(inputs)
{
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(URL);
request.Method = "POST";
request.ContentType = "application/xml";
byte[] requestBytes = Encoding.UTF8.GetBytes(inputXML);
using (Stream requestStream = request.GetRequestStream())
{
requestStream.Write(requestBytes, 0, requestBytes.Length);
}
request.GetResponseAsync();
}
Main()
{
try
SendRequest(inputs);
catch ex
log ex;
}
首先,制作完全异步版本的代码
using System.Threading;
public async Task<System.Net.WebResponse> SendRequestAsync(
string inputXML, string url, CancellationToken cancellationToken)
{
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
request.Method = "POST";
request.ContentType = "application/xml";
byte[] requestBytes = Encoding.UTF8.GetBytes(inputXML);
// GetRequestStreamAsync is a lightweight operation I assume
// so we don't really need any cancellation
using (Stream requestStream = await request.GetRequestStreamAsync())
{
// Idk if we really need cancellation here, but just in case of big request we might need to
await requestStream.WriteAsync(
requestBytes, 0, requestBytes.Length, cancellationToken);
}
// Close any long-running request
using (cancellationToken.Register(() => request.Abort(), useSynchronizationContext: false))
{
var response = await request.GetResponseAsync();
cancellationToken.ThrowIfCancellationRequested();
return response;
}
}
让我们创建一个async void
方法,但要确保它是安全的。它基本上会以"炒了就忘了"的方式执行;方式。
public async void DoWork(string inputXML, string url, CancellationToken ct)
{
try
{
using(var response = await SendRequestAsync(inputXML, url, ct))
{
var httpResponse = (HttpWebResponse) response;
// Use 201 Created or whatever you need
if (httpResponse.StatusCode != HttpStatusCode.Created)
{
// TODO: handle wrong status code
}
}
}
catch (Exception e)
{
if (ct.IsCancellationRequested)
{
Console.WriteLine("Cancelled");
}
else
{
// TODO: handle exception
}
}
}
private static CancellationTokenSource _cts = new CancellationTokenSource();
public static void Main (string[] args)
{
DoWork("xml string", "example.com", cts.Token);
Console.WriteLine("Boom!");
if (Console.ReadLine() == "exit")
{
// Cancel the damn job
cts.Cancel();
}
}
从DoWork
内部处理所有错误是很重要的,因为下面的操作将不起作用
// Warning, will NOT catch an exception
public static void Main (string[] args)
{
try
{
DoWork("xml string", "example.com");
}
catch (Exception e)
{
}
}
编辑: OP请求取消,所以我添加了取消
请注意,不使用即发即忘并不是最佳实践,特别是当这是应用程序的核心层时,您可能会错过重要的异常。当您使用此技术时,您必须记住以下情况:
- 异常将静默失败,没有任何机会捕获它们。通常你会想要记录它们或者得到一个通知。
- 你不知道代码什么时候完成,
- 因为你不需要代码来完成,它可能不会运行到你将没有通知,它未能完成
使用此技术的一个很好的场景可能是更新一个示例的缓存。
话虽如此,你可以使用以下技巧:
. NET 4.5允许我们通过Task.Run
Task.Run(() => FireAndForget());
你也可以用无参数的lambda:
来启动一个线程(new Thread(() => {
FireAndForget();
}) {
Name = "Running Work Thread (FireAndForget)",
Priority = ThreadPriority.BelowNormal
}).Start();