C# 调用包含来自MVC控制器的异步调用的服务的正确模式

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

我不熟悉在C#中使用TAP和async/wait,所以这里可能有一些不好的代码味道,所以请温柔点。:-)

我有一个如下所示的服务方法:

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
 }