2017-10-04 2 views
1

Ich nehme eine "API" (ich benutze den Begriff lose), die als COM + -Objekt implementiert ist. Soweit ich weiß, gibt es keine Unterstützung für die Warteschlangenfunktionalität, die COM + bietet, aber ich weiß ziemlich genau, was COM betrifft. Nimm es mit einem Körnchen Salz. Ich habe nur eine Methode zur Verfügung: invoke, und es ist synchron.Zufriedenstellen einer asynchronen Schnittstellenmethode, wenn Sie nur die Synchronisierung ausführen können

In einem Strich von etwas persönlicher Brillanz, habe ich einen Web Api-Wrapper um dieses COM + -Objekt erstellt, das nur einen Endpunkt hat und das COM + -Objekt mit dem Post-Body der Anfrage aufruft. Dadurch konnte ich stattdessen asynchrone Aufrufe an die Web-API senden (und auch die gottverdammte Abhängigkeit von meinen Apps entfernen).

Jetzt erstelle ich eine Bibliothek, um das ganze Durcheinander zu abstrahieren, aber ich habe beschlossen, ein Provider-Muster zu implementieren, bei dem Sie entweder den COM + direkt oder den Web-API-Wrapper verwenden können. Ich habe natürlich eine Schnittstelle mit sync und async Methoden. Der Web-API-Provider ist natürlich kein Problem, da Sie eine HTTP-Anfrage in beide Richtungen tun können, aber ich stoße mit dem COM + -Anbieter auf eine Wand. Da ist Async keine Option.

Also, ich habe drei Möglichkeiten, wie ich es sehe:

  1. „Implementieren“ die Asynchron-Interface-Methode mit einem NotImplementedException, die eine Verletzung der Schnittstelle Segregation Prinzip.

  2. Tun Sie etwas schlecht beraten wie Verwendung Task.Run, die ich weiß, ist nicht wirklich async in diesem Zusammenhang, und im Grunde liegt für jeden, der gegen meine Bibliothek programmiert.

  3. Führen Sie so etwas wie das Erstellen einer sync- und async-Version der Schnittstelle aus, die vom Standpunkt der Schnittstellentrennung besser ist, aber vom Standpunkt des Anbietermusters aus gesehen schlechter ist. Wenn ich von der asynchronen Schnittstelle abhängig bin, kann der COM + -Provider niemals verwendet werden, und wenn ich von der Synchronisierungsschnittstelle abhängig bin, kann ich niemals die asynchronen Methoden des Web-API-Providers verwenden.

Lange und kurze, meine allgemeine Frage ist, was Sie in einer Situation zu tun, wo Sie brauchen etwas asynchron laufen, aber die Methode, die Sie nur nutzen möchten, können synchron betrieben werden? Wenn es keine echte Alternative gibt, was ist der am wenigsten beleidigende Weg, um eine Schnittstellenanforderung zu erfüllen?

EDIT

habe ich vergessen, eine weitere Option zu erwähnen:

  1. Rufen Sie die Methode Synchronisierung innerhalb der Implementierung asynchronen und dann wieder einfach Task.FromResult mit dem Ergebnis. Das heißt, ich ziehe keinen neuen Thread (was ein Problem in einer Webanwendung sein könnte), aber ich bin nicht sicher, ob das wirklich besser ist als Task.Run in dem Sinne, dass der Verbraucher darüber belügt wird, dass er tatsächlich "asynchron" ist ".
+0

Ich sehe hier keine vernünftige Auswahl außer 2. Wenn Sie wirklich nicht die COM-Seite ändern können, müssen Sie nicht "lügen", es ist eine Tatsache, die nicht von Ihnen abhängt, Sie tun Ihr Bestes wrap Verhalten unter. Wenn Sie es ändern können: https://msdn.microsoft.com/en-us/library/windows/desktop/ms692623.aspx –

+0

Ja, nein, kann es nicht ändern. Leider handelt es sich um eine DLL eines Drittanbieters, die von unserem POS-Anbieter (der sowohl Point-of-Sale als auch die andere Sache bedeutet) als "API" bereitgestellt wird. Es war eine ständige Quelle von Migräne. –

+0

Task.Run() ist ziemlich async. Aber COM hat die Eigenschaft, dass ein Objekt dem Betriebssystem sagen kann, dass es nicht Thread-sicher ist. Neigt dazu, nützlich zu sein, besser als wenn es zufällig einmal am Tag auf eine völlig undiagnosefähige Weise in Code abstürzt, von dem Sie nicht die Quelle haben. Sie müssen sich wirklich über die Thread-Sicherheit Sorgen machen, wenn Sie starke Beweise dafür haben, dass eine Bibliothek nicht Thread-sicher ist, wie es Bibliotheken nie sind. Gib ihm einfach ein [sicheres Zuhause] (https://StackOverflow.com/a/21684059/17034). –

Antwort

1

Die Lösung war ich landete auf Task.FromResult zu verwenden, um eine Task sogar zurück, obwohl nichts async getan wird. Obwohl dies nicht wirklich asynchron ist, erfüllt es die Schnittstelle. Ich habe dann die Methode kommentiert, um zu bemerken, dass sie eine Synchronisierung ausführt und als Delegat an Task.Run in Situationen weitergegeben werden sollte, in denen der Thread nicht blockiert werden kann (z. B. GUIs). Die Verwendung von Task.Run ist nicht in jeder Situation angemessen (z. B. Web-Anwendungen) und ist ein Implementierungsdetail, über das der Benutzer der Bibliothek entscheiden sollte.

Um das wirklich zu implementieren, müssen Sie drei Task Szenarios behandeln: abgeschlossen, fehlerhaft und abgebrochen. Hier ist der tatsächliche Code, um all dies zu tun:

public Task<int> DoSomethingAsync(CancellationToken cancellationToken) 
{ 
    if (cancellationToken.IsCancellationRequested) 
    { 
     return Task.FromCanceled<int>(cancellationToken); 
    } 

    try 
    { 
     return Task.FromResult<int>(DoSomething()); 
    } 
    catch (Exception e) 
    { 
     return Task.FromException<int>(e); 
    } 
} 

Zuerst wird sichergestellt, dass der Vorgang nicht abgebrochen wurde. Wenn dies der Fall ist, wird eine abgebrochene Aufgabe zurückgegeben. Dann wird die Synchronisierungsarbeit, die wir tun müssen, in einen try..catch-Block gehüllt. Wenn eine Ausnahme ausgelöst wird, müssen wir eine fehlerhafte Aufgabe zurückgeben, die diese Ausnahme enthält. Wenn es schließlich korrekt ausgeführt wird, geben wir eine abgeschlossene Aufgabe zurück.

Verwandte Themen