如何阻止WCF SOAP的WSDL随请求域名变更soapAction头?
解决WCF服务WSDL中SOAP Action随请求域名变化的问题
WCF默认会根据请求的域名动态修改WSDL里的SOAP Action,导致不同域名访问时返回的soapAction和契约中定义的固定值不匹配,进而触发契约过滤不匹配的错误。以下是两种可行的解决办法:
方法一:自定义ServiceHost固定基地址
创建自定义ServiceHost,强制WSDL生成时使用契约中指定的固定域名作为基地址,这样soapAction就不会随请求域名变化。
代码示例:
public class FixedBaseAddressServiceHost : ServiceHost { public FixedBaseAddressServiceHost(Type serviceType, params Uri[] baseAddresses) : base(serviceType, baseAddresses) { } protected override void ApplyConfiguration() { base.ApplyConfiguration(); // 替换为契约里的固定域名 var fixedUri = new Uri("https://service-abc.com"); BaseAddresses.Clear(); BaseAddresses.Add(fixedUri); } }
然后在Global.asax的Application_Start里用这个自定义Host启动服务:
protected void Application_Start(object sender, EventArgs e) { using var host = new FixedBaseAddressServiceHost(typeof(YourServiceImplementation)); host.Open(); }
方法二:自定义WsdlExporter替换soapAction
通过自定义WsdlExporter,在WSDL生成过程中把所有动态生成的soapAction替换为契约中定义的固定值,适合需要保留多个基地址但固定soapAction的场景。
首先实现自定义WsdlExporter:
public class FixedActionWsdlExporter : WsdlExporter { protected override void ExportEndpoint(ServiceEndpoint endpoint, XmlSchemaSet schemas) { base.ExportEndpoint(endpoint, schemas); // 遍历所有WSDL操作,替换soapAction为固定值 foreach (var wsdlDoc in GeneratedWsdlDocuments) { foreach (var binding in wsdlDoc.Definitions.Bindings) { foreach (var operation in binding.Operations) { var soapOp = operation.Extensions.Find<SoapOperationBinding>(); if (soapOp == null) continue; // 根据操作名匹配替换,这里以GetTodos为例 switch (operation.Name) { case "GetTodos": soapOp.SoapAction = "https://service-abc.com/GetTodos"; break; // 其他操作照此添加 // case "AnotherOperation": // soapOp.SoapAction = "https://service-abc.com/AnotherOperation"; // break; } } } } } }
接着创建对应的服务行为,让WCF使用这个自定义导出器:
public class FixedActionBehavior : IServiceBehavior { public void AddBindingParameters(ServiceDescription desc, ServiceHostBase host, Collection<ServiceEndpoint> endpoints, BindingParameterCollection parameters) { } public void ApplyDispatchBehavior(ServiceDescription desc, ServiceHostBase host) { } public void Validate(ServiceDescription desc, ServiceHostBase host) { var metadataBehavior = desc.Behaviors.Find<ServiceMetadataBehavior>(); if (metadataBehavior != null) { metadataBehavior.MetadataExporter = new FixedActionWsdlExporter(); } } }
最后在代码里注册这个行为:
protected void Application_Start(object sender, EventArgs e) { using var host = new ServiceHost(typeof(YourServiceImplementation)); host.Description.Behaviors.Add(new FixedActionBehavior()); host.Open(); }
验证
部署后用三个域名分别请求WSDL,检查<soap:operation>的soapAction是否均为https://service-abc.com/GetTodos,再用任意域名调用服务,确认不会再出现契约过滤不匹配的错误。
内容的提问来源于stack exchange,提问作者DavidGouge
相关产品推荐
相关产品推荐

