Autofac:如何在SingleInstance范围内使用每个请求的依赖关系?

时间:2018-07-23 09:05:23

标签: c# asp.net-web-api dependency-injection asp.net-web-api2 autofac

IDbConnection个连接依赖项已注册为per-requestApplicationOAuthProvider已注册为single instance

builder.Register(c => new SqlConnection(WebConfigUtils.DefaultConnectionString))
            .As<IDbConnection>()
            .InstancePerRequest();

builder.RegisterType<ApplicationOAuthProvider>()
            .As<IOAuthAuthorizationServerProvider>()
            .PropertiesAutowired()
            .SingleInstance();

需要在身份声明中存储用户权限。为此,我创建了命令GetRolePermissions,并在此命令中注入IDbConnection实例。

public class GetRolePermissions
{
    public class Command: IRequest<List<string>>
    {
        public ICollection<AspNetUserRole> UserRoles { get; set; }
    }

    public class Handler : AsyncRequestHandler<Command, List<string>>
    {
        private IDbConnection databaseConnection;

        public Handler(IDbConnection databaseConnection)
        {
            this.databaseConnection = databaseConnection;
        }
    }
}

此命令正在ApplicationOAuthProvider

中创建
public class ApplicationOAuthProvider : OAuthAuthorizationServerProvider
{
    private async Task<ClaimsIdentity> GenerateUserIdentityAsync(AspNetUser user, string authenticationType)
    {
        user.SecurityStamp = Guid.NewGuid().ToString();
        var identity = await mediator.Send(new GenerateUserIdentity.Command
        {
            AuthenticationType = authenticationType,
            User = user
        });

        List<string> permissions = null;
        permissions = await mediator.Send(new GetRolePermissions.Command { UserRoles = user.Roles });
        var permissionClaimValue = permissions != null && permissions.Count > 0
            ? permissions.Aggregate((resultString, permission) => resultString + "," + permission)
            : "";
        identity.AddClaim(new Claim(AuthenticationConstants.Gender, user.Gender.ToString()));
        identity.AddClaim(new Claim(AuthenticationConstants.Permissions, permissionClaimValue));
        return identity;
    }
}

permissions = await mediator.Send(new GetRolePermissions.Command { UserRoles = user.Roles });-抛出错误,因为GetRolePermissions.Handler需要注入IDbConnection,但是当前ApplicationOAuthProvider的autofac范围是"root",并且没有{{1 }}在此范围内注册。但是它存在于iDbConnection范围内。

不想为IDbConnection使用per-request,因为我认为,perLifettime不必要时应关闭。我以为是这样的:

dbConnection

但是不能使该解决方案起作用。而且我不知道如何正确获取容器,因为它是我手动设置的AutofacConfig静态变量。

如何启用将using(var scope = AutofacConfig.container.BeginLifiTime("AutofacWebRequest")) { permissions = await mediator.Send(new GetRolePermissions.Command { UserRoles = user.Roles }); } 注入此IDbConnection

1 个答案:

答案 0 :(得分:1)

实际上,InstancePerLifetimeScope()是您要寻找的解决方案。您所需要做的就是注入DbConnection 工厂,该DbConnection产生DbConnection的拥有的(docs link 1docs link 2)实例,而不是DbConnection本身。

// registration

builder.RegisterType<SqlConnection>()
    .As<IDbConnection>()
    .WithParameter(new NamedParameter("connectionString", WebConfigUtils.DefaultConnectionString))
    .InstancePerLifetimeScope();

// usage

public class GetRolePermissions
{
    public class Command: IRequest<List<string>>
    {
        public ICollection<AspNetUserRole> UserRoles { get; set; }
    }

    public class Handler : AsyncRequestHandler<Command, List<string>>
    {
        private Func<Owned<IDbConnection>> _connectionFactory;

        public Handler(Func<Owned<IDbConnection>> connectionFactory)
        {
            _connectionFactory = connectionFactory;
        }

        // not really sure where your consuming code is, so just something off the top of my head
        public DontKnowYourResultType Handle(GetRolePermissions.Command cmd) {
            using (var ownedConnection = _connectionFactory()) {
                // ownedConnection.Value is the DbConnection you want
                // ... do your stuff with that connection
            } // and connection gets destroyed upon leaving "using" scope
        }
    }
}

它确实改变了属于请求范围的子范围的行为,但是我不确定这对您的代码是否有问题-请尝试一下,可能它应该可以正常工作。如果没有,那么你知道在哪里问。 ;)