Verwendung eines DI / IoC-Containers mit dem Modellbinder in ASP.NET MVC 2+?

8

Nehmen wir an, ich hätte eine User-Entity, und ich möchte ihre CreationTime-Eigenschaft im Konstruktor auf DateTime.Now setzen. Aber als Unit Test Adopter möchte ich nicht direkt auf DateTime.Now zugreifen, sondern einen ITimeProvider verwenden:

%Vor%

Ich verwende NInject 2 in meiner ASP.NET MVC 2.0-Anwendung. Ich habe einen UserController und zwei Create-Methoden (eine für GET und eine für POST). Die für GET ist einfach, aber die für POST ist nicht so geradlinig und nicht so vorwärts: P, weil ich mit dem Modellbinder herumhantieren muss, um eine Referenz einer Implementierung von ITimeProvider zu bekommen, um konstruieren zu können eine Benutzerinstanz.

%Vor%

Ich möchte auch alle Funktionen des Standardmodellbinders beibehalten können.

Jede Chance, dieses einfache / elegante / etc zu lösen? : D

    
Andrei Rînea 24.05.2010, 19:30
quelle

3 Antworten

5

Wie wäre es, statt ein ITimeProvider zu verwenden:

%Vor%

Und in Ihrem Komponententest:

%Vor%

Ich weiß, dass das nicht sehr elegant ist, aber anstatt mit dem Modellbinder zu spielen, könnte dies eine Lösung sein. Wenn dies nicht als eine gute Lösung empfunden wird, können Sie ein benutzerdefiniertes Modellbinder implementieren und CreateModel Methode, wo Sie die Abhängigkeiten in den Konstruktor des Modells injizieren würden.

    
Darin Dimitrov 24.05.2010, 19:35
quelle
20

Ein paar Beobachtungen:

Fügen Sie keine Abhängigkeiten ein, nur um sie im Konstruktor abzufragen

Es gibt keinen Grund, einen ITimeProvider in einen Benutzer zu injizieren, um sofort Now aufzurufen. Einfach die Erstellungszeit direkt eingeben:

%Vor%

Eine wirklich gute Faustregel in Bezug auf DI ist, dass Konstruktoren keine Logik ausführen sollten.

Verwenden Sie keine DI mit ModelBinders

Ein ASP.NET MVC ModelBinder ist ein wirklich schlechter Ort, um DI zu erledigen, insbesondere weil Sie Constructor Injection nicht verwenden können. Die einzige verbleibende Option ist das statische Service Locator-Anti-Pattern .

Ein ModelBinder übersetzt HTTP-GET- und POST-Informationen in ein stark typisiertes Objekt, aber konzeptionell diese Typen sind keine Domänenobjekte, sondern ähnlich wie Datenübertragungsobjekte .

Eine viel bessere Lösung für ASP.NET MVC besteht darin, auf benutzerdefinierte ModelBinders vollständig zu verzichten und explizit einzuschließen, dass das, was Sie von der HTTP-Verbindung erhalten, nicht Ihr vollständiges Domänenobjekt ist .

Sie können einen einfachen Lookup oder Mapper verwenden, um Ihr Domain-Objekt in Ihrem Controller abzurufen:

%Vor%

wobei this.userRepository eine injizierte Abhängigkeit ist.

    
Mark Seemann 25.05.2010 07:46
quelle
1

Eine weitere Option besteht darin, eine andere Klasse zu erstellen, um Benutzer darzustellen, die noch nicht persistent sind und noch keine Erstellungsdatumseigenschaft haben.

Auch wenn CreationDate eine der Invarianten von User ist, kann es in Ihrem Ansichtsmodell nullbar sein - und Sie können es in Ihrem Controller- oder Domain-Layer weiter nach unten setzen.

Schließlich spielt es wahrscheinlich keine Rolle, aber sollte das Erstellungsdatumsattribut wirklich den Moment darstellen, in dem Sie eine Benutzerinstanz konstruieren, oder wäre es angemessener, wenn es den Moment eines Benutzers darstellt übergibt ihre Daten?

    
Jeff Sternal 24.05.2010 20:07
quelle