You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在C#中移除XML中的<xsi:type="xsd:string">属性

解决C#调用SOAP服务时object属性自动添加xsi:type导致的验证错误

当调用SOAP服务时,服务定义了一个object类型的属性,传递XML字符串时,WCF序列化器会自动为该节点添加xsi:type="xsd:string"属性,但服务端未声明xsd命名空间,引发以下验证错误:

UndeclaredPrefix: Cannot resolve 'xsd:string' as a QName: the prefix 'xsd' is not declared.
cvc-elt.4.1: The value 'xsd:string' of attribute 'http://www.w3.org/2001/XMLSchema-instance,type' of element 'DatosEspecificos' is not a valid QName.

在SOAPUI中移除该属性后请求可正常执行,因此需要在C#调用时避免或移除这个xsi:type属性。

方案1:将object属性替换为XmlElement类型(优先推荐)

如果可以重新生成或修改服务引用,将Item的类型从object改为XmlElement,这样序列化时会直接嵌入XML节点,不会自动添加xsi:type属性。

代码示例:

XmlDocument xmlDoc = new XmlDocument();
XmlNode nameNode = xmlDoc.CreateElement("Name");
XmlNode genderNode = xmlDoc.CreateElement("Gender");
genderNode.InnerText = "M";
nameNode.AppendChild(genderNode);
xmlDoc.AppendChild(nameNode);

// 此时Item类型为XmlElement
p_SolicitudTransmision[0].Item = xmlDoc.DocumentElement;

方案2:自定义消息检查器移除xsi:type属性

如果无法修改服务引用的类型,通过实现IClientMessageInspector拦截SOAP请求,手动移除多余的xsi:type属性。

步骤1:实现消息检查器

using System.ServiceModel;
using System.ServiceModel.Channels;
using System.ServiceModel.Description;
using System.ServiceModel.Dispatcher;
using System.Xml;

public class RemoveXsiTypeInspector : IClientMessageInspector
{
    public object BeforeSendRequest(ref Message request, IClientChannel channel)
    {
        // 将请求消息转换为XmlDocument进行修改
        var doc = new XmlDocument();
        using (var reader = request.GetReaderAtBodyContents())
        {
            doc.Load(reader);
        }

        // 定位需要移除xsi:type的节点(根据实际节点名称调整)
        var nsManager = new XmlNamespaceManager(doc.NameTable);
        nsManager.AddNamespace("xsi", "http://www.w3.org/2001/XMLSchema-instance");
        var targetNodes = doc.SelectNodes("//DatosEspecificos[@xsi:type='xsd:string']", nsManager);

        foreach (XmlNode node in targetNodes)
        {
            // 移除xsi:type属性
            node.Attributes.RemoveNamedItem("type", "http://www.w3.org/2001/XMLSchema-instance");
        }

        // 重新构造请求消息
        var newMessage = Message.CreateMessage(request.Version, request.Headers.Action, new XmlNodeReader(doc));
        newMessage.Headers.CopyHeadersFrom(request.Headers);
        newMessage.Properties.CopyProperties(request.Properties);
        request = newMessage;

        return null;
    }

    public void AfterReceiveReply(ref Message reply, object correlationState)
    {
        // 无需处理响应
    }
}

步骤2:实现端点行为

public class RemoveXsiTypeBehavior : IEndpointBehavior
{
    public void AddBindingParameters(ServiceEndpoint endpoint, BindingParameterCollection bindingParameters) { }

    public void ApplyClientBehavior(ServiceEndpoint endpoint, ClientRuntime clientRuntime)
    {
        clientRuntime.ClientMessageInspectors.Add(new RemoveXsiTypeInspector());
    }

    public void ApplyDispatchBehavior(ServiceEndpoint endpoint, EndpointDispatcher endpointDispatcher) { }

    public void Validate(ServiceEndpoint endpoint) { }
}

步骤3:给服务客户端添加行为

var soapClient = new YourSoapServiceClient();
soapClient.Endpoint.Behaviors.Add(new RemoveXsiTypeBehavior());

// 正常调用服务方法
soapClient.YourServiceMethod(p_SolicitudTransmision);

方案3:手动构造SOAP请求(绕过WCF序列化)

如果服务结构简单,可直接使用HttpWebRequest发送原始XML,完全控制请求内容,避免自动添加的属性。

代码示例:

var soapRequest = @"<soapenv:Envelope xmlns:soapenv=""http://schemas.xmlsoap.org/soap/envelope/"">
   <soapenv:Header/>
   <soapenv:Body>
      <DatosEspecificos>
         <Name>
            <Gender>M</Gender>
         </Name>
      </DatosEspecificos>
      <!-- 其他请求内容 -->
   </soapenv:Body>
</soapenv:Envelope>";

var request = (HttpWebRequest)WebRequest.Create("http://your-soap-service-url");
request.Method = "POST";
request.ContentType = "text/xml;charset=utf-8";
request.Headers.Add("SOAPAction", "http://your-soap-action-uri");

// 写入请求内容
using (var stream = request.GetRequestStream())
{
    var bytes = Encoding.UTF8.GetBytes(soapRequest);
    stream.Write(bytes, 0, bytes.Length);
}

// 获取响应
using (var response = (HttpWebResponse)request.GetResponse())
using (var reader = new StreamReader(response.GetResponseStream()))
{
    var responseContent = reader.ReadToEnd();
    // 处理响应结果
}

内容的提问来源于stack exchange,提问作者Adrian Tornero Ortiz

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.25 11:47:03