C# HttpWebRequest ,触发并忘记 API 调用
C # HttpWebRequest , Fire and forget an API call
在我的 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;
}
请注意,最好不要使用即发即弃的做法,尤其是当这是应用程序的核心层并且您可能会错过重要的异常时。当您使用此技术时,您必须记住会发生以下情况:
- 异常将在没有任何机会捕获它们的情况下默默地失败。通常您会想要记录它们或收到通知。
- 您不知道代码何时完成,
- 由于您不需要代码来完成并且它可能不会 运行 您不会收到它未能完成的通知。
使用此技术的一个很好的案例场景可能是更新缓存示例。
话虽如此,您可以使用以下技巧:
NET 4.5 允许我们通过 Task.Run
使用它
Task.Run(() => FireAndForget());
您也可以使用无参数 lambda 启动线程:
(new Thread(() => {
FireAndForget();
}) {
Name = "Running Work Thread (FireAndForget)",
Priority = ThreadPriority.BelowNormal
}).Start();
首先,制作代码的完全异步版本
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 请求取消所以我添加了取消
在我的 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;
}
请注意,最好不要使用即发即弃的做法,尤其是当这是应用程序的核心层并且您可能会错过重要的异常时。当您使用此技术时,您必须记住会发生以下情况:
- 异常将在没有任何机会捕获它们的情况下默默地失败。通常您会想要记录它们或收到通知。
- 您不知道代码何时完成,
- 由于您不需要代码来完成并且它可能不会 运行 您不会收到它未能完成的通知。
使用此技术的一个很好的案例场景可能是更新缓存示例。
话虽如此,您可以使用以下技巧:
NET 4.5 允许我们通过 Task.Run
Task.Run(() => FireAndForget());
您也可以使用无参数 lambda 启动线程:
(new Thread(() => {
FireAndForget();
}) {
Name = "Running Work Thread (FireAndForget)",
Priority = ThreadPriority.BelowNormal
}).Start();
首先,制作代码的完全异步版本
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 请求取消所以我添加了取消