![](/img/trans.png)
[英]ASP.NET Web API 2 Async action methods with Task.Run performance
[英]Task.Run() in .NET web API Controller / PayPal IPN
我正在我的 .NET Core Web API 中實現 PayPal Instant Payment Notifcation (IPN),而 PayPal 的參考實現使用 Web API 控制器中的 Task.Run()。
Visual Studio 為該調用提供了一個綠色波浪下划線,並帶有提示,即不等待該調用。 這是在這種特殊情況下使用的,因為這是 PayPal 工作流程所要求的。
[HttpPost]
public async Task<IActionResult> Receive()
{
IPNContext context = new IPNContext()
{
IPNRequest = Request
};
using (var ms = new StreamReader(context.IPNRequest.Body))
{
context.RequestBody = await ms.ReadToEndAsync();
}
//Fire and forget verification task
Task.Run(() => VerifyTask(context)); // Send back the same IPN-message with added "_notify-validate"-parameter and then continue to process from there
//Reply back a 200 code
return Ok();
}
private void VerifyTask(IPNContext ipnContext)
{
try
{
var verificationRequest = WebRequest.Create("https://www.sandbox.paypal.com/cgi-bin/webscr");
//Set values for the verification request
verificationRequest.Method = "POST";
verificationRequest.ContentType = "application/x-www-form-urlencoded";
//Add cmd=_notify-validate to the payload
string strRequest = "cmd=_notify-validate&" + ipnContext.RequestBody;
verificationRequest.ContentLength = strRequest.Length;
//Attach payload to the verification request
using (StreamWriter writer = new StreamWriter(verificationRequest.GetRequestStream(), Encoding.ASCII))
{
writer.Write(strRequest);
}
//Send the request to PayPal and get the response
using (StreamReader reader = new StreamReader(verificationRequest.GetResponse().GetResponseStream()))
{
ipnContext.Verification = reader.ReadToEnd();
}
}
catch (Exception exception)
{
_logger.LogDebug($"IPN-REQUEST::VerifyTask::ERROR => {exception.Message}");
}
ProcessVerificationResponse(ipnContext); // That is my internal processing of the Event
}
所以我的問題是:
此致
不,這不是一個好的做法,因為未等待的任務(如您所寫的)會在沒有正確的上下文來處理調用方法時處理異常或失敗的情況下觸發並忘記。 所以在你的情況下,消費者只是收到一個OK
(200),所以從他的角度來看,一切都很好。 這實際上取決於您的工作流程(尤其是IPNContext
正在做什么)。 我個人希望Accepted
(202),如果你做了一個火並忘記並給消費者另一個 Api 來查詢我認為的狀態,那么它就可以了。
您當然可以通過簡單地編寫以下代碼來欺騙 Visual Studio: _ = Task.Run(...)
更好的解決方案是await
Visual Studio 推薦您的任務。 我不知道為什么在 PayPal 示例中缺少await
的背景,但也許只是問他們。
Imo 未等待的Task
總是看起來像代碼異味,因為方法調用方無法進行正確的異常/失敗處理。
首先,我想說所有 API 代碼示例都應該謹慎對待。 即使對於大公司,通常也只有一個小團隊(或一個人)必須維護六種(或更多)語言的代碼示例。 在這種情況下,根本不可能擁有高質量的 API 代碼示例(或客戶端庫,就此而言)。
在這種情況下,示例代碼存在幾個問題:
WebRequest
實際上在代碼中。Task.Run
在 ASP.NET 上運行。 如果 PayPal 工作流可以處理它,您可以完全刪除Task.Run
。
如果 PayPal 工作流需要離線處理,那么正確的解決方案是使用分布式架構。 即,將請求參數保存在一個可靠的隊列(Azure 存儲隊列 / Amazon SQS / 本地磁盤隊列)中,並有一個獨立的處理器(Azure Function / Amazon Lambda / ASP.NET Core Worker)從隊列中讀取並發送向 PayPal API 發出請求。 希望使用比WebRequest
更現代的東西。
我所說的“適當的解決方案”比適合代碼示例的要復雜得多。 這是代碼示例通常更多地是關於“這里是如何調用此 API”,而不是“這是您的代碼應該如何顯示”的另一個原因。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.