Ich habe eine mehrschichtige C# MVC4-Webanwendung in einem stark frequentierten Szenario, das Dependency Injection für verschiedene Repositorys verwendet. Dies ist sehr nützlich, da es leicht testbar ist, und in der Produktion können wir die Repositories für bestimmte Controller leicht konfigurieren. Alle Controller erben von AsyncController, so dass Aktionsmethoden, die Task<JsonResult>
oder Task<ActionResult>
zurückgeben, wirklich unserem Server helfen, mit mehr Benutzern und solve for the dreaded thread starvation problem zu skalieren. Einige Repositories verwenden Webdienste, die wir definitiv mit Async/Await nutzen können, um Skalierbarkeit zu bieten. In anderen Fällen können einige nicht verwaltete Dienste verwenden, die nicht sicher verlegt werden können und bei denen async/await keine Vorteile bietet. Jedes Repository ist eine Implementierung einer Schnittstelle, IRepository. Kurz gesagt, jede Implementierung unterscheidet sich drastisch in der Art, wie sie Daten erhalten kann. Diese Konfiguration wird zum Zeitpunkt der Bereitstellung mit web.config-Änderungen und Autofac-Modulen ausgewählt.Async/Warte in mehrschichtigen C# -Anwendungen
Was sind einige der empfohlenen Wege zur Implementierung von async/await in einer Anwendung wie dieser? Um das Muster in meiner vorhandenen Anwendung anzupassen, muss ich die Schnittstelle ändern, um Task<MyBusinessObject>
zurückzugeben. Aber ist das nicht mehr ein Implementierungsdetail? Ich könnte zwei Methoden Stubs zur Verfügung stellen, GetData
und GetDataAsync
, aber für mich würde das die Flexibilität nicht erlauben, die ich jetzt mit IoC-Frameworks wie Autofac habe, wo ich leicht alles aus tauschen kann, ohne Code ändern zu müssen.
Einer der Microsoft-Entwickler für Async/Await hat einen Blog-Beitrag veröffentlicht, "Should I expose an asynchronous wrapper for my synchronous methods?", der in das Problem eingeht. Wenn Ihre asynchrone Methode nicht wirklich asynchron ist (dh native E/A-Vorteile bietet), wird nur ein Overhead hinzugefügt. Mit anderen Worten, es bietet keine Skalierbarkeitsvorteile.
Ich möchte nur, wie der Rest der Gemeinschaft dieses Problem angegangen ist.
'async' und' warten' sind nur Abstraktionen, um eine Blockierungsmethode in eine nicht blockierende Methode umzuwandeln. Sie können dies an einer beliebigen Stelle in Ihrem Code durchführen, ohne die Schnittstelle zu ändern, es sei denn, Sie möchten erzwingen, dass die Schnittstellenmethode immer asynchron ist. –
Wenn Sie die Aufgabe während des gesamten Aufruf-Stacks nicht haben, wird sie NIE asynchron aufgerufen. Man müsste also in die Schnittstelle setzen, um immer eine Task zurückzugeben. –
Das habe ich nicht gesagt. Was ich gesagt habe, ist, dass Sie jede Methode in eine asynchrone Methode verwandeln können, indem Sie 'async' und' await' verwenden, einschließlich einer der Blockierungsmethoden, die Sie bereits auf Ihren Schnittstellen haben. Ein 'Task' Rückgabetyp ist bei der ursprünglichen Methode nicht erforderlich. Es ist natürlich eine vollkommen gültige Sache, all Ihre Schnittstellenmethoden durch ihre Async-Entsprechungen zu ersetzen, aber es ist nicht erforderlich. –