← 全部文章 工业通讯

VS2019 发布和调用 WebService,以及 IIS 的坑

2023 年 7 月 4 日 · 5 分钟读完

目录
  1. WebService 是什么
  2. 一、创建服务
  3. 二、发布到 IIS
  4. 三、客户端调用
  5. 四、问题汇总
  6. 系统里没有 IIS 管理器
  7. HTTP 错误 403.14 - Forbidden
  8. 浏览器提示「你的连接不是专用连接」
  9. HTTP 错误 404.3 - Not Found
  10. 「应用程序中的服务器错误」
  11. 测试页「只能用于来自本地计算机的请求」
  12. 别的电脑访问不了
  13. 延伸

对接工厂 MES 时发现 WebService 挺有意思,记录一下创建、发布和调用的过程,以及遇到的问题。原来的三篇(发布调用、IIS 安装、403.14)合在这里。

WebService 是什么

WebService 是基于 HTTP 和 XML(SOAP 协议)的远程调用方式:服务端把方法公开出来,客户端像调本地方法一样调用,参数和返回值被打包成 XML 在网络上传输。服务会提供一份 WSDL 描述文件,说明有哪些方法、参数是什么类型,客户端根据它自动生成调用代码。

它的好处是跨平台、跨语言:Java 写的 MES 和 C# 写的上位机都认 SOAP。很多工厂的 MES、WMS 系统是十几年前建的,对外接口就是 WebService,所以上位机经常要对接它。

新项目一般用 REST 风格的 HTTP + JSON(见 WinForm 里的简单 HTTP 服务器与客户端),更轻量。

一、创建服务

  1. 新建「ASP.NET Web 应用程序(.NET Framework)」项目:

如果找不到这个模板,拉到列表最下方点「安装多个工具和功能」:

在 Visual Studio Installer 里勾选 ASP.NET 和 Web 开发:

装好后继续新建,模板选「空」:

  1. 项目右键 → 添加 → 新建项 → Web 服务(ASMX):

  1. 在生成的 WebService1 类里加一个自己的方法。加了 [WebMethod] 特性的方法才会对外公开:

[WebMethod]
public string SendName(string name)
{
    return "Hello " + name;
}
  1. F5 启动,浏览器会打开 WebService1.asmx,列出所有方法:

点方法名进入测试页,比如 SendName:

填参数、点「调用」,弹出返回的 XML:

服务创建完毕。地址后面加 ?wsdl 能看到 WSDL。

二、发布到 IIS

  1. 项目右键 → 发布,目标选「文件夹」:

可以在设置里勾选「发布前删除所有现有文件」,避免旧文件残留引起奇怪的问题:

  1. 打开计算机管理(或者直接搜「IIS」),找到 Internet Information Services (IIS) 管理器。没有的话见下文「系统里没有 IIS 管理器」:

  1. 右键「网站」→ 添加网站,物理路径选刚才发布的文件夹,填一个没被占用的端口:

注意 IP 地址:可以选本机的局域网 IP,也可以填 127.0.0.1(只能本机访问)。选了一个本机并没有的 IP,浏览时会一直超时。

  1. 右键网站 → 管理网站 → 浏览,打开 WebService1.asmx,能看到方法列表,说明发布成功:

三、客户端调用

新建一个调用方的项目(这里是控制台程序),右键 → 添加 → 服务引用:

