下面我将从核心原理、详细步骤、常见问题和代码示例四个方面,为你详细讲解如何实现 Java 调用 C# WebService。

核心原理:为什么可以互通?
Java 和 C# 虽然是两种不同的语言,但它们都支持业界标准的 WebService 技术。
-
WSDL (Web Services Description Language):
- 无论服务端是 C# 还是 Java,它们都会将自身的接口(提供了哪些方法、方法有哪些参数、参数是什么类型、返回值是什么类型)描述成一个标准的 XML 文件,这个文件就是 WSDL。
- WSDL 就像一个“说明书”或“地图”,客户端(Java 程序)可以通过它来了解如何调用服务。
-
SOAP (Simple Object Access Protocol):
- 这是一种基于 XML 的协议,用于在 Web 上交换结构化的信息,当 Java 客户端调用 C# WebService 的一个方法时,它会将请求信息(方法名、参数等)打包成一个符合 SOAP 规范的 XML 消息,然后通过 HTTP 发送给 C# 服务端。
- C# 服务端收到这个 SOAP 消息后,会解析它,执行对应的方法,然后将结果再打包成一个 SOAP 响应 XML 消息,返回给 Java 客户端。
-
标准化工具:
(图片来源网络,侵删)- C# (/.NET Framework):使用 ASMX、WCF 或 ASP.NET Core 等技术栈来创建 WebService,这些框架能自动生成标准的 WSDL 文件和处理 SOAP 消息。
- Java:使用 JAX-WS (Java API for XML Web Services) 框架,这个框架提供了强大的工具,可以根据 WSDL 文件自动生成客户端调用代码(通常称为 "Stub" 或 "Proxy" 代码),从而让开发者可以像调用本地方法一样调用远程的 WebService。
总结一下流程:
- C# 服务端 发布一个 WebService,并提供一个 WSDL 地址。
- Java 客户端 获取这个 WSDL 文件。
- Java 客户端 使用 JAX-WS 工具(如
wsimport)根据 WSDL 生成客户端代理类。 - Java 客户端 代码中实例化这个代理类,并直接调用其方法。
- JAX-WS 框架在底层自动完成 SOAP 请求的构建、发送和 SOAP 响应的解析,并将结果返回给调用者。
详细步骤(以最常用的 JAX-WS 为例)
假设你已经有一个 C# 编写的 WebService,并且你知道它的 WSDL 地址(http://your-csharp-service.com/MyService.asmx?wsdl)。
第 1 步:获取 WSDL 文件
在浏览器中访问 C# WebService 的 WSDL 地址(URL 后面加上 ?wsdl),你应该能看到一个 XML 文件,这就是你的 Java 客户端需要使用的“地图”。
第 2 步:使用 wsimport 生成客户端代码
wsimport 是 JDK 自带的一个命令行工具,它的作用是根据 WSDL 文件生成 Java 客户端代码。

-
打开命令行(CMD 或 PowerShell)。
-
执行以下命令:
wsimport -p com.example.client -keep -d src http://your-csharp-service.com/MyService.asmx?wsdl
参数解释:
-p com.example.client:指定生成的 Java 包名。-keep:生成代码后,保留.java源文件,方便查看。-d src:指定编译后的.class文件存放目录(需要确保src目录已存在)。http://...wsdl:你的 C# WebService 的 WSDL 地址。
执行成功后,
src/com/example/client目录下会生成一堆 Java 文件,其中最重要的是:MyService.java:服务的服务接口。MyServiceService.java:服务的工厂类,用于获取服务接口的实例。- 以及一些用于映射 SOAP 消息中数据类型的类(如
MyRequestType.java,MyResponseType.java等)。
第 3 步:在 Java 项目中编写调用代码
你可以在你的 Java 项目(例如一个 Maven 或 Gradle 项目)中编写调用代码了。
- 将第 2 步生成的所有
.class文件(或者直接将.java文件也放进项目)添加到你的 Java 项目的类路径中。 - 创建一个 Java 类来调用服务。
package com.example.client;
public class CSharpWebServiceClient {
public static void main(String[] args) {
try {
// 1. 创建服务实例(通过工厂类)
// MyServiceService 是 wsimport 生成的工厂类
MyServiceService service = new MyServiceService();
// 2. 获取服务端口(即服务的接口)
// MyService 是 wsimport 生成的服务接口
MyService port = service.getMyServicePort();
// 3. 调用 WebService 提供的方法
// 假设 C# WebService 有一个名为 "HelloWorld" 的方法,接受一个字符串参数
String request = "Java Client";
String response = port.helloWorld(request);
// 4. 处理返回结果
System.out.println("调用 C# WebService 成功!");
System.out.println("请求参数: " + request);
System.out.println("返回结果: " + response);
} catch (Exception e) {
e.printStackTrace();
System.err.println("调用 C# WebService 失败: " + e.getMessage());
}
}
}
第 4 步:处理常见问题(认证、超时等)
在实际项目中,你很可能需要处理更复杂的情况,HTTP Basic/Digest 认证、设置超时等,这通常需要通过设置 BindingProvider 的上下文来实现。
// ... 在获取 port 之后,调用方法之前 ...
// 假设 port 是 MyService 类型
BindingProvider bindingProvider = (BindingProvider) port;
// 1. 设置 HTTP 认证信息 (如果服务需要)
// 假设用户名是 "user",密码是 "password"
Map<String, Object> requestContext = bindingProvider.getRequestContext();
requestContext.put(BindingProvider.USERNAME_PROPERTY, "user");
requestContext.put(BindingProvider.PASSWORD_PROPERTY, "password");
// 2. 设置连接和读取超时 (单位:毫秒)
// 防止因网络问题导致程序长时间阻塞
requestContext.put(BindingProviderProperties.CONNECT_TIMEOUT, 5000); // 5秒连接超时
requestContext.put(BindingProviderProperties.REQUEST_TIMEOUT, 10000); // 10秒读取超时
// 3. 调用方法
String response = port.helloWorld("Java Client");
常见问题与解决方案
数据类型映射问题
这是最常见的问题,C# 和 Java 的数据类型不是一一对应的,WSDL 规范定义了它们之间的映射关系。
| C# / .NET 类型 | XML Schema 类型 | Java (JAX-WS) 类型 | 说明 |
|---|---|---|---|
string |
xs:string |
java.lang.String |
无问题 |
int, Int32 |
xs:int |
int |
无问题 |
bool, Boolean |
xs:boolean |
boolean |
无问题 |
double |
xs:double |
double |
无问题 |
DateTime |
xs:dateTime |
XMLGregorianCalendar |
注意:Java 端需要使用 XMLGregorianCalendar,而不是 java.util.Date 或 java.time.LocalDateTime,工具类可以方便转换。 |
DataSet |
xs:complexType (复杂) |
List<YourCustomObject> |
.NET 的 DataSet 是一个非常灵活的结构,Java 端通常会将其映射成一个或多个自定义的 Java 对象列表。 |
enum |
xs:restriction |
java.lang.String 或 enum |
如果枚举值是固定的,wsimport 可能会生成一个 Java enum,如果更灵活,则可能映射为 String。 |
解决方案:
- 检查
wsimport生成的 JavaBean 类,了解它期望的输入和输出类型。 - C# 端使用
DataSet,请与 C# 开发人员确认其内部结构,然后在 Java 端创建对应的 POJO (Plain Old Java Object)。 - 对于
DateTime,
