Mit async / await-innen .Wählen Sie lambda

Ich bin mit Asp.Net Kern-Identität und versucht, etwas zu vereinfachen-code, dass die Projekte eine Liste der Benutzer und Ihre Rollen zu einem ViewModel. Dieser code funktioniert, aber beim Versuch, um es zu vereinfachen habe ich gegangen in eine verrückte Spirale von Fehlern und Neugier.

Hier mein funktionierenden code:

        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);
        }

Versuchen, den code vereinfachen, dachte ich, ich könnte so etwas tun
(broken code):

        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();

Diese Pausen, weil ich bin nicht mit dem async-Schlüsselwort in der lambda-Ausdruck vor Benutzer. Wenn ich jedoch hinzufügen, async, bevor Benutzer, ich bekomme aber eine andere Fehlermeldung, die sagt "Asynchrone lambda-Ausdrücke können nicht konvertiert werden, um die expression trees"

Meine Vermutung ist, dass die GetRolesAsync () - Methode ist wieder eine Aufgabe und die Zuordnung zu Rollen, statt der eigentlichen Ergebnisse von dieser Aufgabe. Was kann ich nicht scheinen, um herauszufinden, für das Leben von mir ist, wie es funktioniert.

Habe ich recherchiert und versucht, viele Methoden, die über den vergangenen Tag ohne Glück. Hier sind ein paar, die ich sah:

Ist es möglich, den Anruf zu einem erwartbaren Methode in einer nicht-async-Methode?

https://blogs.msdn.microsoft.com/pfxteam/2012/04/12/asyncawait-faq/

Aufruf der asynchronen Methode in IEnumerable.Wählen Sie

Wie zu erwarten, eine Liste von Aufgaben asynchron mit LINQ?

wie Benutzer async/await innerhalb eines lambda

Wie zu verwenden async innerhalb eines lambda gibt eine Sammlung

Zugegeben, ich verstehe nicht ganz, wie async /await-Arbeit, also das ist wohl Teil des Problems. Meine foreach-code funktioniert, aber ich möchte in der Lage sein zu verstehen, wie es funktioniert die Weise, die ich versuche zu. Da hab ich verbrachte so viel Zeit auf die es schon habe, dachte ich es wäre eine gute erste Frage.

Dank!

Bearbeiten

Ich denke, ich muss erklären, was ich in jedem Fall von den Artikeln, die ich recherchiert, damit diese nicht gekennzeichnet werden als eine doppelte Frage - und ich versuchte wirklich hart, um zu vermeiden, dass :-/. Während die Frage klingt ähnlich, sind die Ergebnisse nicht. Im Fall der Artikel, die markiert war, als Antwort habe ich versucht den folgenden code:

    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))
        };
    }

Ich auch versucht, mit Hilfe AsEnumerable etwa so:

    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();

Beide produzieren die Fehlermeldung: "InvalidOperationException: Eine zweite operation gestartet, die auf diesem Zusammenhang vor einer früheren operation abgeschlossen ist. Jede Instanz, die Mitglieder sind nicht garantiert, um thread-sicher."

In diesem Punkt scheint es, wie mein original-ForEach ist vielleicht die beste Wette, aber ich bin immer noch am Rätseln, was der richtige Weg wäre, um dies zu tun, wenn ich mit den async-Methoden.

Edit 2 - mit Antwort
Dank Tseng-Kommentare (und einige andere Forschungs -) ich war in der Lage, um die Dinge funktionieren mit dem folgenden code:

        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());

Obwohl jetzt, dass ich teilgenommen habe, alle Kommentare berücksichtigt, suchte ich näher an die SQL Profiler-nur um zu sehen wie viele hits die DB ist eigentlich immer - wie Matt Johnson erwähnt, dass es eine Menge ist (N+1).

So, während diese beantworten meine Frage, ich bin nun überdenken, wie die Abfrage ausgeführt, und kann nur ablegen der Rollen in der Hauptansicht und nur ziehen Sie für jeden einzelnen Benutzer ausgewählt ist. Ich habe definitiv viel gelernt durch diese Frage, obwohl (und mehr gelernt, was ich nicht weiß), also danke an alle.

  • My guess is that the GetRolesAsync() method is returning a Task and assigning it to Roles instead of the actual results of that task. - wahrscheinlich nicht, weil await greifen, das Ergebnis der Aufgabe.
  • Versuchen Sie, eine AsEnumerable vor der Select so wird es laufen in LInq to Objects, anstatt zu versuchen, es zu konvertieren, um einen Ausdruck-Baum für EF oder was auch immer Anbieter, die Sie verwenden.
  • var usersViewModels = (await Task.WhenAll(allUsers.AsEnumerable().Wählen Sie(async user => neue UsersViewModel { Id = = user.Id, UserName = user.Benutzername, Vorname = user.FirstName, LastName = user.Nachname, DisplayName = user.DisplayName, E-Mail = user.E-Mail Enabled = Benutzer aus.Aktiviert, Rollen = string.Join(", ", erwarten _userManager.GetRolesAsync(user)) }))).ToList();
  • Damit leisten Sie einen Anruf, um alle Benutzer, und klicken Sie dann für jeden Benutzer eine separate Anruf bekommen Ihre Rollen. Dies ist die bekannte anti-pattern namens "Wählen Sie" N+1" (Google/Bing it). Sollten Sie wirklich nicht tun. Was passiert, wenn 10.000 Benutzer? Tun Sie wirklich wollen, um 10,001 Datenbank-Aufrufe?
  • Mögliche Duplikate von: Multi-async in Entity Framework 6?
  • Im wesentlichen, da GetRolesAsync anscheinend läuft auch etwas auf den Kontext der Datenbank, können Sie nicht mehrere parallel GetRolesAsync Anrufe. Sie würde ausführen müssen, die Sie in der Folge. Als pro Matt Johnson ' s Kommentar, Sie sollten einen Weg, um Abfragen an mehrere (alle) Benutzer-Rollen auf einmal, wenn Sie Sie wirklich brauchen. – btw. Ihre ursprüngliche Frage völlig neben der entsprechenden Teile von dem, was Sie versucht haben, mit diesen verknüpfte Fragen, und jetzt haben Sie bearbeitet, die in, es ist mir nicht klar, warum Sie nicht die Suche nach der Fehlermeldung.
  • Vielen Dank für das feedback, jeder. Natürlich will ich nicht haben, ein db-Aufruf an alle user, deshalb war ich versucht, dies zu beheben, in den ersten Platz. Ich verließ die EF6-link, weil ich gerannt bin EF7 - und da EF7 ist eine komplette Neuentwicklung von Entity Framework war ich nicht sicher, dass es relevant war. Ich weiß, ich könnte einfach schreiben Sie diese Abfrage mit der db-Kontext, aber die beste Praxis ist immer gegeben, die Identität Methoden zur Verfügung gestellt, das ist es, was ich versuche zu tun. Vielleicht ist dies für EF7 / Identität. Ich halte tuckern entlang - zumindest ich bin nicht in Eile. Danke.
  • Wenn Sie nicht wissen, was EF ist mithilfe von expression trees für, die Sie wissen müssen. EF ist eine große Magische box, wo Sie Daten, aber wenn Sie nicht wissen, wie die Magie funktioniert, Sie am Ende opfern Sie Ihre Katze für keinen wirklichen Grund.

InformationsquelleAutor FranksBrain | 2016-09-15
Schreibe einen Kommentar