将 .NET 程序集转换为 Silverlight 程序集






4.92/5 (15投票s)
与 Silverlight 共享您的 .NET 程序集。
引言
本文旨在通过创建一个简单的控制台应用程序来解决 David Betz 在其文章 在 Silverlight 中重用 .NET 程序集 中提出的问题,该应用程序可在生成后命令中使用。
背景
现在 Silverlight 已进入第二版,并被越来越多的开发人员采用,该框架正在开发更高级的应用程序。
Silverlight 的强大功能之一是它与 WCF 服务的连接。由于大多数架构师选择在公共程序集中实现合同类,然后由服务实现者和客户端引用,因此在尝试通过 Silverlight 应用程序引用此公共程序集时会发生问题。
我不会详细说明 Visual Studio 为什么不允许您将非 Silverlight 程序集添加到 Silverlight 项目中,因为 David Betz 在其 NeFX harmonics 网站上发表的文章中对此进行了深入介绍。但简而言之,Silverlight 使用的程序集(*System.dll*、*mscorlib.dll* 等)与基本的 .NET 程序集不同,尽管许多函数在这两者中都存在。可以说 Silverlight 程序集是完整 .NET 程序集的精简版本,但暴露的功能几乎相同。
因此,基本上,如果我们能够修改我们的公共程序集以引用这些程序集的 Silverlight 版本而不修改代码,我们就可以在我们的 Silverlight 应用程序中重用我们的公共程序集。
MSIL 程序集
基本上,当您使用任何 .NET 语言(C#、VB.NET)编写代码时,编译器会将代码编译成所谓的 MSIL 或 Microsoft Intermediate Language。然后,此代码将被组装成 .NET 程序集,该程序集在运行时被加载和 JIT 编译。由于程序集引用仅在运行时进行验证,因此我们可以安全地将有问题的程序集的引用更改为 IL 代码中正确的 Silverlight 程序集,并且当程序集通过 Silverlight 加载时,正确的程序集将已在内存中,JIT 编译器将针对它编译我们的代码。
我们的目标
所以,为了保持简单,我们基本上想做的是,一旦程序集构建完成,将其反汇编回 MSIL,在引用中做一些更改(也许删除一些 Silverlight 版本引用不支持的属性),然后将代码重新组装成 Silverlight 可以使用的新程序集。
注意:我们将创建的新程序集只能从 Silverlight 项目中使用,但所有类型签名将与我们的原始程序集相同,因此我们可以共享两者之间的 WCF 合同。
设置应用程序
包含的代码是一个用 C# 编写的简单控制台应用程序。它附带一个包含运行所需的所有设置的 XML 文件。
基本上,该应用程序需要以下信息:
- MSIL 汇编器和反汇编器的位置(*ilasm.exe* 和 *ildasm.exe*)。
- 一个程序集列表,这些程序集在其 Silverlight 实现和 .NET 对等项之间有所不同。
- 原始 .NET 程序集中任何不受支持的属性列表,这些属性在 Silverlight 程序集中不存在,必须从 IL 代码中删除。
XML 文件看起来像这样:
<?xml version="1.0" encoding="utf-8" ?>
<SLAsm.Settings xmlns="urn:Silverlight-Assmblies/SLAsmSettings.xsd"
ILAssembler="C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\ilasm.exe"
ILDisassembler="C:\Program Files\Microsoft Visual Studio 8\SDK\v2.0\Bin\ildasm.exe">
<ExternAssembly Name="System" Version="2.0.5.0"
PublicKeyToken="7C EC 85 D7 BE A7 79 8E" />
<ExternAssembly Name="mscorlib" Version="2.0.5.0"
PublicKeyToken="7C EC 85 D7 BE A7 79 8E" />
<ExternAssembly Name="System.Core" Version="2.0.5.0"
PublicKeyToken="7C EC 85 D7 BE A7 79 8E" />
<ExternAssembly Name="System.Net" Version="2.0.5.0"
PublicKeyToken="7C EC 85 D7 BE A7 79 8E" />
<ExternAssembly Name="System.Runtime.Serialization"
Version="2.0.5.0" PublicKeyToken="7C EC 85 D7 BE A7 79 8E" />
<ExternAssembly Name="System.Windows"
Version="2.0.5.0" PublicKeyToken="7C EC 85 D7 BE A7 79 8E" />
<ExternAssembly Name="System.Json"
Version="2.0.5.0" PublicKeyToken="31 BF 38 56 AD 36 4E 35" />
<ExternAssembly Name="System.ServiceModel"
Version="2.0.5.0" PublicKeyToken="31 BF 38 56 AD 36 4E 35" >
<UnsupportedAttribute>
System.ServiceModel.FaultContractAttribute
</UnsupportedAttribute>
<UnsupportedAttribute>
System.ServiceModel.DeliveryRequirementsAttribute
</UnsupportedAttribute>
<UnsupportedAttribute>
System.ServiceModel.CallbackBehaviorAttribute
</UnsupportedAttribute>
<UnsupportedAttribute>
System.ServiceModel.MessageHeaderAttribute
</UnsupportedAttribute>
<UnsupportedAttribute>
System.ServiceModel.MessageHeaderArrayAttribute
</UnsupportedAttribute>
<UnsupportedAttribute>
System.ServiceModel.MessagePropertyAttribute
</UnsupportedAttribute>
<UnsupportedAttribute>
System.ServiceModel.OperationBehaviorAttribute
</UnsupportedAttribute>
<UnsupportedAttribute>
System.ServiceModel.ServiceBehaviorAttribute
</UnsupportedAttribute>
<UnsupportedAttribute>
System.ServiceModel.XmlSerializerFormatAttribute
</UnsupportedAttribute>
<UnsupportedAttribute>
System.ServiceModel.PeerHopCountAttribute
</UnsupportedAttribute>
<UnsupportedAttribute>
System.ServiceModel.TransactionFlowAttribute
</UnsupportedAttribute>
<UnsupportedAttribute>
System.ServiceModel.Activation.AspNetCompatibilityRequirementsAttribute
</UnsupportedAttribute>
</ExternAssembly>
</SLAsm.Settings>
请记住设置到 *ILAsm.exe* 和 *ILdasm.exe* 文件的正确路径。
我已将所有 Silverlight 程序集引用预先填充到文件中,并向 System.ServiceModel
程序集添加了一个不受支持的属性列表。
注意:这不是一个不受支持的属性的完整列表,而是我自己遇到过的那些。如果您发现任何与 Silverlight 不兼容的属性,请随时添加。(当您的 Silverlight 应用程序尝试加载您的程序集时,它会引发 TypeLoadException
。)
Using the Code
现在您已经设置了 XML 文件,您可能想使用该代码。该应用程序是一个简单的控制台应用程序,它接受以下参数:
<AssemblyPath.dll> [/Key=<StrongNameKeyPath.snk>] [/Output=<TargetPath.dll>]
其中 *AssemblyPath.dll* 是您的公共 .NET 程序集的路径。可选的 /Output 开关指定您想要存储新 Silverlight 程序集的位置。(如果留空,输出文件将是 *AssemblyPath.SL.dll*。)
最后,由于我们修改了所有原始 IL 代码,如果原始程序集是用强名称密钥签名的,那么新创建的程序集将不会被正确签名,因此您可以包含您用于签名程序集的原始 *.snk* 文件的路径,应用程序将把它们重新组合起来。
设置为生成后事件
确保您的公共程序集被转换为与 Silverlight 兼容的版本并在修改时保持更新的最佳方法是将生成后命令添加到您的项目中。为此,请右键单击您的项目,然后单击“项目属性”菜单项。
导航到“生成事件”选项卡。
现在,单击“编辑生成后命令”,会打开一个对话框。
输入我们的转换器应用程序的路径,后跟 "$(TargetPath)" 宏,以将生成的程序集指定为要转换的文件。添加您需要的任何额外参数(例如 /Output= 和 /Key=),然后单击“确定”。
在“生成事件”选项卡中,确保“运行生成后事件:”选项设置为“生成成功后”。保存项目。从现在开始,每当您的项目成功生成时,Visual Studio 将运行我们的应用程序并创建一个与 Silverlight 兼容的程序集。
注意:如果兼容程序集的创建失败,整个项目将被标记为“生成失败”,并且您将在输出窗口中看到 *ilasm.exe* 返回的错误消息。
结论
希望这对遇到同样问题的您有所帮助,如果您确实得到了帮助,请务必给我留言……
历史
- 2009年1月22日 - 更新了源代码以从 .NET 安装文件夹加载 *ilasm.exe*,并将 *ildasm.exe* 包含在解决方案中,以供那些没有安装 .NET SDK 的用户使用。
- 2009年3月3日 - 更新了“删除不受支持的属性”功能,以支持具有多个属性的方法(由 Boris Modylevsky 指出)。