我想知道是否有一个事件我可以在 SqlConnection 关闭之前处理事件触发的地方,即:OnBeforeClose
?我想要实现的是 -sp_unsetapprole
在 SQL Server 中调用,以便在连接关闭并返回连接轮询时 - 所以它没有附加任何应用程序。
起初我以为我可以处理这个StateChange
事件 - 但我相信已经太晚了。
我目前的解决方法是手动调用sp_unsetapprole
SqlConnection 调用者。
非常感谢您的关注+时间!
是的。
我想知道是否有一个事件我可以在 SqlConnection 关闭之前处理事件触发的地方,即:OnBeforeClose
?我想要实现的是 -sp_unsetapprole
在 SQL Server 中调用,以便在连接关闭并返回连接轮询时 - 所以它没有附加任何应用程序。
起初我以为我可以处理这个StateChange
事件 - 但我相信已经太晚了。
我目前的解决方法是手动调用sp_unsetapprole
SqlConnection 调用者。
非常感谢您的关注+时间!
是的。
当事件触发时为时已晚,无法运行任何类型的 SQL 批处理。我建议您遵循有关该主题的 MSDN 建议:
通过调用
sp_setapprole
系统存储过程激活 SQL Server 应用程序角色后,无法重置该连接的安全上下文。但是,如果启用了池化,则将连接返回到池中,并且在重新使用池化连接时会发生错误。
当提出这样的建议时,试图反对它们通常是一个坏主意。你可以放弃应用角色,还有更好的选择:
应用程序角色替代
应用程序角色依赖于密码的安全性,这会带来潜在的安全漏洞。密码可能会通过嵌入应用程序代码或保存在磁盘上而暴露。您可能需要考虑以下替代方案:
使用带有 NO REVERT 和 WITH COOKIE 子句的 EXECUTE AS 语句进行上下文切换。您可以在未映射到登录名的数据库中创建用户帐户。然后,您将权限分配给此帐户。对无登录用户使用 EXECUTE AS 更安全,因为它是基于权限的,而不是基于密码的。有关详细信息,请参阅在 SQL Server 中使用模拟自定义权限。
使用证书签署存储过程,仅授予执行过程的权限。有关详细信息,请参阅在 SQL Server 中签署存储过程。
我知道这已经晚了,但我遇到了这个答案,并想在那里抛出另一个选择。我们对我们的应用程序有非常相似的要求。我们需要在每次打开连接时调用自定义存储过程,并在关闭连接时再次调用。
我们能够在EF Provider Wrapper Toolkit的帮助下处理这个问题(现在似乎也在Nuget上)。这基本上可以让您将自己的逻辑注入到各种 ADO.NET 对象中——因此在数据库访问的最低级别。然后,我们创建了自己的自定义 DbConnection 类,您的应用程序中的任何代码最终都将使用该类。它实际上非常简单,并且为我们提供了很多很好的“挂钩”到最低级别的数据库访问,这些都派上了用场。
请注意,我们使用的是实体框架,该库称为EF Provider Wrapper Toolkit,但它适用于任何使用 ADO.NET 访问数据库的代码。
下面是我们的自定义 DbConnection 类的一些示例代码,显示了您可以完成的各种事情:
/// <summary>
/// Custom implementation of a wrapper to <see cref="DbConnection"/>.
/// Allows custom behavior at the connection level.
/// </summary>
internal class CustomDbConnection : DbConnectionWrapper
{
/// <summary>
/// Opens a database connection with the settings specified by
/// the <see cref="P:System.Data.Common.DbConnection.ConnectionString"/>.
/// </summary>
public override void Open()
{
base.Open();
//After the connection has been opened, use this spot to do any initialization type logic on/with the connection
}
/// <summary>
/// Closes the connection to the database. This is the preferred method of closing any open connection.
/// </summary>
/// <exception cref="T:System.Data.Common.DbException">
/// The connection-level error that occurred while opening the connection.
/// </exception>
public override void Close()
{
//Before closing, we do some cleanup with the connection to make sure we leave it clean
// for the next person that might get it....
CleanupConnection();
base.Close();
}
/// <summary>
/// Cleans up the connection so the next person that gets it doesn't inherit our junk.
/// </summary>
private void CleanupConnection()
{
//Create the ADO.NET command that will call our stored procedure
var cmd = CreateCommand();
cmd.CommandType = CommandType.StoredProcedure;
cmd.CommandText = "p_cleanup_connection";
//Run the SP
cmd.ExecuteNonQuery();
}
}