在Controller Action中进行异步调用

时间:2014-12-08 21:42:51

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

我有一个控制器操作,它获取文档类型列表,然后为每个文档类型进行Web服务调用。我想立刻制作这些,所以循环它们只需要最长的一个。我不知道我的代码是否正确,我还需要做其他事情,或者我的代码是不正确的。

动作:

public ActionResult GetPlan(MemberViewModel request)
{
    DocService ds = new DocService();

    List<DocType> docTypes = ds.GetDocTypesForPlan(request.PlanId);

    List<CoverageDocument> coverageDocuments = ds.GetDocumentsForDocTypes(docTypes);

    return View(coverageDocuments);
}

GetDocumentsForDocTypes:

public List<CoverageDocument> GetDocumentsForDocTypes(List<DocType> planDocTypes)
{
    List<CoverageDocument> planDocuments = new List<CoverageDocument>();

    DocumentUtility documentUtility = new DocumentUtility();
    int lastYear = DateTime.Now.Year - 1;

    planDocTypes.ForEach(async (docType) =>
    {
        DocumentUtility.SearchCriteria sc = new DocumentUtility.SearchCriteria();
        sc.documentType = docType;
        Dictionary<long, Tuple<string, string>> documentList = await documentUtility.FindDocuments(sc);

        documentList.ToList().ForEach((document) =>
            {
                CoverageDocument doc = this.coverageDocumentConstructor(document);
                planDocuments.Add(doc);
            });
    });

    return planDocuments;
}

例外:

  

附加信息:无法启动异步操作   这次。异步操作只能在一个内部启动   异步处理程序或模块或在页面中的某些事件期间   生命周期。如果在执行页面时发生此异常,请确保   页面标记为&lt;%@ Page Async =“true”%&gt;。这个例外可能   还表示尝试调用“异步void”方法,即   通常在ASP.NET请求处理中不受支持。相反,   异步方法应该返回一个Task,并且调用者应该等待   它

1 个答案:

答案 0 :(得分:6)

您的代码不正确。通过向ForEach扩展方法发送异步lambda,您强制它为async void,这在UI事件处理程序之外永远不是一个好主意。

要实际上是异步的,您的呼叫需要始终保持异步:

public async Task<ActionResult> GetPlan(MemberViewModel request)
{
    DocService ds = new DocService();

    List<DocType> docTypes = ds.GetDocTypesForPlan(request.PlanId);

    List<CoverageDocument> coverageDocuments = await ds.GetDocumentsForDocTypesAsync(docTypes);

    return View(coverageDocuments);
}

public async Task<List<CoverageDocument>> GetDocumentsForDocTypesAsync(List<DocType> planDocTypes)
{
    DocumentUtility documentUtility = new DocumentUtility();
    int lastYear = DateTime.Now.Year - 1;

    var planDocuments = await Task.WhenAll(planDocTypes.Select(async (docType) =>
    {
        DocumentUtility.SearchCriteria sc = new DocumentUtility.SearchCriteria();
        sc.documentType = docType;

        return await documentUtility.FindDocuments(sc).Select((document) => this.coverageDocumentConstructor(document))
    }));

    return planDocuments.SelectMany(doc => doc);;
}