如何告诉失败的方法调用参数值?

时间:2016-10-12 17:44:23

标签: c# asynchronous async-await task

我有List<Task<searchDataResponse>>,其中包含约30个条目。调试此列表时,我无法确定30个条目中的哪个是特定条目。

如何确定任务集合中特定任务的方法调用(包括输入参数值)?

示例代码:

var tasks = new List<Task<searchDataResponse>>();

for (var i = 0; i < 30; i++)
{
    // GET DATE OF N DAYS PAST (UP TO 30)
    var searchDate = DateTime.Now.AddDays(i * -1);

    // CALL WEB SERVICE WITH A SPECIFIC DATE
    var dateSpecificTask = wsClient.searchDataAsync(searchDate);

    // ADD TASK TO LIST OF TASKS
    tasks.Add(dateSpecificTask);
}

try
{
    Task.WaitAll(tasks.ToArray());
}
catch (AggregateException ae)
{
    // SET ALL EXCEPTIONS AS HANDLED
    ae.Handle(x => { return true; }); 
}

// GET LIST OF FAILED TASKS
var failedTasks = tasks.Where(x => x.Status == TaskStatus.Faulted).ToList();

// IDENTIFY FAILED TASKS - TRY TO IDENTIFY WHICH DATE SUPPLIED TO WEB SERVICE FAILED.
foreach (var failedTask in failedTasks)
{
    var failedMethod = failedTask.MethodSignature;   //<----  here is what i want to do.  Property 'MethodSignature' does not exist - this is merely an example of what I am attempting to do.
}

更新 - 一些评论表明人们对使用“方法签名”这一短语感到胃灼热。我所说的方法签名实际上是方法签名,包括输入参数值。因此,我更改了问题标题,以更准确地反映我所寻求的内容。我的例子很简单。它并不反映我的现实问题。但我的问题仍然是 - 在查看失败任务列表时,如何确定作为任务一部分调用的实际方法。我似乎找不到任务的任何属性来描述导致失败的方法。

3 个答案:

答案 0 :(得分:2)

var operations = Enumerable.Range(0, 30)
 .Select(i => {
     // GET DATE OF N DAYS PAST (UP TO 30)
    var searchDate = DateTime.Now.AddDays(i * -1);

    // CALL WEB SERVICE WITH A SPECIFIC DATE
    var dateSpecificTask = wsClient.searchDataAsync(searchDate);

    return new { i, searchDate, dateSpecificTask };
}.ToList();

Task.WaitAll(operations.ConvertAll(x => x.dateSpecificTask));

var failed = operation.Where(x => x.dateSpecificTask.State == Faulted).ToList();

failed列表中,您现在拥有所有日期和索引。

答案 1 :(得分:1)

如果您希望能够将日期传递给失败的任务,您可以将日期和任务存储在集合中(而不仅仅是现在的任务)。

为什么不使用中间类,例如有两个成员(日期,任务)?

答案 2 :(得分:1)

在您发布的代码中,我发现了一些差异,我认为这些差异源于Async-Await的使用尚未被充分了解的事实,让我提出几个重要方面,然后再提出建议替代解决方案:

wsClient.searchDataAsync(searchDate)的来电不是awaited,这违反了Async来电的目的,因为这会使其成为阻止Synchronous来电,尽管您正在汇总所有Async中的Task List来电稍后等待,但仍然阻止,并且不会释放通话线程

代码修改:

  1. await wsClient.searchDataAsync异步调用,肯定需要成为async方法的一部分

    for (var i = 0; i < 30; i++)
    {
      // GET DATE OF N DAYS PAST (UP TO 30)
        var searchDate = DateTime.Now.AddDays(i * -1);
    
     // CALL WEB SERVICE WITH A SPECIFIC DATE
      var dateSpecificTask = await wsClient.searchDataAsync(searchDate);
    
    // ADD TASK TO LIST OF TASKS
      tasks.Add(dateSpecificTask);
    }
    
  2. 等待任务集合Task.WhenAll而不是WaitAll,因为除了没有Ui上下文的控制台应用程序,WaitAll具有死锁范围

  3. 修改代码如下:

    return await Task.WhenAll(tasks)返回值为Task<searchDataResponse[]>,因为所有调用都具有相同的返回类型searchDataResponse

    1. 现在问题的关键,如何获取失败的任务,尽管在上面的问题中已经接受,你可以创建一个包含Task和其他值的包装器,从而映射它们,但为什么不添加所有相关的searchDataResponse返回类型中的详细信息,您尚未发布其架构,可以添加和更新失败状态,然后从Task<searchDataResponse[]>方法返回的Async更新而你所需要的只是:
    2. 打开结果Task<searchDataResponse[]>,获取searchDataResponse[],您可以获得所有失败/通过详细信息。

      要解包,ASP.Net项目有多种方式:

      • 创建完整的调用链Async,它会自动解包最终解析最顶层调用者的结果

      对于控制台应用程序,请使用以下内容:

      searchDataResponse [] results = Task.WhenAll(<returned searchDataResponse taskList>).ConfigureAwait(false).GetAwaiter().GetResult();