c# - 如何使用 linq 进行异步

标签 c# asp.net asp.net-mvc linq asynchronous

我正在尝试使用 asp.net mvc 制作我的第一个 Web 应用程序,包括使用 linq 的远程数据库。所以我使用来自 mvc 的默认模板,我在 AccountController 中重新制作代码,使用 linq 实现注册用户,现在我很感兴趣用异步来做。那么是否可以用异步处理linq?如果是,请告诉我如何做,这对我很有帮助。这是我通过 linq 注册的示例:

[AllowAnonymous]
public ActionResult Register()
{
    return View();
}

//
// POST: /Account/Register
[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
public ActionResult Register(RegisterViewModel model)
{
    if (ModelState.IsValid)
    {
        using (DataBaseClassDataContext dc = new DataBaseClassDataContext())
        {
            Users tbUsers = new Users();
            tbUsers.Login = model.Login;
            tbUsers.Name = model.Name;
            tbUsers.Surname = model.Surname;
            tbUsers.Password = model.Password;
            tbUsers.E_Mail = model.Email;
            tbUsers.Knowledge = model.Knowledge;
            dc.Users.InsertOnSubmit(tbUsers);
            dc.SubmitChanges();

            ModelState.Clear();
            ViewBag.Message = "Successfully Registration Done";
        }
    }

    // If we got this far, something failed, redisplay form
    return View(model);
}

最佳答案

让我们先看看你的第一个 Action :

[AllowAnonymous]
public ActionResult Register()
{
  return View();
}

好吧,这里没有做任何会延迟当前线程的事情,所以异步做任何事情都没有好处,所以最好的办法就是不理会这个。

现在,让我们看看您的第二个操作。它包含:

dc.SubmitChanges();

在将更改发送到数据库时,这确实会阻塞当前线程。它可能不会大受欢迎,但它是我们可能从使用异步代码中获益的地方,尤其是因为如今它非常容易实现。

首先更改签名:

public async Task<ActionResult> Register(RegisterViewModel model)

如果你现在编译它会工作,但你会得到一个警告:

 This async method lacks 'await' operators and will run synchronously. Consider using the 'await' operator to await non-blocking API calls, or 'await Task.Run(...)' to do CPU-bound work on a background thread.

但是我们已经做了两件事:

  1. 从返回中更改 ActionResult返回 Task<ActionResult> .
  2. 用过async这意味着我们可以做 return View(model);它变成了实际返回 Task<ActionResult> 的代码运行时将运行您原始方法中的代码。

但实际上我们并没有得到任何东西。然而,而不是 dc.SubmitChanges()我们将使用 dc.SubmitChangesAsync() .

这是假设它存在,这将取决于您的数据提供者。稍后会详细介绍。

如果它确实存在则不返回 void或一些值 T它会返回 TaskTask<T> .

我们可以自己编写代码来处理该任务,但最简单的做法是:

await dc.SubmitChangesAsync();

现在我们拥有的方法是返回一个 Task<Action>当最初Run (MVC 将为我们处理那部分)将执行代码直至 await。 .然后它会释放运行代码的线程去做其他事情。 SubmitChangesAsync之后已完成其工作,该方法的执行将在此时恢复。

类似地,我们可以将方法转换为:

var someList = someQuery.ToList();

进入:

var someList = await someQuery.ToListAsync();

现在,正如我所说,这一切都取决于导致数据库访问实际上具有异步版本的方法。如果没有SubmitChangesAsync()那么要么你必须放弃这种方法(嘘!),要么你必须编写自己的实现(不是微不足道的)。

当前版本的 EntityFramework 提供了以下内容:

AllAsync
AnyAsync
AverageAsync
ContainsAsync
CountAsync
FirstAsync
FirstOrDefaultAsync
ForEachAsync
LoadAsync
LongCountAsync
MaxAsync
MinAsync
SingleAsync
SingleOrDefaultAsync
SumAsync
ToArrayAsync
ToDictionaryAsync
ToListAsync
SaveChangesAsync

也就是说,几乎所有导致实际数据库访问的方法都有一个 Async版本。

如果您没有使用提供此功能的提供程序,那么转向异步代码并不容易;它涉及的不仅仅是快速回答才能做好。

最后一个警告。假设你有一个 async总是执行单个 await 的方法那await是尾调用:

public async Task<List<int>> GetList(int typeID)
{
  if(typeID < 1)
    throw new ArgumentOutOfRangeException();
  return await (from stuff in place where stuff.TypeID == typeID select stuff).ToListAsync();
}

这里你不应该使用asyncawait完全没有,因为你正在创建一个任务,它总是会导致等待一个任务,所以额外的 await无缘无故地使幕后的事情复杂化。在这里你应该只返回任务:

public Task<List<int>> GetList(int typeID)
{
  if(typeID < 1)
    throw new ArgumentOutOfRangeException();
  return (from stuff in place where stuff.TypeID == typeID select stuff).ToListAsync();
}

但请注意,在 using 中看起来像尾调用的东西 block 并不是真正的尾调用,因为它也隐含地执行了 Dispose()using 的末尾,因此您不能以这种方式简化此类调用。

您可以简化存在不同可能的尾调用的情况,只要每条路径都执行这样的调用或抛出异常:

public async Task<List<int>> GetList(int? typeID)
{
  if(!typeID.HasValue)
    throw new ArgumentNullException();
  if(typeID.Value < 0)
    return await (from stuff in place).ToListAsync();
  return await (from stuff in place where stuff.TypeID == typeID select stuff).ToListAsync();
}

可以变成:

public Task<List<int>> GetList(int? typeID)
{
  if(!typeID.HasValue)
    throw new ArgumentNullException();
  if(typeID.Value < 0)
    return (from stuff in place).ToListAsync();
  return (from stuff in place where stuff.TypeID == typeID select stuff).ToListAsync();
}

关于c# - 如何使用 linq 进行异步,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30260716/

相关文章:

c# - Controller 中的 "The entity or complex type cannot be constructed in a LINQ to Entities query"

c# - 外键引用对象返回 null

c# - 异步任务给出警告,(没有)异步任务给出错误

javascript - 如何从 MVC 中的 Javascript 代码将值传递到 Controller

c# - 如何让 BigInteger 正确地看到这个十六进制字符串的二进制表示?

c# - 如果嵌套语句的执行取决于第一个语句的结果,我该如何嵌套异步语句?

c# - ASP.NET 页面上的打印按钮

asp.net - 使用 ASP.Net GridView 排序和分页

c# - Json.NET 序列化中有没有办法区分 "null because not present"和 "null because null"?

asp.net-mvc - 在 Visual Studio 2015 RC 中添加 View