Willkommen auf myCSharp.de! Anmelden | kostenlos registrieren
 | Suche | FAQ

Hauptmenü
myCSharp.de
» Startseite
» Forum
» Suche
» Regeln
» Wie poste ich richtig?

Mitglieder
» Liste / Suche
» Wer ist online?

Ressourcen
» FAQ
» Artikel
» C#-Snippets
» Jobbörse
» Microsoft Docs

Team
» Kontakt
» Cookies
» Spenden
» Datenschutz
» Impressum

  • »
  • Community
  • |
  • Diskussionsforum
Wie entwickelt man eine MMVM Anwendung, wenn Tasks abhängig von Tasks sind?
JimStark
myCSharp.de - Member

Avatar #dOpLzh7hN1az1g0eGRc0.jpg


Dabei seit:
Beiträge: 225

Themenstarter:

Wie entwickelt man eine MMVM Anwendung, wenn Tasks abhängig von Tasks sind?

beantworten | zitieren | melden

Hi Leute,

bisher dachte ich die sauberste und einfachste Benutzung von Tasks in WPF ist z.B.:


// Beispiel Command an Button gebunden:
public async void AddCustomerExecute(){
   await AddCustomer(...);
...
}

Also dass die Oberfläche weiterläuft und auf die Beendigung wartet. Ich verstehe nur nicht ganz wie man die Anwendung am besten entwirft wenn Tasks abhängig von Tasks sind.

Beispiel:


public async void AddCustomerExecute(){
   await AddCustomeViewModel(...);
...
}

public Task AddCustomerViewModel(...){
// in dieser Funktion werden mehrere Tasks ausgeführt.
// async ohne Task sollte es so aussehen:
var result = await GetResults(...);
...
await AddCustomerToDb(...);
}

// Diese Funktion ist vorgegeben:
public Task AddCustomerToDb(...){
}

Wie gestalte ich nun die AddCustomerViewModel() Funktion, da ich ja z.B. in einem Task.Run( () => {...}) kein await nutzen kann? Mit Wait() und Result,.. ?

Ich hoffe man versteht was ich meine Und wo ist eigentlich Abt?
Dieser Beitrag wurde 1 mal editiert, zum letzten Mal von JimStark am .
private Nachricht | Beiträge des Benutzers
Papst
myCSharp.de - Experte



Dabei seit:
Beiträge: 350
Herkunft: Kassel

beantworten | zitieren | melden

eine async Methoden ohne Rückgabewerte (void) können zu Race conditions führen. Nutze besser async Methoden, die einen Task zurückgeben.

Du kannst auch in einer inline Funktion await nutzen, in dem du diese als async markierst.


var func = async () => {
  await ...;
  await ...;
}

await func;

Je nachdem, was du genau machen möchtest gibt es unterschiedliche Herangehensweisen an das Problem. Angefangen von kompletten Frameworks, die dir die Arbeit abnehmen über Mediation (CQRS via MediatR) bis hin zu simplem ausprogrammieren der Abhängigkeiten.
Was passt hängt davon ab, wie deine Anforderungen aussehen.

Dein Beispielcode sieht aber nach Schichtenverletzung aus. Datenbankzugriff sollte nicht in der Datenbank erfolgen.

P.S.: ist mir erst am Ende aufgefallen... willst du nur mehrere await's in einer Methode ausführen? Das funktioniert doch Problemlos..

Pseudo Code:


public async Task AddCustomer() 
{
  var customer = await AddCustomerToDb();
  await AddCustomerAddress(customer, address);
  await AddCustomerToProject(customer, 1);
}
private Nachricht | Beiträge des Benutzers
JimStark
myCSharp.de - Member

Avatar #dOpLzh7hN1az1g0eGRc0.jpg


Dabei seit:
Beiträge: 225

Themenstarter:

beantworten | zitieren | melden

Super, vielen Dank! Genau was ich gesucht habe.

Ich verstehe da aber den Syntax nicht ganz oder wie das genau funktioniert:



public async Task AddCustomer()
{
  var customer = await AddCustomerToDb(); //Task<Customer>
  await AddCustomerAddress(customer, address); // Task 
  await AddCustomerToProject(customer, 1); // Task
}

//vs.

