【Azure API 管理】使用APIM進(jìn)行XML內(nèi)容讀取時遇見的詭異錯誤 Expression evaluation failed. Object reference not set to a...

問題描述

使用APIM,在 Inbound 中對請求的Body內(nèi)容進(jìn)行解析辆琅。客戶端請求所傳遞的Request Body為XML格式,需要從Request Body中解析出多個(Element)節(jié)點(diǎn)值吨悍,然后設(shè)置通過(set-variable)為參數(shù)在后續(xù)使用。

但是驗(yàn)證發(fā)現(xiàn)蹋嵌,當(dāng)且只當(dāng)使用一個set-variable 從 Request Body中讀取數(shù)據(jù)時候育瓜,是可以成功的。如果要讀取第二個栽烂,第三個時躏仇,始終會遇見一個詭異的錯誤 Expression evaluation failed. Object reference not set to an instance of an object。 關(guān)鍵問題是愕鼓,為什么第一個可以成功钙态,第二個的語句和第一個完全一樣,卻面臨如此問題菇晃?真是詭異册倒!

需要解析的XML格式如下:

<?xml version="1.0" encoding="utf-8"?>
<CDHotel xmlns="http://schemas.xmlsoap.org/soap/cdhotel/">
<Body>
<GetHotel xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://tempuri.org/">
<input>
<ID xmlns="http://schemas.datacontract.org/2014/01/wcf">202203081007001</ID>
<Name xmlns="http://schemas.datacontract.org/2014/01/wcf">Cheng Du Junyi Hotel</Name>
<Code xmlns="http://schemas.datacontract.org/2014/01/wcf">ICP1009100</Code>
</input>
</GetHotel>
</Body>
</CDHotel>

在APIM Policies中,需要獲取 ID, Name磺送, Code 和 Desc 值驻子,策略語句如下:

<!-- IMPORTANT:
    - Policy elements can appear only within the <inbound>, <outbound>, <backend> section elements.
    - To apply a policy to the incoming request (before it is forwarded to the backend service), place a corresponding policy element within the <inbound> section element.
    - To apply a policy to the outgoing response (before it is sent back to the caller), place a corresponding policy element within the <outbound> section element.
    - To add a policy, place the cursor at the desired insertion point and select a policy from the sidebar.
    - To remove a policy, delete the corresponding policy statement from the policy document.
    - Position the <base> element within a section element to inherit all policies from the corresponding section element in the enclosing scope.
    - Remove the <base> element to prevent inheriting policies from the corresponding section element in the enclosing scope.
    - Policies are applied in the order of their appearance, from the top down.
    - Comments within policy elements are not supported and may disappear. Place your comments between policy elements or at a higher level scope. -->
<policies>
    <inbound>
        <base />
        <set-variable name="myID" value="@(
 context.Request.Body.As<XElement>().Descendants().FirstOrDefault(x => x.Name.LocalName == "ID")?.Value
        )" />
        <set-variable name="myName" value="@(
 context.Request.Body.As<XElement>().Descendants().FirstOrDefault(x => x.Name.LocalName == "Name")?.Value
        )" />
        <set-variable name="myCode" value="@(
 context.Request.Body.As<XElement>().Descendants().FirstOrDefault(x => x.Name.LocalName == "Code")?.Value
        )" />
        <set-variable name="myDesc" value="@(
 context.Request.Body.As<XElement>().Descendants().FirstOrDefault(x => x.Name.LocalName == "Desc")?.Value
        )" />
    </inbound>
    <backend>
        <base />
    </backend>
    <outbound>
        <set-header name="myID" exists-action="override">
            <value>@((string)context.Variables["myID"])</value>
        </set-header>
        <set-header name="myName" exists-action="override">
            <value>@((string)context.Variables["myName"])</value>
        </set-header>
        <set-header name="myCode" exists-action="override">
            <value>@((string)context.Variables["myCode"])</value>
        </set-header>
        <set-header name="myDesc" exists-action="override">
            <value>@((string)context.Variables["myDesc"])</value>
        </set-header>
        <base />
    </outbound>
    <on-error>
        <base />
    </on-error>
