在三层应用程序中使用Unity

时间:2016-03-31 15:22:40

标签: c# asp.net-web-api unity-container

我有一个应用程序,由DAL,BLL和API层组成,Iam使用统一注入。在Business层中,我有一个名为AuthRepository的类,它继承自IAuthRepository,以下是该类的一部分。

BLL中的类AuthRepository:

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;
    }

在API层中我有另一个名为SimpleAuthorizationServerProvider的类,该类负责Owin提供的Bear令牌以下是类

API层中的SimpleAuthorizationServerProvider类:

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);
    }
}

问题是应该删除AuthRepository中的第一个构造函数以使应用程序耦合。如果我删除这个构造函数,所以我需要在此语句的方法GrantResourceOwnerCredentials中从SimpleAuthorizationServerProvider类发送一个类型为UserAuthContext的参数

  

使用(AuthRepository _repo = new AuthRepository())

那就是我不想做的事情,API层应该与BLL而不是DAL进行通信。

知道如何解决这个问题吗?

2 个答案:

答案 0 :(得分:1)

我不熟悉Unity但通常IoC容器应该注意通过构造函数注入注入依赖项。在您的情况下,您应该更改SimpleAuthorizationServerProviderAuthRepository类。

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;
    }
    ...
}

如果您的AuthRepository类不需要UserAuthContext(您的代码段仅使用它来创建UserManager<UserInfo>),那么您可以从构造函数中删除该类并将该依赖项移至UserManager<T>类的构造函数:

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;
    }
    ...
}

最后,您需要按照in the documentation

所述注册必须使用Unity注入的所有类

还有一件事:在可能的情况下,您最好用接口替换构造函数中的具体类。通常,最好是针对接口而不是具体类进行编程。可以找到一个很好的概述here

修改

添加了GrantResourceOnwerCredentials的主体,强调您不再需要新的存储库,因为该对象已经可以访问注入的存储库。

<强>更新

在您的启动课程中,您不应该创建新的SimpleAuthorizationServerProvider,而是要求SimpleAuthorizationServerProvider依赖Java HotSpot(TM) 64-Bit Server VM warning: INFO: os::commit_memory(0x000000078fb80000, 293601280, 0) failed; error='Cannot allocate memory' (errno=12) 的{​​{3}}为您执行此操作。

答案 1 :(得分:1)

按照venerik的指示进行操作,所以添加一个带有IAuthRepository接口的构造函数:

public class SimpleAuthorizationServerProvider 
{
    private IAuthRepository _authRepository;

    public SimpleAuthorizationServerProvider(IAuthRepository authRepository)
    {
        _authRepository = authRepository
    }

    ...

然后,正如您在Startup类中注册SimpleAuthorizationServerProvider时所提到的那样,您需要传递类型为“ IAuthRepository ”的参数,您可以通过添加以下内容来执行此操作:

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

在上面的代码中, provider 行是您需要注入具体类的地方。

P.S。我假设您在Owin启动文件中注册Unity配置,即

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