ASP.Net Web 服务 - 将详细信息元素添加到适用于 SOAP 1.1 和 SOAP 1.2 的 SOAP 错误响应的正确方法是什么?

发布于 2024-09-07 17:35:32 字数 4411 浏览 2 评论 0原文

ASP.Net 2.0 Web 服务自动创建 SOAP 1.1 和 SOAP 1.2 绑定。然而,我们的 Web 服务具有 SOAP 扩展和自定义异常处理,这些扩展和自定义异常处理假设仅使用 SOAP 1.1 绑定(例如,SOAP 扩展使用 HTTP SOAPAction 标头来控制行为)。

我希望纠正做出这些假设的代码,并使其能够正确地与 SOAP 1.1 或 SOAP 1.2 一起工作。我在为 SOAP 错误生成元素时遇到了一些问题。

考虑以下 Web 方法实现:

[WebMethod]
public void
ThrowsSoapException()
{
    throw new SoapException("This is a SOAP exception.", SoapException.ServerFaultCode);
}

通过 SOAP 1.1 调用此方法会产生以下结果:

<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
   <soap:Body>
      <soap:Fault>
         <faultcode>soap:Server</faultcode>
         <faultstring>This is a SOAP exception.</faultstring>
         <detail/>
      </soap:Fault>
   </soap:Body>
</soap:Envelope>

通过 SOAP 1.2 调用会产生以下结果:

<soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
   <soap:Body>
      <soap:Fault>
         <soap:Code>
            <soap:Value>soap:Receiver</soap:Value>
         </soap:Code>
         <soap:Reason>
            <soap:Text xml:lang="en">This is a SOAP exception.</soap:Text>
         </soap:Reason>
         <soap:Detail/>
      </soap:Fault>
   </soap:Body>
</soap:Envelope>

在这两种情况下,都有一个空的详细信息元素作为 的子元素。 元素,但它具有不同的限定名称,

现在考虑以下代码,该代码尝试创建带有详细信息元素的 SOAPException。

[WebMethod]
public void
ThrowsSoapExceptionWithDetail()
{
    XmlDocument doc = new XmlDocument();
    XmlNode detail =
        doc.CreateNode(XmlNodeType.Element, SoapException.DetailElementName.Name, SoapException.DetailElementName.Namespace);
    XmlNode custom =
        doc.CreateNode(XmlNodeType.Element, "custom", "http://example.com/xml/namespace/blah");
    custom.InnerXml = "Detail value";
    detail.AppendChild(custom);
    throw new SoapException("This is a SOAP exception with a detail element.", SoapException.ServerFaultCode, Context.Request.Url.AbsoluteUri, detail);
}

SOAP 1.1 响应是:

<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
   <soap:Body>
      <soap:Fault>
         <faultcode>soap:Server</faultcode>
         <faultstring>This is a SOAP exception with a detail element.</faultstring>
         <faultactor>http://localhost/simplewebservice/service1.asmx</faultactor>
         <detail>
            <custom xmlns="http://example.com/xml/namespace/blah">Detail value</custom>
         </detail>
      </soap:Fault>
   </soap:Body>
</soap:Envelope>

SOAP 1.2 响应是:

<soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
   <soap:Body>
      <soap:Fault>
         <soap:Code>
            <soap:Value>soap:Receiver</soap:Value>
         </soap:Code>
         <soap:Reason>
            <soap:Text xml:lang="en">This is a SOAP exception with a detail element.</soap:Text>
         </soap:Reason>
         <soap:Node>http://localhost/simplewebservice/service1.asmx</soap:Node>
         <detail>
            <custom xmlns="http://example.com/xml/namespace/blah">Detail value</custom>
         </detail>
      </soap:Fault>
   </soap:Body>
</soap:Envelope>

SOAP 1.2 响应现在的详细信息元素的限定名称是错误的。它应该是 ,但实际上只是 ,与 SOAP 1.1 响应相同。

ASP.Net 2.0 框架似乎已经做了相当多的工作来将 SOAPException 转换为 SOAP 版本的适当形式,但忽略了正确处理详细信息元素。此外,它们似乎没有像 SoapException.DetailElementName 属性那样公开详细信息元素的正确 SOAP 1.2 限定名称。

