链接Task.Factory.FromAsync和ContinueWith vs.等待

时间:2013-09-20 15:53:51

标签: c# asp.net-mvc-4 task-parallel-library async-await

考虑一个MVC4 / NET 4.5异步操作方法,该方法有两个IO绑定的有序操作,这两个操作都遵循IAsyncResult模式。下面我使用System.DirectoryServices.Protocols命名空间创建了一个简单的示例。虽然我长期以来一直是.NET中TPL和其他异步模型的粉丝(以及像node.js这样的回调模型),但我终于开始异步/等待了。

如'await'所示,它会返回正确的结果,但是我一直对使用.ContinueWith和Task.Factory.FromAsync获得相同结果的方式感到困惑,后者有效地减轻了混乱的代码处理IAsyncResult或语法混乱的回调。

也许我的示例代码已经以最佳方式处理了事情? .ContinueWith似乎是更惯用的方法(或者是它?)但我找不到任何方法将新任务链接为延续;一个Func延续不会在没有下放的情况下将其删除。

public async Task<ActionResult> AjaxStuff()
    {
        var c = new LdapConnection(string.Empty);

        var t1 = Task.Factory.FromAsync<string>(
            c.BeginSendRequest(new SearchRequest(string.Empty, "(&(objectClass=*))", SearchScope.Base, "defaultNamingContext"), PartialResultProcessing.NoPartialResultSupport, null, null),
            iar =>
            {
                return ((SearchResponse)c.EndSendRequest(iar)).Entries[0].Attributes["defaultNamingContext"][0].ToString();
            });

        var nc = await t1;

        var t2 = Task.Factory.FromAsync<string>(
            c.BeginSendRequest(new SearchRequest(nc, "(&(givenName=steve))", SearchScope.Subtree), PartialResultProcessing.NoPartialResultSupport, null, null),
            iar =>
            {
                var result = (SearchResponse)c.EndSendRequest(iar);
                return result.Entries.Count > 0 ? result.Entries[0].DistinguishedName : "no such thing";
            });

        return this.PartialView("AjaxStuff", await t2);
    }

1 个答案:

答案 0 :(得分:8)

await肯定会产生比ContinueWith更清晰的代码。

也就是说,没有指定的回调就更容易使用FromAsync。我也更喜欢用简单的扩展方法包装FromAsync

public static Task<DirectoryResponse> SendRequestAsync(this LdapConnection c, DirectoryRequest request, PrtialResultProcessing partialMode)
{
    return Task.Factory<DirectoryResponse>.FromAsync(c.BeginSendRequest, c.EndSendRequest, request, partialMode, null);
}

然后你可以这样使用:

public async Task<ActionResult> AjaxStuff()
{
    var c = new LdapConnection(string.Empty);

    var result1 = await c.SendRequestAsync(new SearchRequest(string.Empty, "(&(objectClass=*))", SearchScope.Base, "defaultNamingContext"), PartialResultProcessing.NoPartialResultSupport);
    var nc = ((SearchResponse)result1).Entries[0].Attributes["defaultNamingContext"][0].ToString();

    var result2 = (SearchResponse)(await c.SendRequestAsync(new SearchRequest(nc, "(&(givenName=steve))", SearchScope.Subtree), PartialResultProcessing.NoPartialResultSupport)));
    var dn = result2.Entries.Count > 0 ? result2.Entries[0].DistinguishedName : "no such thing";

    return this.PartialView("AjaxStuff", dn);
}

通过简化您的FromAsync代码,您可以将所有逻辑移动到单个方法中,await使其更具可读性。