地址要填到 .asmx(比如 http://192.168.1.10:8081/WebService1.asmx),只填到网站根目录是找不到服务的。点「转到」,展开就能看到方法:

VS 会根据 WSDL 生成代理类,调用起来就像本地方法:

var client = new ServiceReference1.WebService1SoapClient();
Console.WriteLine(client.SendName("wwww"));

代理类在添加服务引用时填的命名空间下,默认叫 ServiceReference1,添加时可以改成有意义的名字:

控制台打印出 SendName 的返回值,调用成功。

服务地址写在 app.config 的 <endpoint address="..."> 里,现场换服务器时改配置文件就行,不用重新编译。也可以在代码里指定:

// 第一个参数是 app.config 里 endpoint 的 name
var client = new ServiceReference1.WebService1SoapClient("WebService1Soap", "http://10.0.0.5:8081/WebService1.asmx");

客户端也有异步版本 SendNameAsync,在界面程序里用它不会卡界面。

四、问题汇总

系统里没有 IIS 管理器

Windows 默认没装 IIS,要手动打开:

  1. 控制面板 → 程序:

  1. 启用或关闭 Windows 功能:

  1. 勾选 Internet Information Services 下的「Web 管理工具」,以及「万维网服务 → 应用程序开发功能」里的 ASP.NET 4.x(只勾管理工具的话,网站能建但跑不了 ASP.NET):

Windows 会下载安装,可能要等一阵,直到提示「Windows 已完成请求的更改」:

  1. 在开始菜单搜「IIS」,能打开管理器就好了:

HTTP 错误 403.14 - Forbidden

「Web 服务器被配置为不列出此目录的内容」:访问的是网站根目录,而目录里没有默认文档(比如 index.html),IIS 又不允许列目录。

WebService 的情况下,正确的做法是访问具体的 .asmx 地址,而不是根目录。如果确实想看目录列表,有两种办法:

在网站的 web.config 里打开目录浏览:

<system.webServer>
  <directoryBrowse enabled="true" />
</system.webServer>

或者在 IIS 管理器里选中网站 → 目录浏览 → 启用:

也可以在「默认文档」里把 WebService1.asmx 加进去,这样访问根目录就直接打开服务页。

另一个常见原因是 ASP.NET 没有注册到 IIS。这种情况访问 .asmx 会报 404 或 500,按上面勾选 ASP.NET 4.x 即可;老系统可以执行 aspnet_regiis -i。

浏览器提示「你的连接不是专用连接」

用 HTTPS 访问自己发布的服务、证书不受信任时会出现,见 浏览器提示「你的连接不是专用连接」。

HTTP 错误 404.3 - Not Found

文件明明在,却报 404.3,意思是 IIS 不知道怎么处理 .asmx 这种扩展名。原因是没有安装 ASP.NET 相关的 IIS 功能:在「启用或关闭 Windows 功能」里,勾选 Internet Information Services → 万维网服务 → 应用程序开发功能 → ASP.NET 4.x,以及 .NET Framework 4.x 高级服务 → WCF 服务 → HTTP 激活。参考:IIS 404.3 的解决办法。

「应用程序中的服务器错误」

这是 ASP.NET 的通用错误页,具体原因看页面上的错误信息。常见的有:应用程序池的 .NET CLR 版本不是 v4.0、web.config 里有当前 IIS 不支持的配置、发布的文件夹权限不够。参考:服务器错误的排查。

测试页「只能用于来自本地计算机的请求」

在别的电脑上打开 .asmx 页面,点进方法后没有「调用」按钮。这是默认的安全设置,只影响浏览器测试页,不影响客户端程序调用。确实需要远程测试时,在 web.config 里加:

<system.web>
  <webServices>
    <protocols>
      <add name="HttpGet" />
      <add name="HttpPost" />
    </protocols>
  </webServices>
</system.web>

别的电脑访问不了

依次检查:服务器上用 localhost 能不能打开;Windows 防火墙是否放行了网站端口;IIS 网站的绑定是不是只绑定了某个 IP。

延伸

  • WebService 和 WCF:WCF 是微软后来的统一通讯框架,也支持 SOAP,ASMX 算是它的前辈。两者在 .NET Core 以后服务端都不再支持(社区有 CoreWCF),新项目服务端建议用 ASP.NET Core Web API。
  • .NET Core / .NET 6 的客户端:没有「添加服务引用」的老界面,用「连接的服务」→ WCF Web Service,或者命令行工具 dotnet-svcutil 生成代理,调用方式一样。
  • 不想生成代理:SOAP 本质是 POST 一段 XML,可以用 HttpClient 直接发,Content-Type: text/xml,请求体格式照着 .asmx 测试页上给的示例写。调试对接问题时这样最直观。
  • XML 的转义:参数里有 <、& 时要转义,见 JSON 与 XML 速查。

# C# # WebService # IIS

原文首发于 blog.csdn.net