65.9K
CodeProject 正在变化。 阅读更多。
Home

创建可由旧版 .NET 1.1 Web 应用使用的 WCF 服务

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.56/5 (5投票s)

2011 年 2 月 26 日

CPOL

6分钟阅读

viewsIcon

39198

downloadIcon

350

公开 .NET 4.0 中创建的 WCF 服务供 .NET 1.1 客户端使用

引言

经过数小时的艰苦斗争,我终于成功地让一个用 .NET 4.0 编写的 WCF 服务能够被我仍然使用 .NET 1.1 的旧版 ASP.NET 应用程序所使用。我之所以使用“斗争”这个词,是因为我真的查阅了网上大量分散的帖子,一个博客 在这里,一篇文章 在那里,以及其他地方的一些内容,耗费了大量时间和精力;我相信仍然有需要做我所做的事情的人;因此,为了保持我对所做事情的清晰认识,并帮助他人避免经历我刚刚经历的痛苦,我决定值得将所有这些内容整理成一篇,并将其发布到 CodeProject.com 以便更广泛的受众。这没有什么学术性 - 我在这里涵盖的内容基本上都带有我辛勤劳作的印记。

背景

在 VS2010 中,WCF 服务模板(一个用于 WCF 服务应用程序,一个用于 WCF 类库)已经准备就绪,创建 WCF 服务非常简单明了;这正是我刚开始时所做的:我使用了 WCF 服务应用程序项目模板,并立即得到了一个 IService 接口和一个 Service1.svc 文件,以及自动配置的 web.config。几分钟后,我发布了 Service1 ,并能够使用它来调用解决方案中 Web 项目的 GetData() 方法。有了这个在 IIS 上运行的 Service1.svc,我进入了我的旧版 .NET 1.1 项目,并为其设置了一个 Web 引用。不出所料,在我从 .NET 1.1 应用程序内部调用同一个 GetData() 方法后,麻烦就开始接踵而至。首先,弹出了一个 VS2010 JIT 调试器对话框,如下图所示

VS2010 JIT Debugger Dialog

如果我点击“是”进行调试,我遇到了晦涩的 **“AccessViolationException Unhandled”** 错误对话框。

Access Violation error

然后深入到“View Detail”(查看详细信息),我就看到了这个 **“Attempted to read or write protected memory. This is often an indication that other memory is corrupt.”**(尝试读取或写入受保护的内存。这通常表示其他内存已损坏。)非常可怕!赶快退出,然后当我返回到 ASP.NET 1.1 应用程序时,我遇到了 **“The underlying connection was closed: An unexpected error occurred on a receive”**(底层连接已关闭:接收时发生意外错误)。

Client side error

创建向后兼容的 Web 服务

那么我错过了什么?在阅读了 MSDN 网站和社交 MSDN 网站的一些内容后,这个项目的两个方面浮出了水面:`ServiceContract` 上的 XmlSerializerFormat 属性,以及 WCF 项目的 web.config 中的 **A**(地址)**B**(绑定)**C**(契约)设置。关键在于配置这些设置,使 WCF 服务成为 ASMX 服务或传统的 Web 服务,而这当然是 ASP.NET 1.1 的老前辈们唯一能够从 WCF 这种现代食物链中获取的“食物”。

IIS 设置

我正在 Windows Server 2003 盒子上运行 IIS 7,因此很容易设置多个运行不同 .NET Framework 版本的站点。对于其他操作系统,如 Windows XP Pro,运行多个站点的唯一方法是逐个停止和启动站点。

首先,我在 IIS7 上创建了一个名为 WcfHost 的新站点,并且我必须为它分配一个不同的 TCP 端口号,在这种情况下,端口是 8088(没有特别的原因,只是听起来不错)。我的 ASP.NET 1.1 应用程序已经占用了默认的 80 端口。之后,当我需要引用在 WcfHost 上发布的 WCF Web 服务时,我将从 https://:8088/WcfHost/..... 开始引用。

创建服务

为了让 .NET 1.1 应用程序能够使用 WCF 服务,从编码角度来看,与创建常规 WCF 服务不同的是,只需要在服务接口中添加一个 XmlSerializerFormat 属性。所以,而不是这样

[ServiceContract]
public interface IService1{…}

我用了这个

[ServiceContract, XmlSerializerFormat]
public interface IService1 {…}

从编码方面来说,这就是全部。现在,另一个关键部分是对 WCF 服务项目的 Web.config 文件进行一些更改。

配置 ABC

在进行任何修改之前,当我使用 WCF 服务应用程序模板创建 WcfToASMX WCF 服务应用程序项目时,自动生成的 Web.config 文件如下所示:

