如何在 ABP 框架中使用拦截器包装工作单元

How to wrap the Unit of Work with an interceptor in ABP framework

文章 https://www.codeproject.com/Articles/1080517/Aspect-Oriented-Programming-using-Interceptors-wit 的作者正在解释如何在 "ASPNET Boilerplate" 框架中创建拦截器。在我的例子中,我想创建一个拦截器(或两个拦截器,一个用于开始,另一个用于结束)来包装 Unit of Work。当任何 AppService 中的方法启动时,我需要调用一个名为 spStart 的存储过程,并在调用提交到数据库时调用 spEnd 。由于 ABP 中的 Unit of Work 也是一个拦截器,这就是我到目前为止所做的: 按照我在上面提供的 link 文章中的步骤,我执行了以下操作:

此代码应使 StartInterceptor 运行 最先,EndInterceptor 运行 最后。考虑到工作单元拦截器将介于两者之间,并且我们将使用逻辑等待被拦截到 return 结果的异步方法,这应该让我们可以选择包装工作单元.然而,这是发生了什么:当 spStart 运行 时,一切正常。这个存储过程 运行s 在工作单元拦截器之前,所以没有问题。但是,当 spEnd 运行s 时,它表示 "Transaction should be disposed before the connection can be used to execute SQL statements" 或 "The operation is not valid for the state of the transaction"... 似乎 UoW 运行s 与我的存储过程并行。有没有其他人对ABP有同样的问题?你是怎么解决的?

如果您遇到事务问题,您可能需要从活动连接中获取活动事务。当您获得交易时,将其分配给您的 sql 命令。

private DbCommand CreateCommand(string commandText, CommandType commandType, params SqlParameter[] parameters)
{
    var command = Context.Database.GetDbConnection().CreateCommand();

    command.CommandText = commandText;
    command.CommandType = commandType;
    command.Transaction = GetActiveTransaction();

    foreach (var parameter in parameters)
    {
        command.Parameters.Add(parameter);
    }

    return command;
}

private void EnsureConnectionOpen()
{
    var connection = Context.Database.GetDbConnection();

    if (connection.State != ConnectionState.Open)
    {
        connection.Open();
    }
}

private DbTransaction GetActiveTransaction()
{
    return (DbTransaction)_transactionProvider.GetActiveTransaction(new ActiveTransactionProviderArgs
    {
        {"ContextType", typeof(PhoneBookDbContext) },
        {"MultiTenancySide", MultiTenancySide }
    });
}




public async Task<GetUserByIdOutput> ExecuteMyStoredProcedure(EntityDto input)
{
    EnsureConnectionOpen();

    using (var command = CreateCommand("SELECT dbo.GetUsernameById(@id)", CommandType.Text, new SqlParameter("@id", input.Id)))
    {
        var username = (await command.ExecuteScalarAsync()).ToString();
        return new GetUserByIdOutput() { Username = username };
    }
}

更多信息:https://www.codeproject.com/Articles/1199648/Using-Stored-Procedure-User-Defined-Function-and-V