0

在我的 WCF 服务中,我必须调用一个 API,我想在其中执行 Fire and Forget 实现。如果可能的话,只要捕获错误(如果有的话)。(这也很好,如果不是一个选项)

我计划进行以下实施,它可能导致什么问题?通过执行以下实现将留下大量打开的连接。或者可能是什么问题?请帮助理解如何以更好的方式实现这一点。

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

2 回答 2

0

请注意,最好不要使用即用即忘,特别是如果这是应用程序的核心层,您可能会错过重要的例外情况。当您使用此技术时,您必须记住会发生以下情况:

  1. 异常将默默地失败,没有任何机会抓住它们。通常你会想要记录它们或收到通知。
  2. 你不知道代码何时完成,
  3. 由于您不需要完成代码并且它可能无法运行,因此您不会收到无法完成的通知。

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

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

NET 4.5 允许我们通过Task.Run

Task.Run(() => FireAndForget());

您还可以使用无参数 lambda 启动线程:

(new Thread(() => { 
 FireAndForget(); 
 }) { 
   Name = "Running Work Thread (FireAndForget)",
   Priority = ThreadPriority.BelowNormal 
}).Start();
于 2021-10-27T18:33:31.867 回答
0

首先,制作代码的完全异步版本

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

从内部处理所有错误很重要 a DoWork,因为以下将不起作用

// Warning, will NOT catch an exception
public static void Main (string[] args)
{
    try 
    {
        DoWork("xml string", "example.com"); 
    }
    catch (Exception e)
    {
    }
}

编辑: OP 要求取消,所以我添加了取消

于 2021-10-27T18:58:57.307 回答