</policies>

在APIM的Test功能,查看Trace語句后估灿,錯誤消息為:

set-variable (0.905 ms)
    {
    "message": "Expression was successfully evaluated.",
    "expression": "\n context.Request.Body.As<XElement>().Descendants().FirstOrDefault(x => x.Name.LocalName == \"ID\")?.Value\n        ",
    "value": "202203081007001"
}
set-variable (0.013 ms)
    {
    "message": "Context variable was successfully set.",
    "name": "myID",
    "value": "202203081007001"
}
set-variable (7.898 ms)
    {
    "messages": [
        {
            "message": "Expression evaluation failed.",
            "expression": "\n context.Request.Body.As<XElement>().Descendants().FirstOrDefault(x => x.Name.LocalName == \"Name\")?.Value\n        ",
            "details": "Object reference not set to an instance of an object."
        },
        "Expression evaluation failed. Object reference not set to an instance of an object.", "Object reference not set to an instance of an object."
    ]
}

說明:

  • 綠色高亮部分為Set-Variable的語句崇呵,兩者語法完全一樣。
  • 但第二次就出現(xiàn)了 未將對象應(yīng)用到實(shí)例的異常馅袁。

錯誤截圖:


image

問題解決

經(jīng)過反復(fù)實(shí)驗(yàn)域慷,問題肯定出現(xiàn)在 context.Request.Body.As<XElement> 上,是不是這個內(nèi)容只能使用一次呢? 經(jīng) Google 搜尋犹褒,終于得出了官方解釋和解決辦法:

官方解釋

文檔鏈接:https://docs.microsoft.com/en-us/azure/api-management/api-management-policy-expressions#ContextVariables

image

context.Request.Body.As<T> 和context.Response.Body.As<T>方法用As<T>的方式指定讀取 Request 和 Response的Body內(nèi)容抵窒,默認(rèn)情況下,這個方式讀取的時原始消息的Body流叠骑,讀取一次后就變?yōu)椴豢捎美罨剩簿褪钦f只能 As<T>的方式一次。這就解釋了為什么第二個Set Variable語句出現(xiàn) Object 異常宙枷。

解決辦法

正如文檔中解釋掉房,使用 preserveContent : true 后,可以多次轉(zhuǎn)換 Body Stream慰丛。

修改后的Policy為:

   <inbound>
        <base />
        <set-variable name="myID" value="@(
 context.Request.Body.As<XElement>(preserveContent:true).Descendants().FirstOrDefault(x => x.Name.LocalName == "ID")?.Value
        )" />
        <set-variable name="myName" value="@(
 context.Request.Body.As<XElement>(preserveContent:true).Descendants().FirstOrDefault(x => x.Name.LocalName == "Name")?.Value
        )" />
        <set-variable name="myCode" value="@(
 context.Request.Body.As<XElement>(preserveContent:true).Descendants().FirstOrDefault(x => x.Name.LocalName == "Code")?.Value
        )" />
        <set-variable name="myDesc" value="@(
 context.Request.Body.As<XElement>(preserveContent:true).Descendants().FirstOrDefault(x => x.Name.LocalName == "Desc")?.Value
        )" />
    </inbound>

修改后卓囚,測試解析XML文件動畫:


image

注意:

  • 因?yàn)锳PIM實(shí)例的內(nèi)存存在限制,內(nèi)部的Memory限制為500MB璧帝,當(dāng)緩存的Request/Response的內(nèi)容大于500MB的時候捍岳,就會出現(xiàn) MessagePayLoadTooLarge異常。
  • 當(dāng)使用 preserveContent:true 后睬隶,會把當(dāng)前的Body內(nèi)容緩存在APIM實(shí)例的內(nèi)存中锣夹,如果Body內(nèi)容大于500MB,則會出現(xiàn) MessagePayLoadTooLarge問題苏潜,所以對于Body Size過大的請求银萍,不能使用 Buffer 及讀取整個Response/Request Body在Policy代碼中。

