【问题标题】:Receive (and send) XML via POST with ASP.NET使用 ASP.NET 通过 POST 接收(和发送)XML
【发布时间】:2011-02-18 11:01:05
【问题描述】:

我必须设置一个接收 POST 的 XML“Web 服务”,其中“Content-type 标头将指定“text/xml”。”

将 XML 放入 XDocument 以供 VB.NET 的轴查询访问的最简单方法是什么?

我不相信 Web 服务可以保证遵循任何协议(例如 SOAP 等);只是各种请求的特定标签和子标签,它将使用基本身份验证,所以我必须处理标头。

(如果重要的话:
* 实时版本将使用 HTTPS,并且
* 响应也是 XML。)

【问题讨论】:

  • 如果 WCF 答案,请将其添加为答案。我绝对不一定需要使用 WCF 来实现它。

标签: asp.net .net xml web-services .net-3.5


【解决方案1】:

当您创建 Web 服务时定义您将收到的 XML 格式,并由发送方来满足您的格式。

我通常在DataSet 中模拟我的Web 服务将接收到的DataTables 信息(因为这与我可能将它们存储在数据库中的方式非常相似)然后在我模拟的DataSet 上执行DataSet.getXML() (可能还获得默认架构)用作我期望“发布”到我的 Web 服务的 XML 的模板。

然后,当我的 web 服务收到一个帖子时,我可以简单地获取发送的 XML,并在发布的 XML 上使用DataSet.readXML()...并处理在DataSet 中发送的信息。

我的大部分网络服务“返回”值都是基于发布信息的查询结果,所以我对返回值进行了同样的格式化...在DataSet 中获取我返回的查询数据的结果, DataSet.getXML() .. 并返回。

【讨论】:

  • 不,我们正在根据现有规范实施“Web 服务”,因此我们没有定义 XML 格式。
  • 啊,我明白你的意思了——我通常将其称为“使用”或“使用”Web 服务……只是术语。 :-)
【解决方案2】:

对于没有在这里回答你的问题,我想提前道歉,但我想给一点警告。也许这已经是您正在考虑的事情,但是如果您不采取适当的应对措施,当处理来自未知来源的 XML(通过 HTTP 和HTTPS)。

有一种技术称为 XML 实体扩展攻击。例如,看看这种看似天真无邪的 XML,当它试图处理它时,它会让你的服务器陷入瘫痪:

<!DOCTYPE foo [ 
<!ENTITY a "1234567890" > 
<!ENTITY b "&a;&a;&a;&a;&a;&a;&a;&a;" > 
<!ENTITY c "&b;&b;&b;&b;&b;&b;&b;&b;" > 
<!ENTITY d "&c;&c;&c;&c;&c;&c;&c;&c;" > 
<!ENTITY e "&d;&d;&d;&d;&d;&d;&d;&d;" > 
<!ENTITY f "&e;&e;&e;&e;&e;&e;&e;&e;" > 
<!ENTITY g "&f;&f;&f;&f;&f;&f;&f;&f;" > 
<!ENTITY h "&g;&g;&g;&g;&g;&g;&g;&g;" > 
<!ENTITY i "&h;&h;&h;&h;&h;&h;&h;&h;" > 
<!ENTITY j "&i;&i;&i;&i;&i;&i;&i;&i;" > 
<!ENTITY l "&k;&k;&k;&k;&k;&k;&k;&k;" > 
<!ENTITY m "&l;&l;&l;&l;&l;&l;&l;&l;" > 
]> 
<foo>&m;</foo>

这个小于 500 字节的小 XML 文档将使您的服务器尝试分配至少 160 GB 的内存。

您可以通过在处理传入的 XML(带有 DTD)之前对其进行验证来保护自己。

您可以阅读有关此攻击的更多信息,here

祝你好运。

【讨论】:

  • +1 获取有用信息。我知道您已链接到您的博客,但直接链接是 blogs.msdn.com/tomholl/archive/2009/05/21/…
  • 你是对的。那是我的懒惰。我将链接更改为直接指向 Tom Hollander 的博客。
  • 我删除了我对这个“答案”的 +1 投票,因为它从未回答视图中删除了我的问题。史蒂文,再编辑一次,这样我就可以把你的 +1 还给你 :-)
  • @codebreaker:无法修补。这就是XmlDocument 的工作方式。解决方案是使用XmlReader 或针对 XSD 验证 xml。
  • @Steven 感谢您的信息:)
