C# 调用包含来自MVC控制器的异步调用的服务的正确模式
我不熟悉在C#中使用TAP和async/wait,所以这里可能有一些不好的代码味道,所以请温柔点。:-) 我有一个如下所示的服务方法:C# 调用包含来自MVC控制器的异步调用的服务的正确模式,c#,asp.net-mvc,asynchronous,async-await,C#,Asp.net Mvc,Asynchronous,Async Await,我不熟悉在C#中使用TAP和async/wait,所以这里可能有一些不好的代码味道,所以请温柔点。:-) 我有一个如下所示的服务方法: public OzCpAddOrUpdateEmailAddressToListOutput AddOrUpdateEmailAddressToList( OzCpAddOrUpdateEmailAddressToListInput aParams) { var result = new OzCpAddOrUpdateEmailAddressTo
public OzCpAddOrUpdateEmailAddressToListOutput AddOrUpdateEmailAddressToList(
OzCpAddOrUpdateEmailAddressToListInput aParams)
{
var result = new OzCpAddOrUpdateEmailAddressToListOutput();
try
{
var mailChimManager = new MailChimpManager(aParams.MailChimpApiKey);
Task<Member> mailChimpResult =
mailChimManager.Members.AddOrUpdateAsync(
aParams.Listid,
new Member
{
EmailAddress = aParams.EmailAddress
});
//Poll async task until it completes.
//Give it at most 8 seconds to do what it needs to do
var outOfTime = DateTime.Now.AddSeconds(8);
while (!mailChimpResult.IsCompleted)
{
if (DateTime.Now > outOfTime)
{
throw new Exception("Timed out waiting for MailChimp API.");
}
}
//Should there have been a problem with the call then we raise an exception
if (mailChimpResult.IsFaulted)
{
throw new Exception(
mailChimpResult.Exception?.Message ??
"Unknown mail chimp library error.",
mailChimpResult.Exception);
}
else
{
//Call to api returned without failing but unless we have
//the email address subscribed we have an issue
if (mailChimpResult.Result.Status != Status.Subscribed)
{
throw new Exception(
$"There was a problem subscribing the email address
{aParams.EmailAddress} to the mailchimp list id
{aParams.Listid}");
}
}
}
catch (Exception ex)
{
result.ResultErrors.AddFatalError(PlatformErrors.UNKNOWN, ex.Message);
}
return result;
}
理想情况下,您应该避免使用
任务
和任务
对象的.Result
和.IsFaulted
属性,这是代码气味的第一位。使用这些对象时,应在整个堆栈中使用async
和wait
。考虑你的服务是这样写的:
public async Task<OzCpAddOrUpdateEmailAddressToListOutput>
AddOrUpdateEmailAddressToList(
OzCpAddOrUpdateEmailAddressToListInput aParams)
{
var result = new OzCpAddOrUpdateEmailAddressToListOutput();
try
{
var mailChimManager = new MailChimpManager(aParams.MailChimpApiKey);
Member mailChimpResult =
await mailChimManager.Members.AddOrUpdateAsync(
aParams.Listid,
new Member
{
EmailAddress = aParams.EmailAddress
});
}
catch (Exception ex)
{
result.ResultErrors.AddFatalError(PlatformErrors.UNKNOWN, ex.Message);
}
return result;
}
将“Async”字后缀到方法中被认为是最佳实践,以表示它是异步的,即
AddorUpdateeMailAddressToListSync
您需要一直执行async
。“隐藏”它总是会导致痛苦的发现——通常是。基本上没有办法解决这个问题。@AlexeiLevenkov但由于我的服务调用没有返回异步句柄等,我应该如何实现这一点。你能根据我的代码给我举个例子吗?你是在服务调用中隐藏它的。您需要等待调用AddOrUpdateAsync
,而不是轮询它-这是一个很大的代码气味。然后您可以使服务方法异步并在控制器中等待它,然后控制器方法就变成var mailChimpResult=wait(平台mailchimpservice.addorUpdateMailAddressToList(…);如果(mailChimpResult.Result==true){}
so仍然隐藏复杂性,除了添加一个word@David谢谢你。在看到你的回复之前,我已经重构了。唯一进一步的增加是使控制器操作也异步。
public async Task<OzCpAddOrUpdateEmailAddressToListOutput>
AddOrUpdateEmailAddressToList(
OzCpAddOrUpdateEmailAddressToListInput aParams)
{
var result = new OzCpAddOrUpdateEmailAddressToListOutput();
try
{
var mailChimManager = new MailChimpManager(aParams.MailChimpApiKey);
Member mailChimpResult =
await mailChimManager.Members.AddOrUpdateAsync(
aParams.Listid,
new Member
{
EmailAddress = aParams.EmailAddress
});
}
catch (Exception ex)
{
result.ResultErrors.AddFatalError(PlatformErrors.UNKNOWN, ex.Message);
}
return result;
}
var mailChimpResult =
await _PlatformMailChimpService.AddOrUpdateEmailAddressToList(
new OzCpAddOrUpdateEmailAddressToListInput
{
EmailAddress = aFormCollection["aEmailAddress"],
Listid = ApplicationSettings.Newsletter.MailChimpListId.Value,
MailChimpApiKey = ApplicationSettings.Newsletter.MailChimpApiKey.Value
});
if (mailChimpResult.Result == true)
{
//So something
}