參考資料

API Management policy expressions - Context variable - IMessageBody : https://docs.microsoft.com/en-us/azure/api-management/api-management-policy-expressions#ContextVariables

Get an attribute value from XML Response in azure apim : https://stackoverflow.com/questions/68618339/get-an-attribute-value-from-xml-response-in-azure-apim

XElement Class : https://docs.microsoft.com/en-us/dotnet/api/system.xml.linq.xelement?view=net-6.0

當(dāng)在復(fù)雜的環(huán)境中面臨問題恤左,格物之道需:濁而靜之徐清贴唇,安以動之徐生。 云中飞袋,恰是如此!

分類: 【Azure API 管理】

標(biāo)簽: APIM, APIM Policy 解析XML語句, preserveContent:true, Expression evaluation failed, set-variable

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末戳气,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子巧鸭,更是在濱河造成了極大的恐慌瓶您,老刑警劉巖,帶你破解...
    沈念sama閱讀 219,490評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件纲仍,死亡現(xiàn)場離奇詭異呀袱,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)郑叠,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,581評論 3 395
  • 文/潘曉璐 我一進(jìn)店門夜赵,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人乡革,你說我怎么就攤上這事寇僧√福” “怎么了?”我有些...
    開封第一講書人閱讀 165,830評論 0 356
  • 文/不壞的土叔 我叫張陵婉宰,是天一觀的道長歌豺。 經(jīng)常有香客問我,道長心包,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,957評論 1 295
  • 正文 為了忘掉前任馒铃,我火速辦了婚禮蟹腾,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘区宇。我一直安慰自己娃殖,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,974評論 6 393
  • 文/花漫 我一把揭開白布议谷。 她就那樣靜靜地躺著炉爆,像睡著了一般。 火紅的嫁衣襯著肌膚如雪卧晓。 梳的紋絲不亂的頭發(fā)上芬首,一...
    開封第一講書人閱讀 51,754評論 1 307
  • 那天,我揣著相機(jī)與錄音逼裆,去河邊找鬼郁稍。 笑死,一個胖子當(dāng)著我的面吹牛胜宇,可吹牛的內(nèi)容都是我干的耀怜。 我是一名探鬼主播,決...
    沈念sama閱讀 40,464評論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼桐愉,長吁一口氣:“原來是場噩夢啊……” “哼财破!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起从诲,我...
    開封第一講書人閱讀 39,357評論 0 276
  • 序言:老撾萬榮一對情侶失蹤左痢,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后盏求,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體抖锥,經(jīng)...
    沈念sama閱讀 45,847評論 1 317
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,995評論 3 338
  • 正文 我和宋清朗相戀三年碎罚,在試婚紗的時候發(fā)現(xiàn)自己被綠了磅废。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,137評論 1 351
  • 序言:一個原本活蹦亂跳的男人離奇死亡荆烈,死狀恐怖拯勉,靈堂內(nèi)的尸體忽然破棺而出竟趾,到底是詐尸還是另有隱情,我是刑警寧澤宫峦,帶...
    沈念sama閱讀 35,819評論 5 346
  • 正文 年R本政府宣布岔帽,位于F島的核電站,受9級特大地震影響导绷,放射性物質(zhì)發(fā)生泄漏犀勒。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,482評論 3 331
  • 文/蒙蒙 一妥曲、第九天 我趴在偏房一處隱蔽的房頂上張望贾费。 院中可真熱鬧,春花似錦檐盟、人聲如沸褂萧。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,023評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽导犹。三九已至,卻和暖如春羡忘,著一層夾襖步出監(jiān)牢的瞬間谎痢,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,149評論 1 272
  • 我被黑心中介騙來泰國打工壳坪, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留舶得,地道東北人。 一個月前我還...
    沈念sama閱讀 48,409評論 3 373
  • 正文 我出身青樓爽蝴,卻偏偏與公主長得像沐批,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子蝎亚,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,086評論 2 355

推薦閱讀更多精彩內(nèi)容