通过反射在脚本组件中组装适用于随机情况
Assembly in Script Component through reflection works for random cases
我有一个奇怪的问题。我有一个包含多个数据流的 SSIS 包,在其中我使用脚本组件作为编写 AVRO 文件的目标。现在为了编写这些 AVRO 文件,我正在使用 Microsoft.Hadoop.Avro.dll,我不想将其安装到 GAC,而只是使用反射进行引用。有一个很棒的指南 here,我一直在关注它。现在所有这些都在上周的一个演示项目中起作用了。然而,今天当我尝试将相同的内容合并到我的实际解决方案中时,一些数据流工作并且一切正常但是当相同的脚本组件被复制到另一个数据流并且 运行 使用另一个数据集时,它没有说它可以'找不到程序集。
需要注意的是——数据集没有任何问题,因为错误是"loading the assembly"。
Error: System.Reflection.TargetInvocationException: Exception has been thrown by the target of an invocation. ---> System.IO.FileNotFoundException: Could not load file or assembly 'Microsoft.Hadoop.Avro, Version=1.1.0.5, Culture=neutral, PublicKeyToken=31bf3856ad364e35' or one of its dependencies. The system cannot find the file specified.
我无计可施,因为它令人费解。
这是我使用的反射代码,它在一个数据流中工作,而不在另一个数据流中工作(在同一个包内)
public ScriptMain()
{
AppDomain.CurrentDomain.AssemblyResolve += new ResolveEventHandler(CurrentDomain_AssemblyResolve);
}
public System.Reflection.Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args)
{
string path = @"C:\Program Files\Microsoft SQL Server0\DTS\Binn\" ; //@"D:\AVRO Serialize and Deserialize\C#\bin\Debug\";
if (args.Name.Contains("Microsoft.Hadoop.Avro"))
{
return System.Reflection.Assembly.LoadFile(System.IO.Path.Combine(path, "Microsoft.Hadoop.Avro.dll"));
}
if (args.Name.Contains("Newtonsoft.Json"))
{
return System.Reflection.Assembly.LoadFile(System.IO.Path.Combine(path, "Newtonsoft.Json.dll"));
}
return null;
}
我已按照 post 的建议将程序集复制到 DTS\binn 文件夹中。
我如何查看 SSIS 运行时间正在查看哪些路径的日志,何时 运行?我不知道我还能提供什么信息,因为这真的很奇怪,但如果有人想让我提供更多细节,请告诉我,我可以编辑问题以包含更多细节。
P.S:我也将它添加到 GAC 一次,然后它起作用了,但我不想在服务器上这样做,而且反射确实在另一个项目中起作用
更多细节-上周所有数据流都在测试解决方案中工作-它的目标版本为 2017,它也显示在 Visual Studio 中的项目名称中。因此,在我遇到这个在一个数据流中而不是在另一个数据流中工作的奇怪问题的实际项目中,我尝试将目标服务器版本更改为 2017(从 2016 年开始),但项目名称的显示仍然显示 2016 年。这可能是问题所在吗?但是为什么即使将目标服务器版本更改为2017,项目的显示名称也不会更改为包括2017?
这就是它在所有工作的解决方案中的样子。
ProjectName (SQL Server 2017)
这就是越野车项目中的情况
ProjectName (SQL Server 2016)
即使将目标版本更改为 2017 也不会影响显示,但我怀疑这是问题所在
编辑 1:好的,我似乎已经弄清楚了问题所在。确实是这个版本。为什么显示名称没有更改为 2017,即使我已将目标服务器版本 属性 更改为 2017,是因为我没有在 "Active(development)" 配置中更改它。我改变了它,收到了一些来自 BIDS 的警告说要备份等等。但在那之后,相同的数据流开始工作,就像以前的项目一样。
所以,现在的问题是为什么这段代码适用于 SQL 2017 版的 SSIS 而不是 2016 版。我从这个 post here 了解到 "In SQL Server 2017, the IS assemblies were upgraded to .NET 4.0",但这不是 IS 本机程序集。
有谁知道更多吗?
所以,终于找到问题所在了。似乎 SSIS 目标版本 2016 和 2017 的行为有所不同。
我有一个 List 变量,我在定义它时就在 class 中初始化它,当然在反射有机会 运行.
之前调用它
所以,深入了解代码,原来是这样
public class ScriptMain : UserComponent
{
List<AvroRecord> CounterpartsRowList = new List<AvroRecord>(); //This line was the problem
public ScriptMain()
{
AppDomain.CurrentDomain.AssemblyResolve += new ResolveEventHandler(CurrentDomain_AssemblyResolve);
}
public System.Reflection.Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args)
{
string path = @"D:\BDS\clientscoredata\ClientScoreDataSsis";
if (args.Name.Contains("Microsoft.Hadoop.Avro"))
{
return System.Reflection.Assembly.LoadFile(System.IO.Path.Combine(path, "Microsoft.Hadoop.Avro.dll"));
}
if (args.Name.Contains("Newtonsoft.Json"))
{
return System.Reflection.Assembly.LoadFile(System.IO.Path.Combine(path, "Newtonsoft.Json.dll"));
}
return null;
}
/// <summary>
/// This method is called once, before rows begin to be processed in the data flow.
///
/// You can remove this method if you don't need to do anything here.
/// </summary>
public override void PreExecute()
{
base.PreExecute();
abc = new List<AvroRecord>(); // initialization moved here
所以基本上 abc 的初始化移到了 PreExecute 方法,而不是在它被定义的时候。
我有一个奇怪的问题。我有一个包含多个数据流的 SSIS 包,在其中我使用脚本组件作为编写 AVRO 文件的目标。现在为了编写这些 AVRO 文件,我正在使用 Microsoft.Hadoop.Avro.dll,我不想将其安装到 GAC,而只是使用反射进行引用。有一个很棒的指南 here,我一直在关注它。现在所有这些都在上周的一个演示项目中起作用了。然而,今天当我尝试将相同的内容合并到我的实际解决方案中时,一些数据流工作并且一切正常但是当相同的脚本组件被复制到另一个数据流并且 运行 使用另一个数据集时,它没有说它可以'找不到程序集。
需要注意的是——数据集没有任何问题,因为错误是"loading the assembly"。
Error: System.Reflection.TargetInvocationException: Exception has been thrown by the target of an invocation. ---> System.IO.FileNotFoundException: Could not load file or assembly 'Microsoft.Hadoop.Avro, Version=1.1.0.5, Culture=neutral, PublicKeyToken=31bf3856ad364e35' or one of its dependencies. The system cannot find the file specified.
我无计可施,因为它令人费解。
这是我使用的反射代码,它在一个数据流中工作,而不在另一个数据流中工作(在同一个包内)
public ScriptMain()
{
AppDomain.CurrentDomain.AssemblyResolve += new ResolveEventHandler(CurrentDomain_AssemblyResolve);
}
public System.Reflection.Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args)
{
string path = @"C:\Program Files\Microsoft SQL Server0\DTS\Binn\" ; //@"D:\AVRO Serialize and Deserialize\C#\bin\Debug\";
if (args.Name.Contains("Microsoft.Hadoop.Avro"))
{
return System.Reflection.Assembly.LoadFile(System.IO.Path.Combine(path, "Microsoft.Hadoop.Avro.dll"));
}
if (args.Name.Contains("Newtonsoft.Json"))
{
return System.Reflection.Assembly.LoadFile(System.IO.Path.Combine(path, "Newtonsoft.Json.dll"));
}
return null;
}
我已按照 post 的建议将程序集复制到 DTS\binn 文件夹中。
我如何查看 SSIS 运行时间正在查看哪些路径的日志,何时 运行?我不知道我还能提供什么信息,因为这真的很奇怪,但如果有人想让我提供更多细节,请告诉我,我可以编辑问题以包含更多细节。
P.S:我也将它添加到 GAC 一次,然后它起作用了,但我不想在服务器上这样做,而且反射确实在另一个项目中起作用
更多细节-上周所有数据流都在测试解决方案中工作-它的目标版本为 2017,它也显示在 Visual Studio 中的项目名称中。因此,在我遇到这个在一个数据流中而不是在另一个数据流中工作的奇怪问题的实际项目中,我尝试将目标服务器版本更改为 2017(从 2016 年开始),但项目名称的显示仍然显示 2016 年。这可能是问题所在吗?但是为什么即使将目标服务器版本更改为2017,项目的显示名称也不会更改为包括2017?
这就是它在所有工作的解决方案中的样子。
ProjectName (SQL Server 2017)
这就是越野车项目中的情况
ProjectName (SQL Server 2016)
即使将目标版本更改为 2017 也不会影响显示,但我怀疑这是问题所在
编辑 1:好的,我似乎已经弄清楚了问题所在。确实是这个版本。为什么显示名称没有更改为 2017,即使我已将目标服务器版本 属性 更改为 2017,是因为我没有在 "Active(development)" 配置中更改它。我改变了它,收到了一些来自 BIDS 的警告说要备份等等。但在那之后,相同的数据流开始工作,就像以前的项目一样。
所以,现在的问题是为什么这段代码适用于 SQL 2017 版的 SSIS 而不是 2016 版。我从这个 post here 了解到 "In SQL Server 2017, the IS assemblies were upgraded to .NET 4.0",但这不是 IS 本机程序集。
有谁知道更多吗?
所以,终于找到问题所在了。似乎 SSIS 目标版本 2016 和 2017 的行为有所不同。
我有一个 List 变量,我在定义它时就在 class 中初始化它,当然在反射有机会 运行.
之前调用它所以,深入了解代码,原来是这样
public class ScriptMain : UserComponent
{
List<AvroRecord> CounterpartsRowList = new List<AvroRecord>(); //This line was the problem
public ScriptMain()
{
AppDomain.CurrentDomain.AssemblyResolve += new ResolveEventHandler(CurrentDomain_AssemblyResolve);
}
public System.Reflection.Assembly CurrentDomain_AssemblyResolve(object sender, ResolveEventArgs args)
{
string path = @"D:\BDS\clientscoredata\ClientScoreDataSsis";
if (args.Name.Contains("Microsoft.Hadoop.Avro"))
{
return System.Reflection.Assembly.LoadFile(System.IO.Path.Combine(path, "Microsoft.Hadoop.Avro.dll"));
}
if (args.Name.Contains("Newtonsoft.Json"))
{
return System.Reflection.Assembly.LoadFile(System.IO.Path.Combine(path, "Newtonsoft.Json.dll"));
}
return null;
}
/// <summary>
/// This method is called once, before rows begin to be processed in the data flow.
///
/// You can remove this method if you don't need to do anything here.
/// </summary>
public override void PreExecute()
{
base.PreExecute();
abc = new List<AvroRecord>(); // initialization moved here
所以基本上 abc 的初始化移到了 PreExecute 方法,而不是在它被定义的时候。