2016-03-31 5 views
0

Ich habe eine Anwendung aus DAL, BLL und der API-Schicht und Iam mit Einheit für die Injektion zusammengesetzt. In der Business-Schicht habe ich eine Klasse namens AuthRepository, wo sie von IAuthRepository erbt, das folgende Teil dieser Klasse ist.Verwendung von Unity in einer 3-Schicht-Anwendung

Klasse AuthRepository in BLL:

public class AuthRepository : IAuthRepository, IDisposable 
{ 
    private UserAuthContext _authContext; 
    private UserManager<UserInfo> _userManager; 

    // Issue 1: this constructor should be delete and use injection instead 
    // to solve the problem in class SimpleAuthorizationServerProvider 
    public AuthRepository() 
    { 
     _authContext = new UserAuthContext(); 
     _userManager = new UserManager<UserInfo>(new UserStore<UserInfo>(_authContext)); 
    } 

    public AuthRepository(UserAuthContext authContext) 
    { 
     _authContext = authContext; 
     //this._authContext = new UserAuthContext(); 
     _userManager = new UserManager<UserInfo>(new UserStore<UserInfo>(_authContext)); // TODO: implement usermanager with Unity 
    } 

    public async Task<IdentityResult> RegisterUser(UserEntity createUserModel) 
    { 
     UserInfo user = new UserInfo 
     { 
      FirstName = createUserModel.FirstName, 
      LastName = createUserModel.LastName, 
      UserName = createUserModel.UserName, 
      Email = createUserModel.Email 
     }; 
     var result = await _userManager.CreateAsync(user, createUserModel.Password); 
     return result; 
    } 

in der API-Ebene Ich habe eine andere Klasse, die SimpleAuthorizationServerProvider genannt wird, die Klasse kümmern sich um die Token-Bär zur Verfügung gestellt von Owin folgenden wird die Klasse

Klasse SimpleAuthorizationServerProvider in API Schicht:

public class SimpleAuthorizationServerProvider : OAuthAuthorizationServerProvider 
{ 
    public override Task ValidateClientAuthentication(OAuthValidateClientAuthenticationContext context) 
    { 
     // Resource owner password credentials does not provide a client ID. 
     if (context.ClientId == null) 
     { 
      context.Validated(); 
     } 

     return Task.FromResult<object>(null); 
    } 
    public override async Task GrantResourceOwnerCredentials(OAuthGrantResourceOwnerCredentialsContext context) 
    { 
     context.OwinContext.Response.Headers.Add("Access-Control-Allow-Origin", new[] { "*" }); 

     using (AuthRepository _repo = new AuthRepository()) 
     { 
      IdentityUser user = await _repo.FindUser(context.UserName, context.Password); 

      if (user == null) 
      { 
       context.SetError("invalid_grant", "The user name or password is incorrect."); 
       return; 
      } 
     } 

     var identity = new ClaimsIdentity(context.Options.AuthenticationType); 
     identity.AddClaim(new Claim("sub", context.UserName)); 
     identity.AddClaim(new Claim("role", "user")); 

     context.Validated(identity); 
    } 
} 

das Problem ist, dass der erste Konstruktor in AuthRepository sollte remov sein um Anwendung lausig gekoppelt zu machen. Wenn ich diesen Konstruktor löschen, so brauche ich einen Parameter vom Typ UserAuthContext aus der SimpleAuthorizationServerProvider Klasse in den Verfahren GrantResourceOwnerCredentials bei dieser Aussage

mit (AuthRepository _repo = new AuthRepository()) senden

und das ist was ich nicht tun möchte, sollte der API-Layer mit dem BLL und nicht mit dem DAL kommunizieren.

Irgendeine Idee, wie man das löst?

Antwort

1

Ich bin nicht vertraut mit Unity, aber im Allgemeinen sollte ein IoC-Container darauf achten, die Abhängigkeiten über Konstruktor-Injektion zu injizieren. In Ihrem Fall sollten Sie die Klassen SimpleAuthorizationServerProvider und AuthRepository ändern.

public class SimpleAuthorizationServerProvider 
{ 
    private IAuthRepository _authRepository; 

    public SimpleAuthorizationServerProvider(IAuthRepository authRepository) 
    { 
     _authRepository = authRepository 
    } 

    ... 

