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;
}

请注意,最好不要使用即发即弃的做法,尤其是当这是应用程序的核心层并且您可能会错过重要的异常时。当您使用此技术时,您必须记住会发生以下情况:

  1. 异常将在没有任何机会捕获它们的情况下默默地失败。通常您会想要记录它们或收到通知。
  2. 您不知道代码何时完成,
  3. 由于您不需要代码来完成并且它可能不会 运行 您不会收到它未能完成的通知。

使用此技术的一个很好的案例场景可能是更新缓存示例。

话虽如此,您可以使用以下技巧:

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 请求取消所以我添加了取消