下面我将为你提供一个详尽的指南,涵盖从最简单的方法到处理复杂情况的技巧。

核心方法
主要有两种主流方法:
- 添加服务引用 (Add Service Reference):这是 Visual Studio 提供的图形化工具,最简单直观,适用于绝大多数标准的、基于 WSDL 的 WebService。
- 使用
svcutil.exe命令行工具:功能与“添加服务引用”类似,但提供了更多自定义选项,适合在构建服务器或需要脚本化时使用。
我们主要介绍第一种方法,因为它最常用。
详细步骤:使用 Visual Studio 添加服务引用
假设我们有一个 Java WebService,其 WSDL 地址是 http://java-server.com/MyService?wsdl。
步骤 1:获取 WSDL 地址
你需要确保可以访问到 Java WebService 的 WSDL 文件,在浏览器中输入 WSDL 地址,你应该能看到一个 XML 文件,里面定义了服务的所有操作、消息类型和端口类型。

步骤 2:创建或打开 .NET 项目
在 Visual Studio 中创建一个新的 C# 项目(控制台应用程序、ASP.NET Core 应用等)。
步骤 3:添加服务引用
-
在 解决方案资源管理器 中,右键点击你的项目。
-
选择 添加 -> 服务引用...。
-
在弹出的对话框中:
(图片来源网络,侵删)- 在 地址 框中,输入 Java WebService 的 WSDL 地址。
- 点击 前往,Visual Studio 会下载并解析 WSDL 文件。
- 解析成功后,会显示服务中的所有可用操作。
- 在 命名空间 框中,为你将要生成的客户端代理类指定一个命名空间(
MyJavaServiceReference)。 - 点击 确定。
-
Visual Studio 会自动生成一系列文件,包括:
- 一个客户端代理类(
MyServiceClient),它封装了所有对 WebService 的调用。 - 用于序列化和反序列化消息的类(对应 WSDL 中定义的复杂类型)。
- 一个客户端代理类(
这些文件通常位于 Service References 或 Connected Services 文件夹下。
步骤 4:编写调用代码
现在你可以在你的 C# 代码中使用生成的客户端了。
using System;
using MyJavaServiceReference; // 使用你在步骤3中指定的命名空间
namespace MyConsoleApp
{
class Program
{
static void Main(string[] args)
{
try
{
// 1. 创建客户端代理类的实例
// 这个类名是根据 WSDL 中的服务名生成的,通常叫 [服务名]Client
var client = new MyServiceClient();
// 2. 准备输入参数
// 参数类型是根据 WSDL 中的操作定义生成的
var request = new MyRequestType
{
// 假设 WSDL 中定义了一个名为 "inputParam" 的字符串参数
InputParam = "Hello from .NET!"
};
// 3. 调用 WebService 的方法
// 方法名是根据 WSDL 中的操作名生成的
Console.WriteLine("正在调用 Java WebService...");
var response = client.MyOperation(request);
// 4. 处理返回结果
// 返回类型也是根据 WSDL 生成的
if (response != null)
{
Console.WriteLine("调用成功!");
Console.WriteLine($"返回结果: {response.OutputResult}");
}
else
{
Console.WriteLine("调用成功,但返回结果为空。");
}
}
catch (Exception ex)
{
// 捕获并处理可能发生的异常
Console.WriteLine($"调用失败: {ex.Message}");
// 如果是 SOAP 错误,通常可以从 InnerException 中获取更详细的信息
if (ex.InnerException != null)
{
Console.WriteLine($"内部错误: {ex.InnerException.Message}");
}
}
}
}
}
常见问题与解决方案
在调用 Java WebService 时,你很可能会遇到以下问题。
问题 1:WSDL 无法解析或“请求被中止”
- 症状:点击“前往”后,长时间无响应或提示“请求被中止”、“基础连接已关闭”等错误。
- 原因:通常是由于 Java 服务器和 .NET 客户端之间关于 SOAP 协议版本的协商不一致,Java 服务器可能默认使用 SOAP 1.1,而 .NET 客户端可能尝试使用 SOAP 1.2,导致兼容性问题。
- 解决方案:强制 .NET 客户端使用 SOAP 1.1。
在创建客户端实例后,设置其绑定属性。
var client = new MyServiceClient();
// 强制使用 SOAP 1.1
// "MyService" 是你在 WSDL 中看到的 <port> 元素的 name 属性值
var binding = client.Endpoint.Binding as BasicHttpBinding;
if (binding != null)
{
binding.MessageVersion = MessageVersion.Soap11;
}
问题 2:用户名和密码认证(SOAP Header)
Java WebService 常常通过 SOAP Header 传递用户名和密码进行认证。
- 症状:调用失败,提示“未授权”或“认证失败”。
- 解决方案:在调用前,创建一个
MessageHeader并添加到请求中。
var client = new MyServiceClient();
// 创建用户名和密码
var username = "your_username";
var password = "your_password";
// 创建 SOAP Header
var authHeader = new MyJavaServiceReference.UsernameToken
{
Username = username,
Password = password
};
// 将 Header 附加到客户端操作上下文
// MyOperation 是你要调用的方法名
using (new OperationContextScope(client.InnerChannel))
{
// 创建消息头并添加到出站消息头集合中
MessageHeader header = MessageHeader.CreateHeader("Security", "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd", authHeader, false);
OperationContext.Current.OutgoingMessageHeaders.Add(header);
// 现在可以正常调用方法了
var request = new MyRequestType { InputParam = "test" };
var response = client.MyOperation(request);
Console.WriteLine($"Result: {response.OutputResult}");
}
注意:UsernameToken 这个类名和命名空间 http://... 需要根据 Java 服务端定义的 WSDL 中的 <xsd:element name="UsernameToken"> 来确定,你通常需要用工具(如 SoapUI)或直接查看 WSDL 来找到正确的结构。
问题 3:日期/时间格式不匹配
- 症状:Java 服务端接收到的日期是
0001/01/01,或者抛出格式异常。 - 原因:Java 和 .NET 处理日期时间的方式不同,Java 常用
java.util.Date或java.xml.datatype.XMLGregorianCalendar,而 .NET 使用DateTime,它们的序列化格式可能有细微差别。 - 解决方案:在调用前,将 .NET 的
DateTime转换为 Java 期望的格式字符串。
// .NET 的 DateTime
var netDateTime = DateTime.Now;
// 转换为 ISO 8601 格式字符串,这是最通用的格式
var javaCompatibleDateString = netDateTime.ToString("yyyy-MM-ddTHH:mm:ss.fffZ");
// 然后将这个字符串作为参数传递给 WebService
var request = new MyRequestType
{
// 假设参数是字符串类型
DateParam = javaCompatibleDateString
};
如果服务端期望的是 XMLGregorianCalendar 类型,.NET 生成的代理类通常会有一个对应的属性,你可以直接赋值 DateTime,代理类会自动处理转换。
问题 4:复杂类型映射问题
- 症状:某个复杂类型的字段在 .NET 客户端中为
null,或者类型不匹配。 - 原因:Java 和 .NET 的数据类型不完全对应,Java 的
List<String>可能会映射到 .NET 的string[]或List<string>。 - 解决方案:
- 检查生成的代码:查看自动生成的 Reference.cs 文件,了解 WSDL 中的类型是如何被映射到 .NET 类型的。
- 使用共享类型:如果可能,让 Java 团队和 .NET 团队就数据结构达成一致,并使用 XSD (XML Schema Definition) 作为“事实标准”,双方都基于同一个 XSD 文件来生成客户端/服务端代码,可以最大程度地避免类型不匹配问题。
