我想知道是否有一个事件可以处理事件在SqlConnection关闭之前触发的位置,即:OnBeforeClose
?我想要实现的是 - 在SQL Server中调用sp_unsetapprole
,以便在连接关闭并返回到连接轮询时 - 因此它没有附加的关联。
起初我以为我可以处理StateChange
事件 - 但我相信已经太晚了。
我目前的解决方法是在SqlConnection调用方上手动调用sp_unsetapprole
。
非常感谢您的关注+时间!
YS。
答案 0 :(得分:2)
当事件触发时太晚,无法运行任何类型的SQL批处理。我建议您按照MSDN recommendation on the subject:
进行操作通过调用激活SQL Server应用程序角色后
sp_setapprole
系统存储过程,即安全上下文 连接无法重置。但是,如果启用了池,则 连接返回到池,并在发生时发生错误 汇集连接被重用。
当提出这些建议时,试图反对它们通常是一个坏主意。您可以放弃应用角色there are better alternatives:
应用程序角色替代
应用程序角色取决于密码的安全性 潜在的安全漏洞。密码可能会被暴露 嵌入应用程序代码或保存在磁盘上。您可能需要考虑以下备选方案:
将上下文切换与EXECUTE AS语句及其NO REVERT和WITH COOKIE子句一起使用。您可以在中创建用户帐户 未映射到登录的数据库。然后,您可以分配权限 此帐户。将EXECUTE AS与无登录用户一起使用会更安全 因为它是基于权限的,而不是基于密码的。更多 信息,请参阅Customizing Permissions with Impersonation in SQL Server。
使用证书对存储过程进行签名,仅授予执行过程的权限。有关详细信息,请参阅Signing Stored Procedures in SQL Server。
答案 1 :(得分:1)
我知道这已经很晚了,但我遇到了这个答案,并想在那里抛出另一个选项。我们的申请要求非常相似。我们需要在每次打开连接时调用自定义存储过程,并在关闭时再次调用。
我们能够在EF Provider Wrapper Toolkit的帮助下处理这个问题(现在似乎也在Nuget上)。这基本上允许您将自己的逻辑注入到各种ADO.NET对象中 - 因此在最低级别的数据库访问中。然后我们制作了自己的自定义DbConnection类,您的应用中的任何代码都将最终使用。它实际上非常简单,并且在最低级别的数据库访问中给了我们很多很好的“钩子”,它们已经派上了用场。
请注意,我们使用的是实体框架,该库名为 EF 提供程序包装工具包,但它适用于使用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();
}
}