【解决方案3】:

鉴于 Steven 的警告,答案可能是在 Page_Load 事件中首先使用 Tom Holland's test 手动解析 Request.InputStream,然后是 XDocument.Load

在我问这个问题之前启动了谷歌搜索,但后来才检查,发现this,也表明我在正确的轨道上。

我还想问我的观点所暗示的问题,即响应也必须是 XML,什么是最好的方法,但我找到了答案 here

综上,最终代码为:

 Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load

    If Request.ContentType <> "text/xml" Then _
        Throw New HttpException(500, "Unexpected Content-Type")

    Dim id = CheckBasicAuthentication

    Dim textReader = New IO.StreamReader(Request.InputStream)

    CheckXmlValidity(textReader)

    ' Reset the stream & reader
    Request.InputStream.Seek(0, IO.SeekOrigin.Begin)
    textReader.DiscardBufferedData()

    Dim xmlIn = XDocument.Load(textReader)

    ' process XML in xmlIn

    Dim xmlOut = <?xml version="1.0" encoding="UTF-8" ?>
                 <someresult>
                     <header>
                         <id><%= id.ToString() %></id>
                         <datestamp>To be inserted</datestamp>
                     </header>
                     <result/>
                 </someresult>

    ' Further generation of XML for output

    xmlOut.<someresult>.<header>.<datestamp>.Value = Date.UtcNow.ToString(xmlDateFormat)
    xmlText.Text = xmlOut.ToString
End Sub

Private Function CheckBasicAuthentication() As Integer
    Dim httpAuthorisation = Request.Headers("Authorization")
    If Left(httpAuthorisation, 6).ToUpperInvariant <> "BASIC " Then _
        Throw New HttpException(401, "Basic Authentication Required")
    Dim authorization = Convert.FromBase64String(Mid(httpAuthorisation, 7))
    Dim credentials = Text.Encoding.UTF8.GetString(authorization).Split(":"c)
    Dim username = credentials(0)
    Dim password = credentials(1)

    Return ConfirmValidUser(username, password)
End Function

Private Shared Sub CheckXmlValidity(ByVal textReader As System.IO.StreamReader)
    Try
        ' Check for "interesting" xml documents.
        Dim settings = New System.Xml.XmlReaderSettings()
        settings.XmlResolver = Nothing
        settings.MaxCharactersInDocument = 655360
        ' Successfully parse the file, otherwise an XmlException is to be thrown. '
        Dim reader = System.Xml.XmlReader.Create(textReader, settings)
        Try
            While reader.Read()
                'Just checking.
            End While
        Finally
            reader.Close()
        End Try
    Catch ex As Exception
        Throw New HttpException(500, "Invalid Xml data", ex)
    End Try
End Sub

而 ASP.NET 网页.aspx 是:

<%@ Page Language="VB" AutoEventWireup="false" CodeFile="webpage.aspx.vb" Inherits="WebPage" ContentType="text/xml" %>

<asp:Literal ID="xmlText" runat="server" Mode="PassThrough"></asp:Literal> 

NB 抛出 HTTPException 不是针对不需要的场景的有效最终解决方案。

【讨论】:

  • 如果您想处理任意请求编码,您可以使用 Request.ContentEncoding 变量作为 IO.StreamReader 的第二个参数。 IO.StreamReader 默认为 UTF-8
  • 仅供参考,为了能够使 HTTP 基本身份验证像这样工作,您需要从 IIS 管理器中的目录/文件中禁用所有表单身份验证。您可能还想在 401 响应中设置 WWW-Authenticate 标头。
  • Vikram Lakhotia 的网站已消失,但仍在 WayBackMachine 中:web.archive.org/web/20101231220015/http://…
猜你喜欢
  • 2013-03-12
  • 1970-01-01
  • 2012-10-11
  • 2012-03-10
  • 2013-07-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多