那么,向适用于 SOAP 1.1 和 SOAP 1.2 的 SOAP 错误响应添加详细信息元素的正确方法是什么?我是否需要自己检测 SOAP 版本并硬编码细节元素的 SOAP 1.2 限定名称?

ASP.Net 2.0 Web Services automatically create both SOAP 1.1 and SOAP 1.2 bindings. Our web service, however, has SOAP extensions and custom exception handling that make the assumption that only the SOAP 1.1 binding is used (for example, the SOAP extension uses the HTTP SOAPAction header to control behavior).

I am looking to correct the code that makes these assumptions and make it work with either SOAP 1.1 or SOAP 1.2 properly. I am running into a bit of a problem in the generation of elements for our SOAP faults.

Consider the following web method implementation:

[WebMethod]
public void
ThrowsSoapException()
{
    throw new SoapException("This is a SOAP exception.", SoapException.ServerFaultCode);
}

Invoking this via SOAP 1.1 yields the following result:

<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
   <soap:Body>
      <soap:Fault>
         <faultcode>soap:Server</faultcode>
         <faultstring>This is a SOAP exception.</faultstring>
         <detail/>
      </soap:Fault>
   </soap:Body>
</soap:Envelope>

Invoking via SOAP 1.2 yields the following result:

<soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
   <soap:Body>
      <soap:Fault>
         <soap:Code>
            <soap:Value>soap:Receiver</soap:Value>
         </soap:Code>
         <soap:Reason>
            <soap:Text xml:lang="en">This is a SOAP exception.</soap:Text>
         </soap:Reason>
         <soap:Detail/>
      </soap:Fault>
   </soap:Body>
</soap:Envelope>

In both these cases there is an empty detail element as a child of the <soap:Fault> element, but it has a different qualified name, either <detail> or <soap:Detail>.

Now consider the following code that tries to create a SOAPException with a detail element.

[WebMethod]
public void
ThrowsSoapExceptionWithDetail()
{
    XmlDocument doc = new XmlDocument();
    XmlNode detail =
        doc.CreateNode(XmlNodeType.Element, SoapException.DetailElementName.Name, SoapException.DetailElementName.Namespace);
    XmlNode custom =
        doc.CreateNode(XmlNodeType.Element, "custom", "http://example.com/xml/namespace/blah");
    custom.InnerXml = "Detail value";
    detail.AppendChild(custom);
    throw new SoapException("This is a SOAP exception with a detail element.", SoapException.ServerFaultCode, Context.Request.Url.AbsoluteUri, detail);
}

The SOAP 1.1 response is:

<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
   <soap:Body>
      <soap:Fault>
         <faultcode>soap:Server</faultcode>
         <faultstring>This is a SOAP exception with a detail element.</faultstring>
         <faultactor>http://localhost/simplewebservice/service1.asmx</faultactor>
         <detail>
            <custom xmlns="http://example.com/xml/namespace/blah">Detail value</custom>
         </detail>
      </soap:Fault>
   </soap:Body>
</soap:Envelope>

and the SOAP 1.2 response is:

<soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
   <soap:Body>
      <soap:Fault>
         <soap:Code>
            <soap:Value>soap:Receiver</soap:Value>
         </soap:Code>
         <soap:Reason>
            <soap:Text xml:lang="en">This is a SOAP exception with a detail element.</soap:Text>
         </soap:Reason>
         <soap:Node>http://localhost/simplewebservice/service1.asmx</soap:Node>
         <detail>
            <custom xmlns="http://example.com/xml/namespace/blah">Detail value</custom>
         </detail>
      </soap:Fault>
   </soap:Body>
</soap:Envelope>

The SOAP 1.2 response now has the wrong qualified name for the detail element. It should be <soap:Detail>, but instead is merely <detail>, same as the SOAP 1.1 response.

It seems that the ASP.Net 2.0 framework has done quite a bit to transform a SOAPException into the appropriate form for the SOAP version, but neglected to properly handle the detail element. Additionally, they don't seem to have exposed the correct SOAP 1.2 qualified name for the detail element as was done with the SoapException.DetailElementName property.

