.NET6 SoapCore XmlSerializer下CancellationToken致WSDL生成失败
.NET 6 SoapCore XmlSerializer模式下CancellationToken导致WSDL生成异常问题
问题表现
- 环境为.NET 6,引用SoapCore NuGet包搭建异步WCF服务,序列化器配置为
SoapSerializer.XmlSerializer。给标记[OperationContract]特性的异步服务方法添加CancellationToken参数后,访问WSDL地址https://localhost:7026/Services.svc?WSDL抛出异常:ArgumentException: .NET type CancellationToken cannot be resolved into XML schema type。 - 异常原因:
System.Threading.CancellationToken是System命名空间下的值类型,被SoapCore识别为与bool、int、long同类的基础类型,生成XML架构映射时无法匹配对应XML架构类型,最终触发异常。 - 已尝试的无效方案:给
CancellationToken参数添加[XmlIgnore]特性未生效;[MessageContract(IsWrapped = false)]特性无法直接应用于方法参数,无法绕过该问题。[XmlIgnore]无效的根因是SoapCore在XmlSerializer模式下生成WSDL时,会先遍历操作方法的所有参数判断是否需要生成对应XML架构,该逻辑既没有识别[XmlIgnore]特性做跳过处理,也没有内置将CancellationToken作为运行时注入参数排除。 - 替代方案的缺陷:切换序列化器为
SoapSerializer.DataContractSerializer可正常运行,但生成的WSDL会枚举大量未使用的基础类型,文档冗余度高,不符合使用需求。
复现代码
Program.cs
using Microsoft.Extensions.DependencyInjection.Extensions; using SoapCore; namespace TestSoapCore; public static class Program { public static void Main(string[] args) { var builder = WebApplication.CreateBuilder(args); builder.Services.AddSoapCore(); builder.Services.TryAddSingleton<MyService>(); builder.Services.AddMvc(); var app = builder.Build(); app.UseRouting(); app.UseEndpoints(endpoints => { endpoints.UseSoapEndpoint<MyService>( "/Services.svc", new SoapEncoderOptions(), SoapSerializer.XmlSerializer // 切换为SoapSerializer.DataContractSerializer可正常运行,但优先选择XmlSerializer ); }); app.Run(); } }
Contract.cs
using System.Runtime.Serialization; namespace TestSoapCore; [DataContract] public class Contract { [DataMember] public string? TestProperty { get; set; } }
MyService.cs
using System.ServiceModel; using System.Xml.Serialization; namespace TestSoapCore; [ServiceContract] public class MyService { [OperationContract] public async Task<string> Test( Contract contract, // [MessageContract(IsWrapped = false)] 无法应用于参数 [XmlIgnore] // 该特性未生效 CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); return contract?.TestProperty + "2"; } }
已验证结论
- 移除方法的
CancellationToken参数后,XmlSerializer模式下可正常生成精简无冗余的WSDL - DataContractSerializer模式下服务可正常运行,但WSDL包含大量无用基础类型定义,不符合预期
可行解决方案
核心逻辑:CancellationToken属于服务运行时注入的参数,不属于SOAP消息契约的一部分,本就不该出现在WSDL定义中。通过分离服务契约与实现类,将CancellationToken参数从WSDL生成扫描的契约定义中移除,同时保留SoapCore运行时自动注入取消令牌的能力。
- 定义独立的服务契约接口,接口中标记服务契约与操作契约,操作方法不声明CancellationToken参数,作为WSDL生成的依据:
using System.ServiceModel; using System.Threading.Tasks; namespace TestSoapCore; [ServiceContract] public interface IMyService { [OperationContract] Task<string> Test(Contract contract); }
- 编写服务实现类,继承上述契约接口,实现操作方法时额外添加
CancellationToken类型参数。SoapCore调用方法时,会自动从当前请求上下文获取HttpContext.RequestAborted取消令牌,传入该参数,不需要额外配置绑定:
using System.Threading; using System.Threading.Tasks; namespace TestSoapCore; public class MyService : IMyService { public async Task<string> Test( Contract contract, CancellationToken cancellationToken) { cancellationToken.ThrowIfCancellationRequested(); return contract?.TestProperty + "2"; } }
- 修改Program.cs中的服务注册与端点配置,将服务注册为接口与实现的映射,端点泛型参数指定为服务契约接口类型:
using Microsoft.Extensions.DependencyInjection.Extensions; using SoapCore; namespace TestSoapCore; public static class Program { public static void Main(string[] args) { var builder = WebApplication.CreateBuilder(args); builder.Services.AddSoapCore(); // 注册契约接口与实现类的映射 builder.Services.TryAddSingleton<IMyService, MyService>(); builder.Services.AddMvc(); var app = builder.Build(); app.UseRouting(); app.UseEndpoints(endpoints => { // 端点指定契约接口类型 endpoints.UseSoapEndpoint<IMyService>( "/Services.svc", new SoapEncoderOptions(), SoapSerializer.XmlSerializer ); }); app.Run(); } }
调整后可同时满足三个核心诉求:
- 保留
CancellationToken的请求取消能力,运行时可正常接收取消信号 - 继续使用
XmlSerializer序列化器,生成的WSDL精简无冗余类型 - 访问WSDL地址不会抛出类型解析异常
内容的提问来源于stack exchange,提问作者Alexandru Chirita
相关产品推荐
相关产品推荐

