【Azure API 管理】使用APIM进行XML内容读取时遇见的诡异错误 Expression evaluation failed. Object reference not set to an instance of an object.
问题描述
使用APIM,在 Inbound 中对请求的Body内容进行解析。客户端请求所传递的Request Body为XML格式,需要从Request Body中解析出多个(Element)节点值,然后设置通过(set-variable)为参数在后续使用。
但是验证发现,当且只当使用一个set-variable 从 Request Body中读取数据时候,是可以成功的。如果要读取第二个,第三个时,始终会遇见一个诡异的错误 Expression evaluation failed. Object reference not set to an instance of an object。 关键问题是,为什么第一个可以成功,第二个的语句和第一个完全一样,却面临如此问题?真是诡异!
需要解析的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的语句,两者语法完全一样。
- 但第二次就出现了 未将对象应用到实例的异常。
错误截图:
问题解决
经过反复实验,问题肯定出现在 context.Request.Body.As<XElement> 上,是不是这个内容只能使用一次呢? 经 Google 搜寻,终于得出了官方解释和解决办法:
官方解释
IMessageBody | As<T>(preserveContent: bool = false): Where T: string, byte[],JObject, JToken, JArray, XNode, XElement, XDocument The context.Request.Body.As<T> and context.Response.Body.As<T> methods are used to read either a request and response message body in specified type T . By default, the method:
To avoid that and have the method operate on a copy of the body stream, set the |
context.Request.Body.As<T> 和
context.Response.Body.As<T>
方法用As<T>的方式指定读取 Request 和 Response的Body内容,默认情况下,这个方式读取的时原始消息的Body流,读取一次后就变为不可用,也就是说只能 As<T>的方式一次。这就解释了为什么第二个Set Variable语句出现 Object 异常。
解决办法
正如文档中解释,使用 preserveContent : true 后,可以多次转换 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文件动画:
注意:
- 因为APIM实例的内存存在限制,内部的Memory限制为500MB,当缓存的Request/Response的内容大于500MB的时候,就会出现 MessagePayLoadTooLarge异常。
- 当使用 preserveContent:true 后,会把当前的Body内容缓存在APIM实例的内存中,如果Body内容大于500MB,则会出现 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
【Azure API 管理】使用APIM进行XML内容读取时遇见的诡异错误 Expression evaluation failed. Object reference not set to an instance of an object.的更多相关文章
- Azure Sphere–“Object reference not set to an instance of an object” 解决办法
在开发Azure Sphere应用时,如果出现项目无法编译,出现“Object reference not set to an instance of an object”时,必须从下面两个方面进行检 ...
- 【Azure API 管理】APIM集成内网虚拟网络后,启用自定义路由管理外出流量经过防火墙(Firewall),遇见APIs加载不出来问题
问题描述 使用 Azure 虚拟网络,Azure APIM 可以管理无法通过 Internet 访问的 API,达到以保护企业内部的后端API的目的.在虚拟网络中,启用网络安全组(NSG:Networ ...
- 【Azure API 管理】APIM 配置Validate-JWT策略,验证RS256非对称(公钥/私钥)加密的Token
问题描述 在APIM中配置对传入的Token进行预验证,确保传入后端被保护的API的Authorization信息正确有效,可以使用validate-jwt策略.validate-jwt 策略强制要求 ...
- 【Azure API 管理】APIM CORS策略设置后,跨域请求成功和失败的Header对比实验
在文章"从微信小程序访问APIM出现200空响应的问题中发现CORS的属性[terminate-unmatched-request]功能"中分析了CORS返回空200的问题后,进一 ...
- 【Azure API 管理】在APIM 中添加 log-to-eventhub 策略,把 Request Body 信息全部记录在Event Hub中
问题描述 根据文档 https://docs.azure.cn/zh-cn/api-management/api-management-howto-log-event-hubs, 可以将Azure A ...
- 【Azure API 管理】为调用APIM的请求启用Trace -- 调试APIM Policy的利器
问题描述 在APIM中,通过门户上的 Test 功能,可以非常容易的查看请求的Trace信息,帮助调试 API 对各种Policy,在Inbound,Backend, Outbound部分的耗时问题, ...
- 【Azure API 管理】Azure APIM服务集成在内部虚拟网络后,在内部环境中打开APIM门户使用APIs中的TEST功能失败
问题描述 使用微软API管理服务(Azure API Management),简称APIM. 因为公司策略要求只能内部网络访问,所以启用了VNET集成.集成方式见: (在内部模式下使用 Azure A ...
- 【Azure API 管理】解决API Management添加AAD Group时遇见的 Failed to query Azure Active Directory graph due to error 错误
问题描述 为APIM添加AAD Group时候,等待很长很长的时间,结果添加失败.错误消息为: Write Groups ValidationError :Failed to query Azure ...
- 【Azure API 管理】API Management如何有效且快速更新呢?如对APIs/Policy等设置内容
问题描述 APIM中的内容(API, Policy)等内容,如果有需要更新时候,通常可以在Azure APIM门户上操作,通过一个接口一个设置的修改,也可以针对一个接口导入/导出的方式修改.当APIM ...
随机推荐
- 近期Android学习
近5天没有更新博客,因为这几天略微放下了python的学习,android这边连带项目比较急迫,先花大约1个星期的时间把重心放在Android,但python肯定还会坚持下去,毕竟连着学了那么久了. ...
- iBooker AI+财务提升星球 2020.4 热门讨论
比特币量化套利的心路历程(附python量化招聘)(分享自知- 如何选择一份好的工作? 你知道为什么大家都想去好公司吗? 不- #财务知识# 可转债套利 辉丰转债128012套利之三个知道- #财务知 ...
- AT2651 [ARC077D] SS
定义 \(nxt_i\) 表示在字符串 \(S\) 中以 \(i\) 结尾的最长 \(border\). 引理一:若 \(n - nxt_n \mid n\) 则 \(S_{1 \sim n - nx ...
- epoll反应堆模型实现
epoll反应堆模型demo实现 在高并发TCP请求中,为了实现资源的节省,效率的提升,Epoll逐渐替代了之前的select和poll,它在用户层上规避了忙轮询这种效率不高的监听方式,epoll的时 ...
- Dubbo原理解析(非常透彻)
一.概述 dubbo是一款经典的rpc框架,用来远程调用服务的. dubbo的作用: 面向接口的远程方法调用 智能容错和负载均衡 服务自动注册和发现. 自定义序列化协议 Dubbo 架构中的核心角色有 ...
- 面试官:谈谈你对IO流和NIO的理解
一.概念 NIO即New IO,这个库是在JDK1.4中才引入的.NIO和IO有相同的作用和目的,但实现方式不同,NIO主要用到的是块,所以NIO的效率要比IO高很多.在Java API中提供了两套N ...
- Netty核心原理
Netty核心原理 1. Netty介绍 1.1 原生NIO存在的问题 NIO的类库和API使用繁杂 需要具备其他额外的技能,如java多线程编程等才能编写出高质量的NIO程序 开发工作量和难度都非常 ...
- Solution -「UVA 1104」Chips Challenge
\(\mathcal{Description}\) Link. 在一个 \(n\times n\) 的方格图中,有一些格子已经放了零件,有一些格子可以放零件,其余格子不能放零件.求至多放多少个 ...
- CentOS7+Rsyslog+MySQL 搭建 Rsyslog 日志服务器
文章目录 1.主机环境 2.rsyslog搭建 2.1.rsyslog-server搭建 2.2.rsyslog-client 2.2.1.测试 2.3.rsyslog日志分类 2.3.1.测试 3. ...
- wmware15安装centos7.9
详细步骤如下: 下面位置应该写:D:\k8s\k8s-master01 也可以桥接 下面可以删除 从官方下载的,不需要test,所以选择第一个 默认英文的即可 改为上海 保持默认 配置静态ip 主机名 ...