msg*_*sme 3 sql-server sql-clr
我有一个 CLR 存储过程(除其他外)调用 TSQL 存储过程。TSQL 存储过程运行一些动态 SQL,并在运行前打印 SQL 以进行调试。PRINT
语句中没有任何内容显示在客户端中。当我们需要排除故障时,有什么好方法可以让我们看到这些命令?
示例代码:
dll中的C#代码
public static void Print_CLR()
{
using (SqlConnection conn = new SqlConnection("context connection=true"))
{
conn.Open();
using (SqlCommand c = new SqlCommand("exec dbo.Print_TSQL", conn))
{
c.ExecuteNonQuery();
}
}
}
Run Code Online (Sandbox Code Playgroud)
CLR 调用的 Proc
public static void Print_CLR()
{
using (SqlConnection conn = new SqlConnection("context connection=true"))
{
conn.Open();
using (SqlCommand c = new SqlCommand("exec dbo.Print_TSQL", conn))
{
c.ExecuteNonQuery();
}
}
}
Run Code Online (Sandbox Code Playgroud)
为了在 .NET 中捕获消息(来自PRINT
或RAISERROR('', 1, 10)
喜欢它)(无论是调用存储过程还是临时 SQL),您需要设置一个将被SqlConnection.InfoMessage事件调用的方法。
基本实现如下:
[SqlProcedure()]
public static void Print_CLR()
{
using (SqlConnection conn = new SqlConnection("context connection=true"))
{
conn.InfoMessage += new SqlInfoMessageEventHandler(CaptureMessage);
conn.Open();
using (SqlCommand c = new SqlCommand("exec dbo.Print_TSQL", conn))
{
c.ExecuteNonQuery();
}
}
}
private static void CaptureMessage(object sender, SqlInfoMessageEventArgs args)
{
// do something with args.Message
return;
}
Run Code Online (Sandbox Code Playgroud)
此时,您仍然需要对 Message 做一些事情。虽然有几个选项,但其中一些选项由于环境原因具有安全隐患。与在用于 Windows 应用程序、控制台应用程序和 ASP.NET 应用程序的操作系统上运行的主 CLR 相比,SQL Server 的 CLR 主机受到高度限制。
如果您使用static
如上所示的方法方法,那么您对 Message 执行的操作将影响PERMISSION_SET
包含此代码的程序集的值:
如果您只是想将消息打印回用户,那么您可以执行以下操作,这些操作可以在程序集中完成SAFE
:
SqlContext.Pipe.Send(args.Message);
Run Code Online (Sandbox Code Playgroud)如果要将消息写入文件,则可以执行以下操作,这些操作可以在程序集中完成EXTERNAL_ACCESS
:
File.AppendAllText(FILE_PATH_CONSTANT, args.Message);
Run Code Online (Sandbox Code Playgroud)
这可能会导致额外的延迟并且不值得。但另一方面,如果该过程在中间失败,则写入文件的任何内容仍然存在,因此这种方法肯定有一些好处。
但是如果你想将消息存储在一个变量中以便以后做一些事情,那么你将需要一个静态类变量,因为捕获消息的方法是static
. 例如,您可以声明private static m_Messages StringBuilder = new StringBuiler("");
. 然后,在您的CaptureMessage
方法中,您可以执行以下操作:
m_Messages.AppendLine(args.Message);
Run Code Online (Sandbox Code Playgroud)
这看起来很简单。并且对于 SQLCLR 之外的大多数环境来说都是如此。但是,在 SQLCLR 中使用静态变量要求程序集具有PERMISSION_SET
of UNSAFE
,并且最好尽可能避免这种情况。需要将程序集标记为的原因UNSAFE
是运行此代码的 AppDomain 在所有会话/SPID 之间共享。因此,静态类变量也在会话之间共享,这可能导致非常奇怪的行为。
值得庆幸的是,如果您想将消息收集到实例变量,则不会失去所有希望。为此,您需要使用匿名委托内联定义处理程序。匿名方法与代码的其余部分在同一范围内,因此它可以访问局部变量。这非常方便,因为它允许您轻松地将消息存储在具有PERMISSION_SET
of SAFE
(非常受欢迎)的程序集中。
[SqlProcedure()]
public static void Print_CLR()
{
StringBuilder _Messages = new StringBuilder("");
using (SqlConnection conn = new SqlConnection("context connection=true"))
{
conn.InfoMessage += delegate(object sender, SqlInfoMessageEventArgs args)
{
SqlConnection _Connection = (SqlConnection)sender;
// _Connection.DataSource is the "Server" of the ConnectionString
// _Connection.Database is the CURRENT database of the Connection
_Messages.Append(args.Message);
return;
};
conn.Open();
using (SqlCommand c = new SqlCommand("exec dbo.Print_TSQL", conn))
{
c.ExecuteNonQuery();
}
}
}
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
4925 次 |
最近记录: |