Entity Framework Core 1.0 Arbeitseinheit mit Asp.Net Core-Middleware oder Mvc-Filter

Ich verwende EF Core 1.0 (zuvor bekannt als EF7) und ASP.NET Core 1.0 (zuvor bekannt als ASP.NET 5) für eine RESTful-API.

Ich hätte gerne eine Arbeitseinheit, die so auf eine http-Anfrage zugeschnitten ist, dass bei der Beantwortung der HTTP-Anfrage entweder ALLE am DbContext vorgenommenen Änderungen in der Datenbank gespeichert werden oder keine (falls vorhanden) gespeichert werden war eine Ausnahme, zum Beispiel).

In der Vergangenheit habe ich WebAPI2 für diesen Zweck mit NHibernate verwendet, indem ein Aktionsfilter verwendet wurde, mit dem ich die Transaktion bei der Ausführung der Aktion beginne. Bei der Ausführung der Aktion beende ich die Transaktion und beende die Sitzung. Dies war der empfohlene Weg beihttp: //isbn.directory/book/978148420110

Aber jetzt verwende ich Asp.Net Core (mit Asp.Net Core Mvc, obwohl dies nicht relevant sein sollte) und Entity Framework, das, wie ich verstanden habe, bereits eine Arbeitseinheit implementiert.

Ich denke, eine in die ASP.NET-Pipeline eingesteckte Middleware (vor MVC) wäre der richtige Weg, um Dinge zu tun. Also würde eine Anfrage gehen:

PIPELINE ASP.NET:MyUnitOfWorkMiddleware ==> MVC Controller ==> Repository ==> MVC Controller ==> MyUnitOfWorkMiddleware

Ich habe darüber nachgedacht, dass diese Middleware die DbContext-Änderungen speichert, wenn keine Ausnahme eingetreten ist, sodass ich in meinen Repository-Implementierungen nicht einmal @ tun musdbcontext.SaveChanges() und alles wäre wie eine zentrale Transaktion. Im Pseudocode würde es ungefähr so aussehen:

class MyUnitOfWorkMiddleware
{
     //..
     1-get an instance of DbContext for this request.
     try {
         2-await the next item in the pipeline.
         3-dbContext.SaveChanges();
     }
     catch (Exception e) {
         2.1-rollback changes (simply by ignoring context)
         2.2-return an http error response
     }
}

Macht das Sinn? Hat jemand ein Beispiel für etwas ähnliches? Ich kann dazu keine guten Praktiken oder Empfehlungen finden.

Auch wenn ich diesen Ansatz auf der Ebene meines MVC-Controllers verwende, hätte ich beim POSTEN einer neuen Ressource keinen Zugriff auf eine von der Datenbank erstellte Ressourcen-ID, da die ID erst generiert wird, wenn die Änderungen an dbContext gespeichert werden (später in der Pipeline in meiner Middleware, NACHDEM der Controller die Ausführung beendet hat). Was ist, wenn ich auf die neu erstellte ID einer Ressource in meinem Controller zugreifen musste?

Jeder Rat wäre sehr dankbar!

UPDATE 1: Ich habe ein Problem mit meinem Ansatz zur Verwendung von Middleware festgestellt, da die DbContext-Instanz in der Middleware nicht mit der Instanz während der Lebensdauer von MVC (und Repositorys) identisch ist. Siehe die FrageEntity Framework Core 1.0 DbContext nicht auf http request @ festgele

UPDATE 2:Ich habe noch keine gute Lösung gefunden. Grundsätzlich sind dies meine Möglichkeiten:

Speichern Sie die Änderungen so schnell wie möglich im DB. Das bedeutet, dass es in der Repository-Implementierung selbst gespeichert wird. Das Problem bei diesem Ansatz ist, dass ich für eine HTTP-Anforderung möglicherweise mehrere Repositorys verwenden möchte (dh: etwas in der Datenbank speichern und dann einen Blob in einen Cloud-Speicher hochladen) und, um eine Arbeitseinheit zu haben, eine implementieren müsste Repository, das sich mit mehr als einer Entität oder sogar mehr als einer Persistenzmethode (DB- und Blob-Speicher) befasst, die den ganzen Zweck zunichte macht

Implementiere einAction Filter wobei ich die gesamte Aktionsausführung in eine DB-Transaktion einbinde. Am Ende der Aktionsausführung des Controllers setze ich den Kontext zurück und verwerfe ihn, wenn es keine Ausnahmen gibt, wenn ich Änderungen an DB vornehme. Das Problem dabei ist, dass die Aktion meines Controllers möglicherweise eine generierte Entity-ID benötigt, um sie an den http-Client zurückzugeben (z. B .: Wenn ich einen POST / api / cars erhalte, möchte ich einen 201 Accepted mit einem Standortheader zurückgeben, der identifiziert Die neue Ressource, die unter / api / cars / 123 und der ID 123 erstellt wurde, ist noch nicht verfügbar, da die Entität nicht in der Datenbank gespeichert wurde und die ID weiterhin eine temporäre 0 ist. Beispiel in der Aktion des Controllers für eine POST-Verbanforderung:

return CreatedAtRoute("GetCarById", new { carId= carSummaryCreated.Id }, carSummaryCreated); //carSummaryCreated.Id would be 0 until the changes are saved in DB

Wie kann ich die gesamte Aktion des Controllers in eine DB-Transaktion einbinden und gleichzeitig eine von der Datenbank generierte ID zur Verfügung haben, um sie in der HTTP-Antwort des Controllers zurückzugeben? Oder.. Gibt es eine elegante Möglichkeit, die http-Antwort zu überschreiben und die ID auf der Ebene des Aktionsfilters festzulegen, sobald die DB-Änderungen festgeschrieben wurden?

UPDATE 3: Wie nathanaldensrs Kommentar Ich konnte das Beste aus beiden Welten herausholen (indem ich die Aktionsausführung meines Controllers in eine DB-Transaktion _UoW einwickelte und auch die ID der neuen Ressource kannte, die erstellt wurde, bevor die DB Änderungen festschrieb), indem ich codegenerierte Guids verwendete und mich stattdessen auf die Datenbank stützte um die Guid zu generieren.

Antworten auf die Frage(6)

Ihre Antwort auf die Frage