异步代码误导aspnet身份

时间:2016-01-26 09:29:12

标签: c# async-await c#-5.0

我需要为aspnetidentity实现自定义存储提供程序。 我好好看了一下,发现了不少。但他们似乎对我来说都不对。

我的理解是,如果你的方法以" async"结尾?而不应该是异步的。

参见从某人的代码中获取的示例,这些代码遍布整个地方。

发现以下内容极具误导性,因为它根本不是我所能看到的异步

    public Task<TUser> FindByIdAsync(int userId)
    {
        TUser result = userTable.GetUserById(userId) as TUser;  //this is not async 
        if (result != null)
        {
            return Task.FromResult<TUser>(result);
        }

        return Task.FromResult<TUser>(null);
    }

应该像这样编码吗?:

     public async Task<TUser> FindByIdAsync(int userId)
        {

            TUser result = userTable.GetUserByIdAsync(userId) as TUser;
            if (result != null)
            {
                return await Task.FromResult<TUser>(result);
            }

            return await Task.FromResult<TUser>(null);
        }

    Questions?
  1. 做&#34; Task.FromResult&#34;是否正确?我的意思是&#34; Task.FromResult实际上变成了同步?应该是什么?

  2. 上述代码的正确方法是什么?怎么样configureAwait(false)     async be&#34;一直向下包括datalayer以避免死锁&#34;

  3. 任何示例代码/代码段都将不胜感激

    非常感谢任何反馈

3 个答案:

答案 0 :(得分:3)

代码没有误导性。 ASP.NET Identity框架旨在通过返回$(document).ready(function() { $(".balls").effect('bounce', { times: 3 }, 'slow'); }); 来提供异步接口,并通过在方法名称中添加Task后缀来指示这一点:

Async

但是,底层提供程序可能没有异步方法。在这种情况下,您无法创建异步实现,但仍然必须实现该接口,并且这样做将完全像在您的第一个代码段中那样使用Task<TUser> FindByIdAsync(int userId)

使用同步代码实现异步方法

Task.FromResult

如果你的底层提供者支持异步方法,你应该使用async和await。

使用异步代码实现异步方法

public Task<TUser> FindByIdAsync(int userId)
{
    TUser result = userTable.GetUserById(userId) as TUser;
    return Task.FromResult<TUser>(result);
}

请注意,未使用public async Task<TUser> FindByIdAsync(int userId) { TUser result = (await userTable.GetUserByIdAsync(userId)) as TUser; return result; } 。仅当您使用同步代码创建Task.FromResult并且必须将其转换为异步代码所需的Task.FromResult时,才需要TResult

有时您的基础提供商可以返回所需的Task<TResult>而无需进一步的工作。在这种情况下,您可以删除异步并等待并仍然提供异步实现。这可以使代码更有效:

Task<TUser>

答案 1 :(得分:0)

初始代码绝对不是异步的。它看起来像是采用这种方式来应对API设计。

然而,建议的更改对我来说也不同步。 Task.FromResult只是创建一个包含结果的已完成任务,不会使任何异步或执行任何类型的等待代码,因此您不应等待它。

在您的情况下,假设GetUserByIdAsync返回Task<TUser>,并假设此代码的全部目的(看起来似乎)始终返回已完成的任务(从不出错或取消),这可能被改写为:

public async Task<TUser> FindByIdAsync(int userId)
{
   var tResult = userTable.GetUserByIdAsync(userId);
   TUser result = null;
   try
   {
     result = await tResult;
   } 
   except
   {
     // Bad idea, but here goes to your first snippet
   }
   return Task.FromResult<TUser>(result);
}

注意:这是一个坏主意,因为@PanagiotisKanavos评论说,它隐藏了一个可能出现故障的状态,你不知道你的null结果是否来了没有找到用户,或者是否有错误情况:我会避免它。

如果故障/取消状态有效,则可能只是:

public Task<TUser> FindByIdAsync(int userId)
{
   return userTable.GetUserByIdAsync(userId);
}

答案 2 :(得分:0)

async方法是编译器构建将返回承诺 future 的内容的一种方式。对于.NET Framework和C#,这是Task

await指令需要等待,而Task恰好是一个。它不知道或不关心被调用的方法/操作是否真的是异步的。

Task.FromResult<T>返回一个已完成的任务,如果您在await方法内的async指令中使用它,它将被视为已同步完成并继续执行。

因此,使用asyncawait只调用Task.FromResult<T>最终只会浪费CPU周期和内存,编译器会生成会浪费更多CPU周期和内存的代码在运行时。

由于async方法始终会返回Task,因此我们决定将其隐含以提高可读性并为其提供某种同步感觉。编译会将返回值包装在Task中。这就是为什么您无法直接返回Task.FromResult<TUser>(result)Task.FromResult<TUser>(null)并等待它获取价值的原因。

因此,同步代码的async等价物将是:

 public async Task<TUser> FindByIdAsync(int userId)
 {
    var result = await userTable.GetUserByIdAsync(userId) as TUser;
    if (result != null)
    {
        return result;
    }

    return null;
}

或者:

 public async Task<TUser> FindByIdAsync(int userId)
 {
    return await userTable.GetUserByIdAsync(userId) as TUser;
 }