2 Stimmen

Async-Methode in asp.net-Webdienst

Ich habe eine Seite, die eine Reihe von Berichten erstellt und eine Zip-Datei mit den Ergebnissen per E-Mail versendet. Dieser Vorgang dauert etwa 30 Sekunden bis 2 Minuten.

Wenn der Benutzer diesen Prozess über Ajax aufruft, kann ich den Webdienst über Ajax abrufen, um die Ergebnisse zu erhalten, aber wie erstelle ich eine asynchrone Methode, die kontinuierlich eine Variable aktualisiert?

Wie könnte ich der Einfachheit halber eine Methode schreiben, die von 1 bis 1 Million zählt und jede Zahl zu einer Liste hinzufügt, und gleichzeitig in der Lage sein, den Webdienst abzufragen und die aktuelle Anzahl der Elemente in der Liste zurückzugeben?

Auch alle anderen Artikel wären willkommen.

1voto

Joe Enzminger Punkte 10882

Zunächst einige Gedanken zum Hintergrund:

1) Da es sich um einen lang laufenden Auftrag handelt, möchten Sie vielleicht einen Zwischenspeicher mit bereits ausgeführten Aufträgen einrichten, um doppelte Arbeit und eine Überlastung des Servers zu vermeiden.

2) Sie sollten keinen separaten Hintergrund-Thread starten müssen, da jede ASP.NET-Anfrage ohnehin in einem eigenen Thread ausgeführt wird. Wenn Sie jedoch feststellen, dass Sie Ihren ASP.NET-Arbeitsprozess aushungern, können Sie Ihre Webmethoden auf der Serverseite asynchron machen - siehe: dieser Artikel .

Die Implementierung erfordert drei Komponenten - einen Cache, eine Webmethode zur Ausführung des Auftrags und eine Webmethode zur Überprüfung des Auftragsstatus. Außerdem müssen Sie in der Lage sein, einen Schlüssel zu generieren, mit dem das System die Anfragen verfolgen kann. Sie können diesen Schlüssel serverseitig (bei der Generierung der Seite) oder clientseitig (wenn Sie einen cleveren Algorithmus haben, der eindeutige IDs erzeugen kann) erzeugen.

Der Cache kann anwendungsspezifisch sein, wenn Sie möchten, dass Benutzer laufende Aufträge gemeinsam nutzen können, oder sitzungsspezifisch, wenn Sie dies nicht wünschen. Der Cache ist einfach ein Wörterbuch, das Verweise auf Ihre laufenden Auftragsinstanzen enthält.

Ein einfaches Beispiel (es lässt sich nicht kompilieren, enthält wahrscheinlich Syntaxfehler und dient hauptsächlich dazu, den Sinn der Sache zu verdeutlichen).

Server-Pseudocode:

//In application Session_Start, 
Session["ReportCache"] = new Dictionary<string, ReportStatus>();

public class ReportResults
{
}

public class ReportStatus
{
    public int PercentComplete = 0;
}

[WebMethod(EnableSessions = true)]
ReportResults RunReport(string uniqueid)
{
    ReportStatus status = new ReportStatus();
    Session["ReportStatus"].Add(uniqueid, status);
    //Start report
    for(int i = 0; i < 100000; ++i)
    {

        //update the report status
        status.PercentComplete = 100 * 100000 * i / 100000;
    }
    Session["ReportStatus"].Remove(uniqueid);

}

[WebMethod(EnableSessions=true)]
public ReportStatus GetStatus(uniqueid)
{
    try
    {
        return Session["ReportStatus"][uniqueid];
    }
    catch(Exception)
    {
        return null;
    }
}

Verwenden Sie auf dem Client Ajax, um die erste Webmethode aufzurufen. Der onSuccess-Callback wird erst dann aufgerufen, wenn der Bericht fertig ist. Verwenden Sie setTimeout, um die zweite Webmethode regelmäßig abzufragen, um Statusinformationen zu erhalten und den Client zu aktualisieren. Wenn die erste Web-Methode abgeschlossen ist, brechen Sie den Timer ab.

Ihr größtes Problem wird die Tatsache sein, dass Ihr Server viele lang laufende Aufträge ausführt, was die Gesamtleistung und Reaktionsfähigkeit beeinträchtigen kann. Vielleicht sollten Sie einen ganz anderen Ansatz wählen. Anstatt die Berichte bei Bedarf pro Benutzer auszuführen, können Sie beispielsweise die Liste der Personen, die den Bericht erhalten möchten, in eine Warteschlange stellen.

0voto

Brandon Montgomery Punkte 6786

Sie müssen Ihren langwierigen Prozess in einem separaten Thread laufen lassen, damit Ihre Webanwendung bei der Erstellung der Berichte nicht scheinbar in die Mittagspause geht. Sie möchten aber auch den Status darüber melden, wie weit Sie in diesem Prozess sind (über AJAX Polling). Ich schlage vor, dass Ihr Webdienst ein Objekt verwendet, das dies für Sie erledigt. Vielleicht so etwas wie dieses:

public class ReportGenerator {
  public string CurrentStatus;

  public void Run() {
    var worker = new Thread(new ThreadStart(this.ExportReports));
    worker.Start();
  }

  private void ExportReports() {
     this.CurrentStatus = "started";
     /* export a report */
     this.CurrentStatus = "1 report complete";
     /* export another report */
     this.CurrentStatus = "2 reports complete";
     /* etc, etc, etc */
  }
}

Ihr Webdienst muss in der Lage sein, eine Instanz dieses Objekts zu erstellen und zu verwalten. Soll in der gesamten Anwendung jeweils nur einer dieser Exporte stattfinden? Wenn ja, verwenden Sie die Singleton-Muster für dieses Objekt und stellen Sie sicher, dass es nicht bereits läuft, bevor Sie es erneut starten.

Wenn mehrere Benutzer diesen Prozess gleichzeitig ausführen können, müssen Sie dieses Objekt instanziieren und einen Verweis darauf in der Sitzung des Benutzers oder etwas Ähnlichem speichern, so dass der Webdienst bei einer Abfrage das Objekt erneut abrufen und seinen Status überprüfen kann und diese Informationen dann an den Client zurückgibt. Bei dieser Art von Threading kann es zu sehr heiklen Situationen kommen, seien Sie also sehr vorsichtig.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X