    public override async Task GrantResourceOwnerCredentials(OAuthGrantResourceOwnerCredentialsContext context) 
    { 
     context.OwinContext.Response.Headers.Add("Access-Control-Allow-Origin", new[] { "*" }); 

     // no need for new repository anymore 
     // class already has repository injected 

     IdentityUser user = await _authRepository.FindUser(context.UserName, context.Password); 

     if (user == null) 
     { 
      context.SetError("invalid_grant", "The user name or password is incorrect."); 
      return; 
     } 

     var identity = new ClaimsIdentity(context.Options.AuthenticationType); 
     identity.AddClaim(new Claim("sub", context.UserName)); 
     identity.AddClaim(new Claim("role", "user")); 

     context.Validated(identity); 
    } 
} 

public class AuthRepository : IAuthRepository, IDisposable 
{ 
    public AuthRepository(UserAuthContext userAuthContext, UserManager<UserInfo> userManager) 
    { 
     _userAuthContext = userAuthContext; 
     _userManager = userManager; 
    } 
    ... 
} 

Wenn Ihre AuthRepository Klasse nicht braucht sich das UserAuthContext (Ihre Code-Snippet verwendet es nur eine UserManager<UserInfo> erstellen), dann können Sie diese Klasse aus dem Konstruktor zu entfernen und diese Abhängigkeit zu dem Konstruktor der UserManager<T> Klasse bewegen:

public class AuthRepository : IAuthRepository, IDisposable 
{ 
    public AuthRepository(UserManager<UserInfo> userManager) 
    { 
     _userManager = userManager; 
    } 
    ... 
} 

public class UserManager<T> 
{ 
    private UserAuthContext _userAuthContext; 

    public UserManager<T>(UserAuthContext userAuthContext) 
    { 
     _userAuthContext = userAuthContext; 
    } 
    ... 
} 

Schließlich müssen Sie alle Klassen registrieren, die mit Unity injiziert werden müssen in the documentation beschrieben

Noch eine Sache: Sie würden tter ersetzen die konkreten Klassen in den Konstruktoren nach Möglichkeit durch Schnittstellen. Im Allgemeinen ist es besser, auf Schnittstellen als auf konkrete Klassen zu programmieren. Eine schöne Übersicht kannhere

bearbeiten

am Körper von GrantResourceOnwerCredentials zu betonen, dass Sie nicht mehr benötigen ein neues Repository, da das Objekt bereits Zugriff auf das injizierte man gefunden werden.

aktualisieren

In Ihrem Start-up-Klasse Sie kein neues SimpleAuthorizationServerProvider aber bitten, eine abstract factory, die eine Abhängigkeit von SimpleAuthorizationServerProvider hat schaffen sollte es für Sie zu tun.

+0

das ist registrieren, was ich zu tun versucht, aber wenn ich SimpleAuthorizationServerProvider in der Startup-Klasse registrieren, werde ich vor dem gleiche Problem, dass der Konstruktor in Der SimpleAuthorizationServerProvider benötigt einen Parameter vom Typ IAuthRepository. Glauben Sie, dass DI mit propreties anstelle von constructor dieses Problem lösen könnte? –

+0

Sie sollten eine konkrete Klasse für 'IAuthRepository' registrieren mit' RegisterType () 'wie folgt:' yourContainer.RegisterType (); ' – venerik

+0

Ich habe bro, ich habe diesen Schritt bereits getan. Mein Problem ist, dass ich einen Parameter vom Typ UserAuthContext in SimpleAuthorizationServerProvider-Klasse in GrantResourceOwnerCredentials-Methode senden muss, –

1

Folgen wie venerik angewiesen, so einen Konstruktor hinzufügen, die Schnittstelle von IAuthRepository nimmt:

public class SimpleAuthorizationServerProvider 
{ 
    private IAuthRepository _authRepository; 

    public SimpleAuthorizationServerProvider(IAuthRepository authRepository) 
    { 
     _authRepository = authRepository 
    } 

    ... 

Then ‚registrieren SimpleAuthorizationServerProvider in der Startup-Klasse‘ Sie einen Parameter vom Typ übergeben müssen, wie Sie bereits erwähnt, wenn Sie 'IAuthRepository', die Sie, indem Sie die folgenden Aktionen durchführen:

var OAuthServerOptions = new OAuthAuthorizationServerOptions() 
     { 
      AllowInsecureHttp = true, 
      TokenEndpointPath = new PathString("/token"), 
      AccessTokenExpireTimeSpan = TimeSpan.FromMinutes(60), 
      Provider = new SimpleAuthorizationServerProvider((IAuthRepository)GlobalConfiguration.Configuration.DependencyResolver.GetService(typeof(IAuthRepository))) 
     }; 

im Code über die Anbieter Linie i s, wo Sie Ihre konkrete Klasse injizieren müssen.

p.s. Ich bin vorausgesetzt, Sie Ihre Unity-Konfiguration in Ihrer Owin Startdatei tatsächlich dh

public class Startup 
{ 
    public void Configuration(IAppBuilder app) 
    { 
     UnityConfig.RegisterComponents(); 
     ConfigureOAuth(app); 
     ... 
+0

Ich werde in der Lage sein, eine detailliertere Beispiel nächste Woche, zu viel auf im Moment, tut mir leid. – Palvinder