public async Task AddCustomer()
{
   return Task.Run( () => {...}; // Task zurück
}



Den zweiten Fall verstehe ich, da gebe ich einen Task zurück. Wenn ich die MS Docs richtig verstanden habe ist "await xyz()" auch vom Typ Task. Wie funktioniert das intern das da was returned wird, auch wenns mehrere Tasks gibt bzw wenn ein übergeordneter Task draus gemacht wird...?
Dieser Beitrag wurde 2 mal editiert, zum letzten Mal von JimStark am .
private Nachricht | Beiträge des Benutzers
Papst
myCSharp.de - Experte



Dabei seit:
Beiträge: 350
Herkunft: Kassel

beantworten | zitieren | melden

Intern erstellt der Compiler aus jedem await eine Statemachine.
Da gibt es sicher einige Blog Posts oder Artikel darüber, wie das genau funktioniert.

Für dich erscheint es aber so, dass das warten auf eine async Methode (await) dazu führt, dass diese im Hintergrund ausgeführt wird und der Verarbeitungsschritt dann an den Rückgabepunkt zurückspringt.
Insofern ist es wunderbar möglich await's untereinander zu schreiben.

In diesem Beispiel, bei AddCustomerToDb: Wenn der Task "AddCustomerToDb" abgearbeitet ist, springt die Ausführung wieder zu dieser Zeile und die variable customer steht zur verfügung. Danach wird "AddCustomerAddress" abgearbeitet.
Also für den Programmierer kein Unterschied zu sequentieller Programmierung.


public async Task AddCustomer()
{
  var customer = await AddCustomerToDb(); //Task<Customer> 
  await AddCustomerAddress(customer, address); // Task
  await AddCustomerToProject(customer, 1); // Task
}

Auch funktionieren würde z.B. ein .ContinueWith().

Das Task.Run wirst du dir vermutlich dort sparen können, wenn die aufgerufene Methode sowieso schon einen Task zurückgibt.
private Nachricht | Beiträge des Benutzers
JimStark
myCSharp.de - Member

Avatar #dOpLzh7hN1az1g0eGRc0.jpg


Dabei seit:
Beiträge: 225

Themenstarter:

beantworten | zitieren | melden

Zitat von Papst
Für dich erscheint es aber so, dass das warten auf eine async Methode (await) dazu führt, dass diese im Hintergrund ausgeführt wird und der Verarbeitungsschritt dann an den Rückgabepunkt zurückspringt.
Insofern ist es wunderbar möglich await's untereinander zu schreiben.

In diesem Beispiel, bei AddCustomerToDb: Wenn der Task "AddCustomerToDb" abgearbeitet ist, springt die Ausführung wieder zu dieser Zeile und die variable customer steht zur verfügung. Danach wird "AddCustomerAddress" abgearbeitet.
Also für den Programmierer kein Unterschied zu sequentieller Programmierung.


public async Task Test(){
   var customer = await GetCustomer(...);
   await AddCustomer(customer); // führt zu CustomerHasChanged = true
   await AndereFunktion(...);
   model.Name = "...";
   syncMethode(...);
   CustomerHasChanged = false;
}

Angenommen ich habe eine Methode wie in dem Beispiel. Verstehe ich das richtig dass nicht garantiert wird dass die Methoden in dieser Reihenfolger ausgeführt werden wenn keine Abhängigkeiten bestehen? Also in meiner Anwedung habe ich das Problem, ich arbeite mehrere Tasks mit await ab. Danach setzte ich CustomerHasChanged = false. Der ist dann aber true, was irgendwie bedeutet dass die Tasks noch laufen (führen zu CustomerHasChanged=true), das setzen aber schon abgearbeitet ist.
Dieser Beitrag wurde 3 mal editiert, zum letzten Mal von JimStark am .
private Nachricht | Beiträge des Benutzers
glandorf
myCSharp.de - Member

Avatar #avatar-4144.jpg


Dabei seit:
Beiträge: 62
Herkunft: Chemnitz

beantworten | zitieren | melden

Hallo,

die Methoden werden in dieser Reihenfolge ausgeführt. Sofern diese async/await richtig implementieren.

glandorf
private Nachricht | Beiträge des Benutzers
FZelle
myCSharp.de - Experte



Dabei seit:
Beiträge: 10064

beantworten | zitieren | melden

Nein, await wartet auf die Rückkehr des Tasks.

Wenn da irgendetwas parallel ausgeführt wird, hast du irgendwo ein await vergessen.
private Nachricht | Beiträge des Benutzers
dannoe
myCSharp.de - Member



Dabei seit:
Beiträge: 151

beantworten | zitieren | melden

Zitat von JimStark
Angenommen ich habe eine Methode wie in dem Beispiel. Verstehe ich das richtig dass nicht garantiert wird dass die Methoden in dieser Reihenfolger ausgeführt werden wenn keine Abhängigkeiten bestehen? Also in meiner Anwedung habe ich das Problem, ich arbeite mehrere Tasks mit await ab. Danach setzte ich CustomerHasChanged = false. Der ist dann aber true, was irgendwie bedeutet dass die Tasks noch laufen (führen zu CustomerHasChanged=true), das setzen aber schon abgearbeitet ist.

Das würde nur zutreffen, wenn du die Async Methoden aufrufst, aber nicht darauf wartest (await).
private Nachricht | Beiträge des Benutzers
Palladin007
myCSharp.de - Member

Avatar #avatar-4140.png


Dabei seit:
Beiträge: 1427
Herkunft: Düsseldorf

beantworten | zitieren | melden

Zitat
Das würde nur zutreffen, wenn du die Async Methoden aufrufst, aber nicht darauf wartest (await).

Dieser Fall kann auch ungewollt auftreten, z.B. bei Events kann man keinen Task zurück geben und Commands funktionieren nur synchron.
Daher gehört für mich immer ein Handling für einen laufenden Task dazu, z.B. könnte man eine abstrakte Command-Basisklasse schreiben, die einen aktuell laufenden Task beobachtet und solange keine weitere Ausführung erlaubt.

Z.B. gibt's dort ein Beispiel, wo so ein AsyncCommand aussehen könnte:https://johnthiriet.com/mvvm-going-async-with-async-command/
private Nachricht | Beiträge des Benutzers