<?xml version="1.0"?>
<configuration>
  <system.web>
    <compilation debug="true" targetFramework="4.0" />
  </system.web>
  <system.serviceModel>
    <behaviors>
      <serviceBehaviors>
        <behavior>
          <!-- To avoid disclosing metadata information,
          set the value below to false and remove the
          metadata endpoint above before deployment -->
          <serviceMetadata httpGetEnabled="true"/>
          <!-- To receive exception details in faults for
          debugging purposes, set the value below to true.
          Set to false before deployment to avoid 
          disclosing exception information -->
          <serviceDebug includeExceptionDetailInFaults="false"/>
        </behavior>
      </serviceBehaviors>
    </behaviors>
    <serviceHostingEnvironment multipleSiteBindingsEnabled="true" />
  </system.serviceModel>
 <system.webServer>
    <modules runAllManagedModulesForAllRequests="true"/>
  </system.webServer>

</configuration>

遵循 MSDN 的文章和 Social.MSDN.COM 的博客,我进行了必要的条目添加和修改,现在文件如下所示:

<?xml version="1.0"?>
<configuration>

  <system.web>
    <compilation debug="true" targetFramework="4.0" />
  </system.web>
  <system.serviceModel>
	  <services>
		  <service name="WcfToAsmx.Service1" behaviorConfiguration="asmx">
			  <endpoint address="basic" binding="basicHttpBinding"
				contract="WcfToAsmx.IService1" ></endpoint>

		  </service>

	  </services>
    <behaviors>
      <serviceBehaviors>
        <behavior name="asmx">
          <!-- To avoid disclosing metadata information, 
          set the value below to false and remove the metadata endpoint 
          above before deployment -->
          <serviceMetadata httpGetEnabled="true"/>
          <!-- To receive exception details in faults for debugging purposes, 
          set the value below to true.  Set to false before deployment 
          to avoid disclosing exception information -->
          <serviceDebug includeExceptionDetailInFaults="false"/>
        </behavior>
      </serviceBehaviors>
    </behaviors>
    <serviceHostingEnvironment multipleSiteBindingsEnabled="true" />
  </system.serviceModel>
 <system.webServer>
    <modules runAllManagedModulesForAllRequests="true"/>
  </system.webServer>

</configuration>

加粗或高亮的区域是 Web.Config 中 WCF 服务项目需要的所有更改,现在 Service1.svc 已经准备好发布到 IIS7,供所有年龄段的客户端(从 .NET 4.0 到 .NET 1.1)使用。

发布服务

将 WCF 服务发布到 IIS 只需点击几下向导。我点击了构建菜单下的“发布”(服务项目名称,在本例中是 WcfToAsmx)链接,然后出现了一个“Publish Web”(发布 Web)向导对话框。我将 Publish 方法保留为默认值“Web Deploy”,并输入了服务 URL:https://:8088,这是之前在 IIS 中设置的;然后我输入了 Site/Application(站点/应用程序): “WcfHost/Test/CP/WcfToAsmx”,并勾选了“Mark as IIS application on destination”(在目标上标记为 IIS 应用程序)复选框。点击“Publish”(发布)按钮,完成。由于勾选了“Mark as IIS app”复选框,我无需创建这些文件夹“Test/CP/WcftoAsmx”;IIS 会自动为我创建,只要“WcfHost”网站已存在。实际的发布屏幕已捕获并显示在此处:

Publish WCF service

Service1.svc 的渲染

为了确保 WCF 服务正常工作,我进入了 IIS7 管理控制台并浏览了 Service1.svc。可调用的服务应该在浏览器中呈现如下屏幕:

a functioning Service1.svc

使用服务

现在,时光倒流十年,启动那个老而强大的 VS2003 来创建一个 ASP.NET 1.1 客户端应用程序。这里没什么特别的——我需要做的就是为项目添加一个 Web 服务引用,就像添加任何其他 Web 服务引用一样,只是服务 URL 会是这个样子:https://:8088/Test/CP/WcfToAsmx/Service1.svc,而不是这个 https://:8088/Test/CP/WcfToAsmx/Service1.asmx。其余的与处理传统 Web 服务完全相同。客户端的 web.configapp.config 文件无需添加或更改任何内容。

摘要

实际上,创建一个可供旧版 .NET 1.1 客户端使用的向后兼容 WCF 服务非常简单。此类 WCF 服务项目所需的关键更改是:

  1. 在构建服务接口时,向 ServiceContract 添加 XmlSerializerFormat 属性。
  2. Web.Config 中添加一个服务终结点,并指定 address=”basic” 和 binding=”basicHttpBinding”。

致谢

以下是我的解决方案搜索过程中的主要参考资料:

  1. MSDN 文章,发布于 2010-06-09,网址:http://msdn.microsoft.com/en-us/library/ms751433.aspx
  2. Jay R. Wren 于 2007-03-15 回答用户 Bernie Almosni 的问题,网址:http://social.msdn.microsoft.com/forums/en-US/wcf/thread/1f8c7fe9-784c-4beb-8d0f-060bf8bfc24f

历史

  • 首次提交于 2011 年 2 月 25 日
© . All rights reserved.