2010-05-02 5 views
11

Ich habe eine ASP.NET MVC-Webanwendung, die einen benutzerdefinierten Mitgliedschaftsprovider implementiert. Der benutzerdefinierte Mitgliedschaftsanbieter verwendet eine UserRepository für seinen Konstruktor, der eine Schnittstelle zwischen dem Mitgliedschaftsprovider und NHibernate bereitstellt. Der UserRepository wird vom Ninject IoC Container bereitgestellt.Dependency Injection mit benutzerdefinierten Mitgliedschaftsanbieter

Offensichtlich funktioniert dies jedoch nicht, wenn der Provider von .NET instanziiert wird: Der parameterlose Konstruktor verfügt über kein UserRepository und kann kein UserRepository erstellen (das UserRepository erfordert die Übergabe einer NHibernate-Sitzung an seinen Konstruktor) bedeutet, dass der Provider nicht auf seinen Datenspeicher zugreifen kann. Wie kann ich meine Objektabhängigkeit auflösen?

Es ist wahrscheinlich erwähnenswert, dass dies eine vorhandene Anwendung ist, die mit Ninject nachgerüstet wurde. Zuvor verwendete ich parameterlose Konstruktoren, die in der Lage waren, ihre erforderlichen Abhängigkeiten in Verbindung mit den parametrisierten Konstruktoren zu erstellen, um Unit-Tests zu unterstützen.

Irgendwelche Gedanken, oder habe ich mich hier in eine Ecke gebaut?

Antwort

5

Sie möchten vielleicht den parameterlosen Konstruktor behalten, der die benötigten Repositorys mit Ninject initialisiert. Vielleicht möchten Sie die Common Service Locator verwenden, so dass Sie weder einen Verweis auf Ninject noch Container in Ihrem benutzerdefinierten Anbieter benötigen. Es scheint, Ninject hat keine offizielle Adapter-Implementierung für CSL, aber das Schreiben sollte nicht zu schwer sein (überprüfen Sie die anderen Implementierungen, wie Windsor), und ich bin sicher, dass es irgendwo eine inoffizielle Implementierung gibt.

+3

Ninject hat einen offiziellen CSL-Adapter Januar 2010. –

+0

Es fehlt noch auf der CSL-Homepage (es ist stattdessen in der NInject-Version enthalten) – SztupY

+1

"-Konstruktor, der die erforderlichen Repositorys mit Ninject initialisiert" - achten Sie darauf, ob Ihre Repositories (oder ihre Abhängigkeiten) im Anforderungs- oder Transientenbereich sind Wenn der Kontext der verfügbaren Daten in den Vordergrund rückt, werden Sie mit Ausnahme der ersten Anfrage auf einen Kontext für entsorgte Daten zugreifen (da Sie die Lebensdauer eines Anbieters nicht steuern und ASP.NET ihn über mehrere Anfragen hinweg wiederverwenden kann). Ich habe jedes Mal eine Repository-Instanz aus dem Locator bekommen, wenn ich sie aufrufen musste, als ich auf dieses Problem stieß. –

-1

Ich hatte das gleiche Problem, ich löste es durch die Übergabe der erforderlichen Daten mit Authentifizierung Ticket für Identitätsobjekt.

Dann müssen keine Objekte in Mitgliedschaftsprovider injiziert werden.

In meinem Authentifizierungscode habe ich

[NonAction] 
    private void SetAuthTicket(Member member, bool isPersistent) 
    { 
     HttpCookie cookie = Request.Cookies.Get(FormsAuthentication.FormsCookieName); 

     FormsAuthentication.SetAuthCookie(member.Email, isPersistent); 

     string userData = "|" + member.ID + "|" + member.Firstname + "|" + member.Lastname + member.Culture; 

     FormsAuthenticationTicket ticket = new FormsAuthenticationTicket(1, member.Email, DateTime.UtcNow, DateTime.UtcNow.AddDays(7), isPersistent, userData); 

     string encryptedTicket = FormsAuthentication.Encrypt(ticket); 
     cookie = new HttpCookie(FormsAuthentication.FormsCookieName, encryptedTicket); 
     Response.Cookies.Add(cookie); 
    } 

Und in Global.asax

void Application_OnPostAuthenticateRequest(object sender, EventArgs e) 
    { 
     IPrincipal user = HttpContext.Current.User; 
     if (user.Identity.IsAuthenticated && user.Identity.AuthenticationType == "Forms") 
     { 
      FormsIdentity identity = user.Identity as FormsIdentity; 

      MyIdentity ai = new MyIdentity(identity.Ticket);    
      MyPrincipal p = new MyPrincipal(ai); 

      HttpContext.Current.User = p; 
      System.Threading.Thread.CurrentPrincipal = p; 

      if (!String.IsNullOrEmpty(ai.Culture)) 
      { 
       CultureInfo ci = new CultureInfo(ai.Culture); 
       System.Threading.Thread.CurrentThread.CurrentUICulture = ci; 
       System.Threading.Thread.CurrentThread.CurrentCulture = CultureInfo.CreateSpecificCulture(ci.Name); 
      } 
     } 
    } 

Und in Identity Klasse I haben Member, Vorname und Nachname Eigenschaften, die Teile der Ticket String zurück.

+0

Bitte könnten Sie gehen in ein wenig mehr Details? Wie würde zum Beispiel die CreateUser() - Überschreibungsfunktion in Ihrem Szenario funktionieren? Wollen Sie damit sagen, dass ich in meinem Szenario das Repository-Objekt im Authentifizierungsticket übergeben müsste? – alastairs

+0

Anstatt Repository-Pass Benutzer-ID übergeben –

+0

was ?? Ich stimme @alastairs zu, wie erstellt man Benutzer und andere Sachen ohne ein Repository? – mare

4

Da die Membership-Sammlung und die MemberShip.Provider-Instanz erstellt werden, bevor Ninject sie instanziieren kann, müssen Sie nach der Erstellung eine Aktivierung für das Objekt durchführen. Wenn Sie Ihre Abhängigkeiten mit [Inject] für Ihre Eigenschaften in Ihrer Provider-Klasse markieren, können Sie kernel.Inject (MemberShip.Provider) aufrufen - dies wird allen Eigenschaften Ihre Abhängigkeiten zuweisen.

+0

Klingt gut; Ich habe es mit der CSL gelöst, aber es könnte einen erneuten Besuch wert sein, um die zusätzliche Abhängigkeit zu entfernen. – alastairs

+0

+1 Ich mag diese Methode. – Pandincus

+2

Wo würdest du kernel.Inject ... nennen? – Matt