私はAsp.Net Core Identityを使用しており、ユーザーリストとそのロールをViewModelに投影するコードを単純化しようとしています。このコードは機能しますが、それを単純化しようとすると、私はエラーと好奇心の狂った渦巻きになってしまいました。ここでasync/await insideを使用してください。ラムダを選択してください
が私の作業コードです:コードを単純化しようとして
var allUsers = _userManager.Users.OrderBy(x => x.FirstName);
var usersViewModel = new List<UsersViewModel>();
foreach (var user in allUsers)
{
var tempVm = new UsersViewModel()
{
Id = user.Id,
UserName = user.UserName,
FirstName = user.FirstName,
LastName = user.LastName,
DisplayName = user.DisplayName,
Email = user.Email,
Enabled = user.Enabled,
Roles = String.Join(", ", await _userManager.GetRolesAsync(user))
};
usersViewModel.Add(tempVm);
}
、私はこの (壊れコード)ような何かを行うことができます考え出し:
var usersViewModel = allUsers.Select(user => new UsersViewModel
{
Id = user.Id,
UserName = user.UserName,
FirstName = user.FirstName,
LastName = user.LastName,
DisplayName = user.DisplayName,
Email = user.Email,
Enabled = user.Enabled,
Roles = string.Join(", ", await _userManager.GetRolesAsync(user))
}).ToList();
この私はユーザの前にラムダ式でasyncキーワードを使用していないので、ブレークします。私はユーザー前に非同期を追加行うときしかし、私は
私の推測では、GetRolesAsync()メソッドは、タスクとを返しているということである「非同期ラムダ式は、式ツリーに変換することができません」と言うまた別のエラーを取得しますそのタスクの実際の結果ではなく、ロールに割り当てます。私が私の人生を理解できないように見えるのは、それを働かせる方法です。
私は、運が悪い過去の日に多くの方法を研究し、試しました。
Is it possible to call an awaitable method in a non async method?
https://blogs.msdn.microsoft.com/pfxteam/2012/04/12/asyncawait-faq/
Calling async method in IEnumerable.Select
How to await a list of tasks asynchronously using LINQ?
how to user async/await inside a lambda
How to use async within a lambda which returns a collection
:ここで私が見たいくつかはあります確かに、私は非同期/待機中の仕事を完全に理解していないので、それはおそらく問題の一部です。私のforeachのコードは動作しますが、私はそれが私のやり方で動作するようにする方法を理解できるようにしたいと思います。私はすでにそれに多くの時間を費やしてきたので、これは良い最初の質問になると思いました。
ありがとうございます!
編集
私は私が私が重複した質問としてフラグ付けされないように、このためには研究論文のそれぞれの場合に何をしたか説明する必要があると思います - と私はそれを避けるために本当に懸命に試みました: - /。問題は同じように聞こえるが、結果は一致しない。これらの両方のエラーメッセージが生成
var usersViewModel = allUsers.AsEnumerable().Select(async user => new UsersViewModel
{
Id = user.Id,
UserName = user.UserName,
FirstName = user.FirstName,
LastName = user.LastName,
DisplayName = user.DisplayName,
Email = user.Email,
Enabled = user.Enabled,
Roles = string.Join(", ", await _userManager.GetRolesAsync(user))
}).ToList();
:を「私もそうのようなAsEnumerableを使用してみました
public async Task<ActionResult> Users()
{
var allUsers = _userManager.Users.OrderBy(x => x.FirstName);
var tasks = allUsers.Select(GetUserViewModelAsync).ToList();
return View(await Task.WhenAll(tasks));
}
public async Task<UsersViewModel> GetUserViewModelAsync(ApplicationUser user)
{
return new UsersViewModel
{
Id = user.Id,
UserName = user.UserName,
FirstName = user.FirstName,
LastName = user.LastName,
DisplayName = user.DisplayName,
Email = user.Email,
Enabled = user.Enabled,
Roles = String.Join(", ", await _userManager.GetRolesAsync(user))
};
}
:答えとしてマークされた記事の場合は、私は次のコードを試してみましたInvalidOperationException:前の操作が完了する前に、このコンテキストで2番目の操作が開始されました。どのインスタンスメンバーもスレッドセーフであることは保証されていません。」
この時点では、私のオリジナルのForEachが最良の賭けになるかもしれないようですが、私はまだこれを行う正しい方法が何であるか疑問に思っています。非同期メソッドを使用してそれを実行していた
編集2 - 回答で ツェンのコメントのおかげで(および他のいくつかの研究)私は次のコードを使用して、物事を動作させることができました:。
var userViewModels = allUsers.Result.Select(async user => new UsersViewModel
{
Id = user.Id,
UserName = user.UserName,
FirstName = user.FirstName,
LastName = user.LastName,
DisplayName = user.DisplayName,
Email = user.Email,
Enabled = user.Enabled,
Roles = string.Join(", ", await _userManager.GetRolesAsync(user))
});
var vms = await Task.WhenAll(userViewModels);
return View(vms.ToList());
を今私は誰もが私はSQL Profilerを見て、DBが実際にどれくらいのヒット数を得ているかを調べ始めました。Matt Johnsonが述べたように、N + 1が多いです。
これは私の質問に答えるが、今質問を実行する方法を再考しているだけで、メインビューにその役割をドロップして、各ユーザーが選択されるたびにそれらをプルすることができます。私は間違いなくこの質問を通してたくさんのことを学びました(そして私が知らないものをもっと学んだ)ので、みんなに感謝します。
'私の推測では、GetRolesAsync()メソッドはTaskを返して、そのタスクの実際の結果ではなくRolesに割り当てていると思います。おそらくそうではないでしょう。なぜなら、 'await'がタスクの結果を得るからです。 – mason
'Select'の前に' AsEnumerable'を置くようにしてください。それは、それをEFのための式ツリーに変換するのではなく、オブジェクトにLInqで実行されます。 – juharr
VaRのusersViewModels =は(Task.WhenAll(allUsers.AsEnumerable()を待つ。(非同期ユーザーを選択=>新しいUsersViewModel {ID = user.Id、 ユーザー名= user.UserName、 姓= user.FirstName、 氏名= user.LastName、 のDisplayName = user.DisplayName、 メール= user.Email、 有効= user.Enabled、 役割= string.Join( ""、_userManager.GetRolesAsync(ユーザ)を待つ) })))。 ToList(); –