将遗留程序集转换为 WCF






4.14/5 (3投票s)
2007 年 4 月 18 日
4分钟阅读

30091
如何通过对 MSIL 进行简单修改,将旧版或第三方程序集暴露到 WCF。
引言
您是否有一个 WCF 之前的分布式 .NET 应用程序想要迁移到 WCF,但要么没有源代码(因为它是第三方组件),要么无法更改源代码(因为您的老板不能或不愿意升级到 .NET 3.0)?您只需要用一些特性装饰您的接口,如果能修改源代码,这将非常简单,但在无法修改源代码的情况下,修改 MSIL 也并非难事。
背景
我有很多应用程序是为 .NET Remoting 构建的,并且在 .NET 1.1 环境中得到积极维护。构建它们时,我将接口代码与实现代码分离,因为接口会分发给客户端程序集,而实现代码在服务器端程序集中。这正是您在 WCF 中组织 ServiceContract 的方式,但我还需要一件事来托管代码在 WCF ServiceHost 中 - 特性。如果能为我的接口添加 [ServiceContract] 和 [OperationContract] 特性,那将非常棒,但这需要我在 .NET 3.0 下重新编译我的接口库,并且还需要分支我的源代码控制项目来维护单独的版本,仅仅是为了添加一些不重要的特性。仔细想想,这可能比更新 MSIL 容易,但在某些遗留代码的情况下,这不是一个选项。
要将旧的 Remoting 应用程序程序集移植到 WCF,过程非常简单:
- 使用 ILDASM 将您的程序集反编译为 MSIL
- 使用您喜欢的文本编辑器添加 IL 来引用定义了特性的程序集(System.ServiceModel),然后为您要应用特性的接口和方法(ServiceContract和OperationContract)添加 IL。
- 使用 ILASM 将您的 MSIL 重新汇编为包含新特性的程序集
繁琐吗?有点,但总比试图说服你的老板放弃 .NET 1.1 支持要好。
反汇编
这是简单部分。请确保您没有违反任何许可协议,特别是如果您正在处理第三方代码。它们通常会有关于您不得反汇编的条款。如果存在这样的条款,请立即停止并要求他们为您执行此操作。使用与现有程序集构建时相同的 ILDASM 版本(稍后是 ILASM),以确保在您的旧环境中保持兼容性。我的程序集目前在 .NET 1.1 下运行,所以我使用的是 ildasm 版本 1.1.4322.573。
ildasm <assembly>.dll /out=<assembly>.il
现在,您可能得到两个文件 - MSIL 文件(<assembly>.il)和资源文件(<assembly>.res)。在您喜欢的文本编辑器中打开 MSIL 文件。既然您要深入研究 MSIL,我建议您将背景设置为黑色,文本设置为亮绿色 Courier 字体,这样就能完美重现 1979 年电影制作人设想的程序员破解可执行文件的场景。
您可能还会发现,反编译一个来自正常工作的 WCF 项目的程序集会很有帮助,这样您就可以看到编译器是如何应用特性的。
修改 IL
繁琐,但仍然简单。您需要将引用的程序集添加到 MSIL 的顶部,您会在那里找到其他程序集引用,如 mscorlib 和 System。
.assembly extern System.ServiceModel
{
  .publickeytoken = (B7 7A 5C 56 19 34 E0 89 )            // .z\V.4..
  .ver 3:0:0:0
}
现在您需要找到接口。它将以 .class interface public abstract 开头。在花括号下方、第一个 .method 之前,您需要添加 [ServiceContract] 特性的 MSIL。
  .class interface public abstract auto ansi IMyServiceInterface
  {
  .custom instance void [System.ServiceModel]
System.ServiceModel.ServiceContractAttribute::.ctor() = ( 01 00 00 00 )
现在您需要为您的方法添加 [OperationContract] MSIL。由于它们是接口方法,它们将是抽象的 - 只有一对花括号。您需要将特性添加到花括号内部。
    .method public hidebysig newslot abstract virtual
            instance class MyReturnType
            MyMethod(valuetype [mscorlib]System.Guid inputId,
                             string inputData) cil managed
    {
    .custom instance void [System.ServiceModel]
System.ServiceModel.OperationContractAttribute::.ctor() = ( 01 00 00 00 )
    } // end of method IMyServiceInterface::MyMethod
重新汇编
一旦您更新了所有方法,就该重新编译程序集了。如果您还没有这样做,请备份现有程序集,以防万一损坏。当您汇编新文件时,您需要记住在 ILDASM 生成资源文件时一起包含它。
同样,请确保您使用的是与您的旧程序集 .NET 版本相对应的 ILASM 版本。我的版本是 .NET 1.1,所以我使用的是 ilasm 版本 1.1.4322.2032。这将确保您的程序集在必要时仍然可以在 .NET 1.1 下运行。特性的一个优点是,如果执行代码不知道它们,它就不会使用它们;您不会破坏运行时兼容性。
ilasm /DLL <assembly>.il /resource=<assembly>.res
此时,您拥有与 .NET 1.1 兼容的相同程序集,但您的接口和方法已添加了 WCF 在 .NET 3.0 下运行时所需的特性。将更新后的接口程序集和未更改的实现程序集结合起来,将这些遗留代码重新托管到 WCF 提供的健壮且安全的体系结构中吧!
