将 ASMX 服务迁移到 WCF 服务
创建一个 WCF 服务来替换现有的 ASMX 服务。
问题与目标
许多公司仍然拥有使用 .NET 2.0 ASMX 技术实现的 Web 服务,并且其客户拥有已使用 .NET 2.0 技术创建了代理的工具。通常,引入 WCF 端点将需要重新设计这些工具,这是一个巨大的问题,应尽可能避免。在这种过程中,只有一个修改被认为是可接受的,那就是更改客户端的端点 URL。这是因为 ASMX 服务通常的 URL 为 http://host/Service.asmx,而 WCF 服务为 http://host/Service.svc。目标是在现有客户端工具不知情的情况下更改服务实现,至少在无需修改代码的意义上。
本文讨论了在尝试实现此迁移过程的解决方案时遇到的问题、解决方案和可能的陷阱。
术语
在 WCF 之前,客户端中创建了一个 .NET 2.0 Web 引用,它充当代理,促进与 Web 服务的通信。 .NET3.5 引入了一种新的机制来创建与 WCF 服务器端技术兼容的代理。
为简化起见,本文将每种技术称为
- Client20
- Client30
拟议解决方案
有两种方法可以管理这种过渡。
解决方案 1
使 ASMX 和 WCF 层充当实际功能实现的包装器层。这意味着在任何时候都会暴露两个独立的端点,它们将调用重定向到一个公共函数。所有现有客户端将连接到旧端点,所有新客户端将连接到新端点。
解决方案 2
使 WCF 服务充当 ASMX 服务。
研究问题
研究此问题最简单的方法是在一个简单的解决方案中重现它,该解决方案复制现有基础结构并尝试在所有部分(旧的和新的)之间实现有效的连接。
服务器端
为简化起见,创建了一个通用的契约接口,所有服务都实现了该接口。
public interface IStringService
{
string StringConcat(string value1, string value2);
}
在 ServiceLayer 中创建了两个不同的项目,它们为 IStringService
契约提供 ASMX 和 WCF 服务。
两个服务实现都由通用引用程序集中的一个函数提供。
客户端
创建了不同的客户端项目,它们为上述服务提供代理类。一个项目使用 Client20
进行代理,另一个项目使用 Client30
。每个代理类都应该能够实现一个通用接口。此时,所有客户端都可以连接到所有服务,从而形成以下组合。
- Client20 - ASMX 服务
- Client20 - WCF 服务
Client30 - ASMX 服务(已弃用)- Client30 - WCF 服务
Client30 - ASMX 服务组合已弃用。
public interface IStringServiceClient
{
string StringConcat(string value1, string value2);
}
至此,我们已经满足了解决方案 1 的要求。
对于解决方案 2,目标是创建一个 WCFAsASMX
服务项目,该项目公开实现 IStringService
契约的 WCF 服务,以成功替换上述所有服务。
Client20
在不进行代码修改的情况下有效连接,确保了向后兼容性。Client30
在不进行代码修改的情况下有效连接,确保了 WCF 的更改不会阻碍未来的实现。(也就是说,我们不仅仅是改变了实现中的技术名称,而是能够获得 WCF 提供的所有当前和未来的好处。)
可以通过以下步骤实现此目标
- '''目标 1''' 配合解决方案 2,通过更改
Client20
的 URL 端点来实现成功调用。 - '''目标 2''' 配合解决方案 2,无需任何更改即可实现成功调用。
目标 1
强制 WCFAsASMX 项目中的 WCF 服务接受 Client20
的请求。在这种情况下,服务名称空间为 "http://tempuri.org/",但也可以是正确指定的名称空间。基于此名称空间,所需的更改是
- 用以下内容注解服务
[WebService(Namespace = "http://tempuri.org/")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
[WebMethod]
[OperationContract(Action=@"http://tempuri.org/StringConcat")]
string[]
,则还需要用以下内容注解服务[XmlSerializerFormat]
现在,Client20 仅通过更改端点就可以连接到 WCF 服务。从 http://host/Service.asmx 到 http://host/Service.svc。
目标 2
通过让 IIS 服务处理 ASMX 请求(使用 WCF)来实现此目标。以下是所需的更改
- 通过在 system.web/compilation 节点中添加以下内容来修改 web.config 文件
<buildProviders>
<remove extension=".asmx">
<add extension=".asmx"
type="System.ServiceModel.Activation.ServiceBuildProvider,
System.ServiceModel.Activation, Version=4.0.0.0, Culture=neutral,
PublicKeyToken=31bf3856ad364e35" />
</buildProvider>
比较解决方案
两种解决方案都存在固有的局限性。它们无法在不破坏向后兼容性的情况下为两个客户端提供 WCF 功能。因此,重要的是要理解 Client20 实现应尽快淘汰,因为它们极大地限制了技术迁移的好处。
解决方案 1
优点
- WCF 服务实现保持不变,不进行任何修改,以保持向后兼容性。这是引入新解决方案时每个人都希望的优点。现有客户端无需修改。
缺点
- 暴露了两组不同的物理服务层,并且需要维护这两层,它们充当实际功能实现的包装器。
- 现有客户端不连接到实际的 WCF 技术堆栈,因此它们无法获得新技术的优势,例如性能。
- 感觉代理生成工具需要支持两种不同的技术。
解决方案 2
优点
- 虽然暴露了两组逻辑服务层,但只有一组实际的物理服务层。这减少了需要维护的层。
- 现有工具连接到 WCF 堆栈并受益于新技术优势。
缺点
- WCF 服务需要进行一些小的修改。尽管这些修改看起来足够简单,但它们是为了向后兼容性而设计的,这一点必须始终予以考虑。积极的一面是,从长远来看,一旦 Client20 实现被淘汰,移除这些修改将非常简单。