当我尝试从SQL Server 2008 R2执行C#CLR存储过程时出现以下错误:
Msg 6522,Level 16,State 1,Procedure PrintShippingDocLabelsToPDF,Line 0
执行用户定义的例程或聚合期间发生.NET Framework错误" PrintShippingDocLabelsToPDF":
System.InvalidOperationException:无法加载动态生成的序列化程序集。在某些托管环境中,组件加载功能受到限制,请考虑使用预生成的序列化程序。有关详细信息,请参阅内部异常。 --->
System.IO.FileLoadException:主机已禁用LoadFrom(),LoadFile(),Load(byte [])和LoadModule()。 System.IO.FileLoadException:
我的理解是,这正是因为我正在努力而发生的 写入网络共享上的文件。我查看了以下来源:https://msdn.microsoft.com/en-us/library/ms345106(v=sql.105).aspx,Accessing Sql FILESTREAM from within a CLR stored procedure,但我仍然迷失了。
我需要做的就是将SSRS中的多个报告写入网络共享上的xxx.pdf
文件(其中xxx表示自定义名称)。此功能的代码如下所示,我相当确定下面的部分是导致错误。
// Create a file stream and write the report to it
using (FileStream stream = File.OpenWrite(strFilePath + strFileName))
{
stream.Write(results, 0, results.Length);
} // END using (FileStream stream = File.OpenWrite(StoredProcedures.strFilePath + StoredProcedures.strFileName))
这是完整的程序。请问有人能指点我吗?我正在紧张的截止日期前工作。作为临时解决方案,也许可以将这些报告写入临时表,然后使用SSIS包将它们移动到文件夹。如果有可能,有人可以给我一个关于如何存储这些文件的指针(varbinary(MAX这些文件大小约为60KB-150KB)?
public static void PrintShippingDocLabelsToPDF()
{
// Put your code here
using (SqlConnection sqlConnTestDB = new SqlConnection("context connection=true"))
{
string sql4ConnectionString = "connection string";
string sqlConnStrTestDB = sql4ConnectionString;
// Select all unprinted SPSNumbers
// If IsValidatedByWms == 0 --> SPS Not printed
// If IsValidatedByWms == 1 --> SPS is printed
string sqlCmdSlctTblPicking = @"SELECT SPSNumber, IsValidatedByWms AS LabelPrintStatus
FROM TestDB.dbo.tblPickingSlip WHERE IsValidatedByWms = 0";
//SqlConnection sqlConnTestDB = new SqlConnection(sqlConnStrTestDB);
SqlCommand sqlCmdSlctPicking = new SqlCommand(sqlCmdSlctTblPicking, sqlConnTestDB);
// Select all SPSNumbers that have invoices against them
// SPS number will be coming from tblPicking
// If SPSNumber is NULL --> No invoice against SPS
// If SPSNumber is NOT NULL --> There is an invoice against the SPS
string sqlCmdStrSlctTblInvoiceItem = @"SELECT DISTINCT SPSNumber
FROM TestDB.dbo.tblInvoiceItem
WHERE SPSNumber IS NOT NULL ";
SqlCommand sqlCmdSlctTblInvoiceItem = new SqlCommand(sqlCmdStrSlctTblInvoiceItem, sqlConnTestDB);
DataTable dtPicking = new DataTable();
SqlDataAdapter sqlPickingAdapter = new SqlDataAdapter(sqlCmdSlctPicking);
sqlPickingAdapter.Fill(dtPicking);
DataTable dtTblInvoiceItem = new DataTable();
SqlDataAdapter sqlTblInvoiceItemAdapter = new SqlDataAdapter();
// Update print status of printed lables, labels only print for SPSNumbers that have invoices against them
string sqlCmdStrUpdate = @"UPDATE TestDB.dbo.tblPickingSlip
SET IsValidatedByWms = 1
WHERE SPSNumber = ";
SqlCommand sqlCmdUpdateSlctPicking = new SqlCommand(sqlCmdStrUpdate, sqlConnTestDB);
string strSpsNumber = null; // keep track of the SPSNumber
// Inspect the Picking table
foreach (DataRow row in dtPicking.Rows)
{
if (Convert.ToInt32(row["LabelPrintStatus"]) == 0)
{
// a label has not been printed for the associated SPSNumber
// check if the particualr SPSNumber has an assocaited invoice
strSpsNumber = row["SPSNumber"].ToString();
// add SPSNumber to query that selects all SPSNumbers that
// have invoices against them
string sqlCmdStrSlctTblInvoiceItem2 = sqlCmdStrSlctTblInvoiceItem + "AND SPSNumber = '" + strSpsNumber + "'";
sqlCmdSlctTblInvoiceItem.CommandText = sqlCmdStrSlctTblInvoiceItem2;
sqlTblInvoiceItemAdapter.SelectCommand = sqlCmdSlctTblInvoiceItem;
sqlTblInvoiceItemAdapter.Fill(dtTblInvoiceItem);
// Inspect tblInvoiceItem and print all SPSNumbers that have invoices against them
if (dtTblInvoiceItem != null)
if (dtTblInvoiceItem.Rows.Count > 0)
{
foreach (DataRow r in dtTblInvoiceItem.Rows)
{
// Write the report to the ExportFilePath
//WriteReport(strSpsNumber);
string ExportFilePath = @"\\testsrv\EXPORT\"; // locaiton where PDF reports will be written.
string ReportPath = @"/xxx/Report1"; // Path to report on modabackupsql reportserver
string FileExtentionPDF = @".pdf";
PrintShippingDocLabelPDF.REService2005.ReportExecutionService _re; // proxy class for the report execution for
// Report arguments
string report = ReportPath;
string historyID = null;
string deviceInfo = null;
string format = @"PDF";
Byte[] results;
string encoding = String.Empty;
string mimeType = String.Empty;
string extension = String.Empty;
PrintShippingDocLabelPDF.REService2005.Warning[] warnings = null;
string[] streamIDs = null;
string strFilePath = ExportFilePath; // location for writing PDF labels generated from executed reports
string strFileName; // the name of pdf labels generated from executed reports
_re = new PrintShippingDocLabelPDF.REService2005.ReportExecutionService();
_re.Credentials = System.Net.CredentialCache.DefaultCredentials;
// Prepare Render arguments
PrintShippingDocLabelPDF.REService2005.ExecutionInfo ei = _re.LoadReport(report, historyID);
PrintShippingDocLabelPDF.REService2005.ParameterValue[] parameters = new PrintShippingDocLabelPDF.REService2005.ParameterValue[1];
// add the spsnumber as the report parameter
parameters[0] = new PrintShippingDocLabelPDF.REService2005.ParameterValue();
parameters[0].Name = "spsnumber";
parameters[0].Value = strSpsNumber;
strFileName = strSpsNumber + FileExtentionPDF;
// set the execution parameters
_re.SetExecutionParameters(parameters, "en-us");
// render the report
results = _re.Render(format, deviceInfo, out extension, out encoding, out mimeType, out warnings, out streamIDs);
// Create a file stream and write the report to it
using (FileStream stream = File.OpenWrite(strFilePath + strFileName))
{
stream.Write(results, 0, results.Length);
} // END using (FileStream stream = File.OpenWrite(StoredProcedures.strFilePath + StoredProcedures.strFileName))
// Set the IsValidatedByWms associated with SPSNumber to 1
// to indicate that the report has been printed.
//sqlConnTestDB.Open();
sqlCmdUpdateSlctPicking.CommandText = sqlCmdStrUpdate + "'" + strSpsNumber + "'";
sqlCmdUpdateSlctPicking.ExecuteNonQuery();
//sqlConnTestDB.Close();
} // END foreach (DataRow r in dtTblInvoiceItem.Rows)
dtTblInvoiceItem.Clear();
} // if (dtTblInvoiceItem.Rows.Count > 0)
} // END if (Convert.ToInt32(row["LabelPrintStatus"]) == 0)
} // END foreach (DataRow row in dtPicking.Rows)
} // END using (SqlConnection sqlConnTestDB = new SqlConnection("context connection=true"))
} // END public static void PrintShippingDocLabelsToPDF()
答案 0 :(得分:0)
首先,关于这个问题的一些注意事项:
无法加载动态生成的序列化程序集。
序列化程序集用于通过Web服务进行通信
System.IO.FileLoadException
此错误不是来自您的代码,因为您没有加载文件。您正在尝试保存文件。两者都要求尝试操作的程序集PERMISSION_SET
EXTERNAL_ACCESS
,但加载和保存不是一回事。
主机已禁用LoadFrom(),LoadFile(),Load(byte [])和LoadModule()。
这很可能是因为没有将程序集的PERMISSION_SET
设置为EXTERNAL_ACCESS
。这需要将数据库设置为TRUSTWORTHY ON
(不好)或根据您为程序集签名的密钥创建登录,并授予登录EXTERNAL ACCESS ASSEMBLY
权限。
出于测试目的,您可以执行以下操作以查看它是否有效。将程序集部署为SAFE
后,运行以下命令:
ALTER DATABASE [{db_name}] SET TRUSTWORTHY ON;
ALTER ASSEMBLY [{assembly_name}] WITH PERMISSION_SET = EXTERNAL_ACCESS;
然后尝试再次运行存储过程。你应该至少走得更远。但是,考虑到代码的当前形式,并且因为您说它已经作为控制台应用程序运行,我认为您最好保持这种方式并从xp_cmdshell
运行它,或者如果尚未启用它,从SQL代理作业的Command步骤运行它。
我认为可能在SQLCLR中工作,但首先需要进行一些重组。
spsnumber
。通过CURSOR
在T-SQL中获取该列表,然后在SPSNumber
中调用此过程。一般说明:
请不要将字符串连接到查询中,因为这会打开您可能的SQL注入。相反,声明参数如下:
SqlParameter _SpsNumber = new SqlParameter("@SpsNumber", SqlDbType.Int);
sqlCmdUpdateSlctPicking.Parameters.Add(_SpsNumber);
然后您更新sqlCmdStrUpdate
以@SpsNumber
结束,而不是为每个项目更新sqlCmdUpdateSlctPicking.CommandText
,而只需致电_SpsNumber.Value = strSpsNumber;
(尽管您可能需要{ {1}}如果它抱怨)。
您不需要两个Int32.Parse(strSpsNumber)
语句:if
和dtTblInvoiceItem != null
。只需将它们合并到dtTblInvoiceItem.Rows.Count > 0