So, what is the correct way to add a detail element to a SOAP fault response that works for both SOAP 1.1 and SOAP 1.2? Do I need to detect the SOAP version myself and hard-code the SOAP 1.2 qualified name for the detail element?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

木落 2024-09-14 17:35:32

不知道你的问题的编码部分,抱歉,但解决方法是在你的 web.config 中禁用soap1.2,如果你还没有这样看的话。

....
  <webServices>
    <protocols>
      <remove name="HttpSoap12"/>
    </protocols>
  </webServices>

No idea about the coding part of your question, sorry, but a workaround wound be to disable the soap1.2 in your web.config, if you haven't already look that way.

....
  <webServices>
    <protocols>
      <remove name="HttpSoap12"/>
    </protocols>
  </webServices>
枕头说它不想醒 2024-09-14 17:35:32

以下内容绝无讽刺之意:

解决此问题的方法是使用 WCF。

这看起来像是 ASMX Web 服务处理 SOAP 1.2 错误中的详细信息元素时出现的错误。根据元素是否具有值来更改元素的限定名称显然是没有意义的。

您可以在 Connect 上报告此错误,但由于仅修复了关键的 ASMX 错误,因此这不太可能有帮助你。

我怀疑 WCF 有这个问题,因为它完全支持 SOAP 错误。

The following is not meant to be snide:

The fix to this problem is to use WCF.

This looks like a bug in ASMX web services handling of the detail element in a SOAP 1.2 fault. It obviously makes no sense for the qualified name of the element to change based on whether or not the element has a value.

You could report this error on Connect, but since only critical ASMX bugs are being fixed, that's unlikely to help you.

I doubt that WCF has this problem, since it fully supports SOAP Faults.

只有影子陪我不离不弃 2024-09-14 17:35:32

这是一个迟到的答案,但由于我自己也遇到了这个问题,所以我想我不妨将我的解决方案放在这里,这本质上是将 SOAP 协议的版本传递给构建错误的详细信息部分的方法信息。

WebService 派生 ASMX Web 服务类的类公开 SoapVersion 属性,其中包含用于发出当前 SOAP 请求的 SOAP 协议的版本。

然后可以轻松构建适合当前 SOAP 版本的详细信息部分。

using System.Xml.Linq;

XNamespace detailElementNamespace;
string detailElementName;
if (soapVersion == SoapProtocolVersion.Soap12)
{
    detailElementNamespace = "http://www.w3.org/2003/05/soap-envelope";
    detailElementName = "Detail";
}
else
{
    detailElementNamespace = "";
    detailElementName = "detail";
}

var document = new XmlDocument();
document.LoadXml(
    new XElement(detailElementNamespace + detailElementName,
        new XElement("MySection",
            new XElement("MyCode", "..."),
            new XElement("MyDescription", "...")
            )).ToString());

throw new SoapException(
    "MESSAGE",
    SoapException.ClientFaultCode,
    "ACTOR",
    document.DocumentElement);

This is a late answer, but since I've ran into the issue myself I thought I might as well put my solution here, which is essentially to pass along the version of the SOAP protocol to the method that builds the detail section of the fault message.

The WebService class from which an ASMX web service class is derived exposes the SoapVersion property, which contains the version of the SOAP protocol used to make the current SOAP request.

A detail section appropriate for the current SOAP version can then be built easily.

using System.Xml.Linq;

XNamespace detailElementNamespace;
string detailElementName;
if (soapVersion == SoapProtocolVersion.Soap12)
{
    detailElementNamespace = "http://www.w3.org/2003/05/soap-envelope";
    detailElementName = "Detail";
}
else
{
    detailElementNamespace = "";
    detailElementName = "detail";
}

var document = new XmlDocument();
document.LoadXml(
    new XElement(detailElementNamespace + detailElementName,
        new XElement("MySection",
            new XElement("MyCode", "..."),
            new XElement("MyDescription", "...")
            )).ToString());

throw new SoapException(
    "MESSAGE",
    SoapException.ClientFaultCode,
    "ACTOR",
    document.DocumentElement);
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文