为什么我的存储过程不执行带有某些 ID 的 CLR 方法?
Why is not my stored procedure executing CLR method with some id's?
简而言之,我有一个 CLR 方法可以从 SQL 服务器向用户发送电子邮件。我的 SQL 服务器 table 中有关于正文、附件、主题、电子邮件等的所有数据信息。好吧,我正在用 C# 做一个应用程序来做到这一点,我没有遇到在 tables 中使用存储过程保存信息的麻烦,但是当我想执行我的 SP 发送 id(邮件)时。这表示 'Command completed successfully' 但邮件不发送。然后我测试从 SQL 服务器手动执行我的 SP,并正确发送一些 id 和一些不 'watch' 我的发送方法,因为这正确执行命令但做任何事情。为什么会这样?有人遇到过这个问题吗??
这是我的 CLR 方法
[SqlProcedure]
public static int CustomMethod(int id_email, out string sError)
{
int mReturn = 0;
DataSet ds = new DataSet();
sError = string.Empty;
Dictionary<int, string> ListFile = new Dictionary<int, string>();
try
{
ds = retornarQuery(strQuery: "ZeusFW_Email_List " + id_email);
if (ds.Tables[0].Rows.Count > 0)
{
for (int i = 0; i <= ds.Tables[0].Rows.Count - 1; i++)
{
DataRow row = ds.Tables[0].Rows[i];
string ds_to_name = (string)row["ds_to_name"];
string ds_to_email = (string)row["ds_to_email"];
string ds_cc_email = (string)row["ds_cc_email"];
string ds_bcc_email = (string)row["ds_bcc_email"];
string ds_idiom = (string)row["ds_idiom"];
string ds_subject = (string)row["ds_subject"];
string ds_body = (string)row["ds_body"];
int am_sent_times = (int)row["am_sent_times"];
int in_process = (int)row["in_process"];
int am_email_port = (int)row["am_email_port"];
string ds_email_host = (string)row["ds_email_host"];
string ds_email_user = (string)row["ds_email_user"];
string ds_email_password = (string)row["ds_email_password"];
int am_email_html = (int)row["am_email_html"];
int am_email_ssl = (int)row["am_email_ssl"];
string ds_email_name = (string)row["ds_email_name"];
string ds_email_xsl = (string)row["ds_email_xsl"];
int in_email_log = (int)row["in_email_log"];
DeliveryNotificationOptions am_notificationoptions = NotificationOptions((int)row["am_notificationoptions"]);
MailPriority am_priority = Priority((int)row["am_priority"]);
if (in_process == 0 && am_email_html == 1)
{
ds_body = DoXSLT(ds_body, ds_email_xsl);
}
ZeusFrameworkSmtp.ZeusFrameworkSmtp email = new ZeusFrameworkSmtp.ZeusFrameworkSmtp();
email.AddFrom = ds_email_user;
email.AddName = ds_email_name;
email.AddTo.Add(ds_to_email);
if (ds_cc_email != null || !ds_cc_email.Equals("")) email.AddCC = ds_cc_email;
if (ds_bcc_email != null || !ds_bcc_email.Equals("")) email.AddBcc = ds_bcc_email;
if (am_sent_times > 0) { ds_subject = "Re#" + am_sent_times + " " + ds_subject; }
email.Subject = ds_subject;
email.Body = ds_body;
email.BodyHtml = (am_email_html == 0 ? false : true);
email.Server = ds_email_host;
email.Port = am_email_port;
email.User = ds_email_user;
email.Password = ds_email_password;
email.EnableSsl = (am_email_ssl == 0 ? false : true); ;
email.NotificationOptions = am_notificationoptions;
email.Priority = am_priority;
am_sent_times = am_sent_times + 1;
if (ds.Tables[1].Rows.Count > 0)
{
for (int j = 0; j <= ds.Tables[1].Rows.Count - 1; j++)
{
DataRow rowAttachments = ds.Tables[1].Rows[j];
if (id_email == (int)rowAttachments["id_email"])
{
if ((int)rowAttachments["in_delete_file"] == 1) ListFile.Add(j, (string)rowAttachments["ds_full_path"]);
email.AddAttachments.Add((string)rowAttachments["ds_full_path"]);
}
}
}
bool bresult = email.Send(out sError);
//if (bresult) { mReturn = 1; Database.ZeusFW_Email_Update(id_email, am_sent_times, sError, in_email_log).Run(); }
if (string.IsNullOrEmpty(sError) || sError.Equals("ESTOY EJECUTANDO EL METODO")) sError = "Operación completada con éxito.";
if (ListFile.Count > 0)
{
foreach (KeyValuePair<int, string> item in ListFile)
{
if (item.Key == 1) File.Delete(item.Value.ToString());
}
ListFile.Clear();
}
}
}
else sError = "No se encontró el ID";
}
catch (Exception ex)
{
StringBuilder s = new StringBuilder();
//sError = sError + "-" + "Error executing SQL statement information: " + ex.Message + "id_email : " + id_email.ToString() + "Conn : " + Database.ConnectionString + ex.StackTrace.ToString();
LogWindows _LogWindows = new LogWindows();
_LogWindows.Save("Zeus", sError, System.Diagnostics.EventLogEntryType.Error);
//SqlContext.Pipe.Send("Error executing SQL statement information: " + ex.Message + "id_email> " + id_email_aux.ToString() + "Conn>" + Database.ConnectionString);
}
return mReturn;
}
这是我的存储过程
CREATE PROCEDURE [dbo].[CustomMethod]
@id_email int
,@sError nvarchar(2000)=NULL OUTPUT
WITH EXECUTE AS CALLER
AS
EXTERNAL NAME [AssemblyNamespace].[AssemblyNamespace.AssemblyNamespace1].[CustomMethod]
GO
这两个 ID 都存在于我的 sql table 中,就像有效邮件一样。忽略 SP 的名称是为了保护它们在 CLR 方法和存储过程中具有相同的名称
我在 SQL 服务器中遇到了这个异常。
Mens 6522, Nivel 16, Estado 1, Procedimiento ZeusFW_EmailqueueUnit_SendOutError, Línea 2
A .NET Framework error occurred during execution of user-defined routine or aggregate "ZeusFW_EmailqueueUnit_SendOutError":
System.IO.IOException: El sistema no puede ponerse en contacto con un controlador de dominio para que atienda la solicitud de autenticación. Inténtelo de nuevo más tarde.
System.IO.IOException:
en System.IO.__Error.WinIOError(Int32 errorCode, String maybeFullPath)
en System.IO.FileStream.Init(String path, FileMode mode, FileAccess access, Int32 rights, Boolean useRights, FileShare share, Int32 bufferSize, FileOptions options, SECURITY_ATTRIBUTES secAttrs, String msgPath, Boolean bFromProxy)
en System.IO.FileStream..ctor(String path, FileMode mode, FileAccess access, FileShare share, Int32 bufferSize, FileOptions options, String msgPath, Boolean bFromProxy)
en System.IO.FileStream..ctor(String path, FileMode mode, FileAccess access, FileShare share)
en System.Net.Mail.AttachmentBase.SetContentFromFile(String fileName, String mediaType)
en System.Net.Mail.Attachment..ctor(String fileName)
en ZeusFrameworkSmtp.ZeusFrameworkSmtp.Send(String& error)
en AssemblyZeusSMTP.AssemblyZeusSMTP.ZeusFW_EmailqueueUnit_SendOutError(SqlInt32 id_email, SqlString& sError)
这里有一些要看的东西:
请使用 Sql*
类型而不是本机 .NET 类型作为 SQLCLR public 方法的输入和输出参数。所以签名应该是:
public static SqlInt32 CustomMethod(SqlInt32 id_email, out SqlString sError)
您可以通过它们都具有的 .Value
属性 从任何这些类型中获取本机值(例如 id_email.Value
)。
您经历了传回状态代码的麻烦,所以捕获它以便您可以看到更多正在发生的事情。在C#代码中,根据bresult
:
给mReturn
赋一个非零值
if (bresult)
{
mReturn = 1;
}
else
{
mReturn = 2;
}
然后将您的 T-SQL 更改为:
DECLARE @id_email INT,
@sError NVARCHAR(4000),
@return_code INT;
SET @id_email = 37;
EXEC @return_code = dbo.ZeusFW_EmailQueueUnit_SendOutError
@id_email,
@sError OUTPUT;
SELECT @return_code AS [ReturnCode],
N'~' + @sError + N'~' AS [ErrorMessage],
DATALENGTH(@sError) AS [ErrorMessageBytes];
查看发布的代码,似乎为 @sError
获取空字符串的唯一方法(它真的是空的吗?)是:
email.Send()
实际上是传回一个非空的白色字符串-space and/or 其他不可打印的字符。上面显示的 T-SQL 已经过调整以检查这一点。
- 代码出现异常,在这种情况下,您应该会在 Windows 事件日志中看到一些内容(因为您正在那里保存条目)。您检查过 Windows 事件日志了吗?
- 您可以检查 Zeus 框架中的任何日志记录吗?
- 最重要的是: 为什么要从 SQLCLR 发送电子邮件,而 SQL 服务器为此内置了一个异步函数?它可以处理文件附件、HTML 电子邮件正文等。请考虑将此 SQLCLR 存储过程换成调用 sp_send_dbmail 的 T-SQL 存储过程(引入在 SQL Server 2008 中,甚至可能在 2005 中)。
其他说明:
- 如果您不再为变量添加数据类型前缀,生活将会更轻松,您的代码将更具可读性。所以用
Result
代替mReturn
,用Result
代替bResult
,用ErrorMessage
代替sError
。这适用于 C# 和 T-SQL.
- 没有必要在循环中从
Count
中减去 1
,因为这会迫使您使用 <=
而不仅仅是 <
。使用 j < ds.Tables[1].Rows.Count
在逻辑上是相同的,少了一个(不必要的)操作,并且更具可读性:-).
简而言之,我有一个 CLR 方法可以从 SQL 服务器向用户发送电子邮件。我的 SQL 服务器 table 中有关于正文、附件、主题、电子邮件等的所有数据信息。好吧,我正在用 C# 做一个应用程序来做到这一点,我没有遇到在 tables 中使用存储过程保存信息的麻烦,但是当我想执行我的 SP 发送 id(邮件)时。这表示 'Command completed successfully' 但邮件不发送。然后我测试从 SQL 服务器手动执行我的 SP,并正确发送一些 id 和一些不 'watch' 我的发送方法,因为这正确执行命令但做任何事情。为什么会这样?有人遇到过这个问题吗??
这是我的 CLR 方法
[SqlProcedure]
public static int CustomMethod(int id_email, out string sError)
{
int mReturn = 0;
DataSet ds = new DataSet();
sError = string.Empty;
Dictionary<int, string> ListFile = new Dictionary<int, string>();
try
{
ds = retornarQuery(strQuery: "ZeusFW_Email_List " + id_email);
if (ds.Tables[0].Rows.Count > 0)
{
for (int i = 0; i <= ds.Tables[0].Rows.Count - 1; i++)
{
DataRow row = ds.Tables[0].Rows[i];
string ds_to_name = (string)row["ds_to_name"];
string ds_to_email = (string)row["ds_to_email"];
string ds_cc_email = (string)row["ds_cc_email"];
string ds_bcc_email = (string)row["ds_bcc_email"];
string ds_idiom = (string)row["ds_idiom"];
string ds_subject = (string)row["ds_subject"];
string ds_body = (string)row["ds_body"];
int am_sent_times = (int)row["am_sent_times"];
int in_process = (int)row["in_process"];
int am_email_port = (int)row["am_email_port"];
string ds_email_host = (string)row["ds_email_host"];
string ds_email_user = (string)row["ds_email_user"];
string ds_email_password = (string)row["ds_email_password"];
int am_email_html = (int)row["am_email_html"];
int am_email_ssl = (int)row["am_email_ssl"];
string ds_email_name = (string)row["ds_email_name"];
string ds_email_xsl = (string)row["ds_email_xsl"];
int in_email_log = (int)row["in_email_log"];
DeliveryNotificationOptions am_notificationoptions = NotificationOptions((int)row["am_notificationoptions"]);
MailPriority am_priority = Priority((int)row["am_priority"]);
if (in_process == 0 && am_email_html == 1)
{
ds_body = DoXSLT(ds_body, ds_email_xsl);
}
ZeusFrameworkSmtp.ZeusFrameworkSmtp email = new ZeusFrameworkSmtp.ZeusFrameworkSmtp();
email.AddFrom = ds_email_user;
email.AddName = ds_email_name;
email.AddTo.Add(ds_to_email);
if (ds_cc_email != null || !ds_cc_email.Equals("")) email.AddCC = ds_cc_email;
if (ds_bcc_email != null || !ds_bcc_email.Equals("")) email.AddBcc = ds_bcc_email;
if (am_sent_times > 0) { ds_subject = "Re#" + am_sent_times + " " + ds_subject; }
email.Subject = ds_subject;
email.Body = ds_body;
email.BodyHtml = (am_email_html == 0 ? false : true);
email.Server = ds_email_host;
email.Port = am_email_port;
email.User = ds_email_user;
email.Password = ds_email_password;
email.EnableSsl = (am_email_ssl == 0 ? false : true); ;
email.NotificationOptions = am_notificationoptions;
email.Priority = am_priority;
am_sent_times = am_sent_times + 1;
if (ds.Tables[1].Rows.Count > 0)
{
for (int j = 0; j <= ds.Tables[1].Rows.Count - 1; j++)
{
DataRow rowAttachments = ds.Tables[1].Rows[j];
if (id_email == (int)rowAttachments["id_email"])
{
if ((int)rowAttachments["in_delete_file"] == 1) ListFile.Add(j, (string)rowAttachments["ds_full_path"]);
email.AddAttachments.Add((string)rowAttachments["ds_full_path"]);
}
}
}
bool bresult = email.Send(out sError);
//if (bresult) { mReturn = 1; Database.ZeusFW_Email_Update(id_email, am_sent_times, sError, in_email_log).Run(); }
if (string.IsNullOrEmpty(sError) || sError.Equals("ESTOY EJECUTANDO EL METODO")) sError = "Operación completada con éxito.";
if (ListFile.Count > 0)
{
foreach (KeyValuePair<int, string> item in ListFile)
{
if (item.Key == 1) File.Delete(item.Value.ToString());
}
ListFile.Clear();
}
}
}
else sError = "No se encontró el ID";
}
catch (Exception ex)
{
StringBuilder s = new StringBuilder();
//sError = sError + "-" + "Error executing SQL statement information: " + ex.Message + "id_email : " + id_email.ToString() + "Conn : " + Database.ConnectionString + ex.StackTrace.ToString();
LogWindows _LogWindows = new LogWindows();
_LogWindows.Save("Zeus", sError, System.Diagnostics.EventLogEntryType.Error);
//SqlContext.Pipe.Send("Error executing SQL statement information: " + ex.Message + "id_email> " + id_email_aux.ToString() + "Conn>" + Database.ConnectionString);
}
return mReturn;
}
这是我的存储过程
CREATE PROCEDURE [dbo].[CustomMethod]
@id_email int
,@sError nvarchar(2000)=NULL OUTPUT
WITH EXECUTE AS CALLER
AS
EXTERNAL NAME [AssemblyNamespace].[AssemblyNamespace.AssemblyNamespace1].[CustomMethod]
GO
这两个 ID 都存在于我的 sql table 中,就像有效邮件一样。忽略 SP 的名称是为了保护它们在 CLR 方法和存储过程中具有相同的名称
我在 SQL 服务器中遇到了这个异常。
Mens 6522, Nivel 16, Estado 1, Procedimiento ZeusFW_EmailqueueUnit_SendOutError, Línea 2
A .NET Framework error occurred during execution of user-defined routine or aggregate "ZeusFW_EmailqueueUnit_SendOutError":System.IO.IOException: El sistema no puede ponerse en contacto con un controlador de dominio para que atienda la solicitud de autenticación. Inténtelo de nuevo más tarde.
System.IO.IOException:
en System.IO.__Error.WinIOError(Int32 errorCode, String maybeFullPath)
en System.IO.FileStream.Init(String path, FileMode mode, FileAccess access, Int32 rights, Boolean useRights, FileShare share, Int32 bufferSize, FileOptions options, SECURITY_ATTRIBUTES secAttrs, String msgPath, Boolean bFromProxy)
en System.IO.FileStream..ctor(String path, FileMode mode, FileAccess access, FileShare share, Int32 bufferSize, FileOptions options, String msgPath, Boolean bFromProxy)
en System.IO.FileStream..ctor(String path, FileMode mode, FileAccess access, FileShare share)
en System.Net.Mail.AttachmentBase.SetContentFromFile(String fileName, String mediaType)
en System.Net.Mail.Attachment..ctor(String fileName)
en ZeusFrameworkSmtp.ZeusFrameworkSmtp.Send(String& error)
en AssemblyZeusSMTP.AssemblyZeusSMTP.ZeusFW_EmailqueueUnit_SendOutError(SqlInt32 id_email, SqlString& sError)
这里有一些要看的东西:
请使用
Sql*
类型而不是本机 .NET 类型作为 SQLCLR public 方法的输入和输出参数。所以签名应该是:public static SqlInt32 CustomMethod(SqlInt32 id_email, out SqlString sError)
您可以通过它们都具有的
.Value
属性 从任何这些类型中获取本机值(例如id_email.Value
)。您经历了传回状态代码的麻烦,所以捕获它以便您可以看到更多正在发生的事情。在C#代码中,根据
给bresult
:mReturn
赋一个非零值if (bresult) { mReturn = 1; } else { mReturn = 2; }
然后将您的 T-SQL 更改为:
DECLARE @id_email INT, @sError NVARCHAR(4000), @return_code INT; SET @id_email = 37; EXEC @return_code = dbo.ZeusFW_EmailQueueUnit_SendOutError @id_email, @sError OUTPUT; SELECT @return_code AS [ReturnCode], N'~' + @sError + N'~' AS [ErrorMessage], DATALENGTH(@sError) AS [ErrorMessageBytes];
查看发布的代码,似乎为
@sError
获取空字符串的唯一方法(它真的是空的吗?)是:email.Send()
实际上是传回一个非空的白色字符串-space and/or 其他不可打印的字符。上面显示的 T-SQL 已经过调整以检查这一点。- 代码出现异常,在这种情况下,您应该会在 Windows 事件日志中看到一些内容(因为您正在那里保存条目)。您检查过 Windows 事件日志了吗?
- 您可以检查 Zeus 框架中的任何日志记录吗?
- 最重要的是: 为什么要从 SQLCLR 发送电子邮件,而 SQL 服务器为此内置了一个异步函数?它可以处理文件附件、HTML 电子邮件正文等。请考虑将此 SQLCLR 存储过程换成调用 sp_send_dbmail 的 T-SQL 存储过程(引入在 SQL Server 2008 中,甚至可能在 2005 中)。
其他说明:
- 如果您不再为变量添加数据类型前缀,生活将会更轻松,您的代码将更具可读性。所以用
Result
代替mReturn
,用Result
代替bResult
,用ErrorMessage
代替sError
。这适用于 C# 和 T-SQL. - 没有必要在循环中从
Count
中减去1
,因为这会迫使您使用<=
而不仅仅是<
。使用j < ds.Tables[1].Rows.Count
在逻辑上是相同的,少了一个(不必要的)操作,并且更具可读性:-).