Ich habe langsam versucht, meinen Code von der Verwendung von Delegaten zu den neuen Aufgaben in meiner WPF-Anwendung zu konvertieren. Ich mag die Tatsache, dass eine abwartende Operation mit der gleichen Methode ausgeführt werden kann, was die Anzahl der benötigten Methoden stark reduziert, die Lesbarkeit verbessert und die Wartung reduziert. Davon abgesehen habe ich beim Aufruf von EF6 Async-Methoden ein Problem mit meinem Code. Sie scheinen alle synchron zu laufen und blockieren meinen UI-Thread. Ich verwende die folgenden Technologien/Frameworks in meinem Code:Entity Framework Async Anruf blockieren UI-Thread
- .NET Framework 4.5
- WPF
- MVVM Licht 5.2
- Allgemeine Arbeitseinheit/Repository-Framework v3.3.5 https://genericunitofworkandrepositories.codeplex.com/
- Entity Framework 6.1.1
- SQL Server 2008 R2 Express
Als Beispiel habe ich ein LogInViewModel mit einem Befehl, der ausgeführt wird, nachdem auf meine WPF-Anwendung geklickt wurde. Hier ist der Befehl, wie im Konstruktor initialisiert:
LogInCommand = new RelayCommand(() => ExecuteLogInCommand());
Hier wird der Befehl Körper:
private async void ExecuteLogInCommand()
{
// Some code to validate user input
var user = await _userService.LogIn(username, password);
// Some code to confirm log in
}
Der Benutzer-Dienst verwendet ein generisches Repository-Objekt, das erstellt wird SimpleIoC Container MVVM Light verwenden. Die LogIn Methode sieht wie folgt aus:
public async Task<User> LogIn(string username, string password)
{
User user = await _repository.FindUser(username);
if (user != null && user.IsActive)
{
// Some code to verify passwords
return user;
}
return null;
}
Und mein Repository Code anzumelden:
public static async Task<User> FindUser(this IRepositoryAsync<User> repository, string username)
{
return await repository.Queryable().Where(u => u.Username == username).SingleOrDefaultAsync();
}
Die SingleOrDefaultAsync() -Aufruf Entity Framework async Anruf ist. Dieser Code blockiert meinen UI-Thread. Ich habe mehrere Artikel von Stephen Cleary und anderen über Async erwarten und ordnungsgemäße Verwendung gelesen. Ich habe versucht, mit ConfigureAwait (falsch) den ganzen Weg nach unten, ohne Glück. Ich habe meinen RelayCommand-Aufruf die Async-erwarten-Schlüsselwörter ohne Glück verwendet. Ich habe den Code analysiert und die Zeile, die am längsten dauert, ist die SingleOrDefaultAsync() Zeile. Alles andere passiert fast augenblicklich. Ich habe das gleiche Problem, wenn ich andere Async-Aufrufe an die DB in meinem Code mache. Das einzige, was es sofort fixiert ist folgendes:
User user = await Task.Run(() =>
{
return _userService.LogIn(Username, p.Password);
});
Aber ich verstehe das nicht nötig sein sollte, da der Anruf ich auf die Datenbank zu machen bin, ist IO gebunden und nicht die CPU gebunden. Also, was ist falsch an meiner Anwendung und warum blockiert sie meinen UI-Thread?
Was genau ist '.Queryable()' auf der Repository-Klasse? Auf was nennst du es? Erbt 'IRepositoryAsync 'von anderen Schnittstellen und was genau ist seine Implementierung? –
Tseng
@Tseng Queriable() gibt nur das zugrunde liegende Benutzer-dbset zurück, auf das Sie einen beliebigen Entity Framework-Methodenaufruf anwenden können. IRepositoryAsync ist die Schnittstelle, die vom Generic Repository/UnitOfWork Framework bereitgestellt wird. Es bietet auch eine EF6-Implementierung. Ich habe keinen Code darin hinzugefügt, weil es umfangreich ist. Ich habe oben den Link bereitgestellt, damit Sie es sich ansehen können, wenn Sie möchten. Vielen Dank! –
Ihr Muster sieht gut aus, einige Empfehlungen: Verkürzen Sie die Syntax bei der Generierung zu 'new RelayCommand'; Sie brauchen nicht den '() =>' Teil. Sie können auch das 'async'- und das' await'-Schlüsselwort in Ihrem Repository-Code entfernen, wenn Sie das zurückgegebene Objekt nicht ändern. Mit dieser kleinen Änderung speichern Sie die Generierung eines in diesem Fall unnötigen Task-Objekts. Für Ihr 'async' Problem: Sie könnten versuchen, die 'Select'-Methode im' IRepositoryAsync <> 'anstelle von' Queryable() 'zu verwenden. –