猿问

在到达操作方法之前修剪 Request.Body,用于 XML 中的模型绑定

我有一个以太网到 1-Wire 接口,它会定期发送带有传感器数据的 HTTP 帖子。数据主体采用 XML 格式,但不是完全有效的 XML。我无法更改 HTTP 正文,因为它位于嵌入式软件中。完整的请求正文如下所示:


 ------------------------------3cbec9ce8f05

 Content-Disposition: form-data; name="ServerData"; filename="details.xml"

 Content-Type: text/plain


 <?xml version="1.0" encoding="UTF-8"?>

 <Devices-Detail-Response xmlns="http://www.example.com" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">

 <PollCount>2739</PollCount>

 <DevicesConnected>1</DevicesConnected>

 <LoopTime>1.022</LoopTime>

 <DevicesConnectedChannel1>0</DevicesConnectedChannel1>

 <DevicesConnectedChannel2>0</DevicesConnectedChannel2>

 <DevicesConnectedChannel3>1</DevicesConnectedChannel3>

 <DataErrorsChannel1>0</DataErrorsChannel1>

 <DataErrorsChannel2>0</DataErrorsChannel2>

 <DataErrorsChannel3>0</DataErrorsChannel3>

 <VoltageChannel1>4.91</VoltageChannel1>

 <VoltageChannel2>4.92</VoltageChannel2>

 <VoltageChannel3>4.92</VoltageChannel3>

 <VoltagePower>5.16</VoltagePower>

 <DeviceName>Unit 3 OW2</DeviceName>

 <HostName>EDSOWSERVER2</HostName>

 <MACAddress>00:00:00:00:00:00</MACAddress>

 <DateTime>2018-12-12 16:44:48</DateTime>

 <owd_DS18B20 Description="Programmable resolution thermometer">

 <Name>DS18B20</Name>

 <Family>28</Family>

 <ROMId>F70000024D85E528</ROMId>

 <Health>7</Health>

 <Channel>3</Channel>

 <RawData>C6004B467FFF0A102A00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000</RawData>

 <PrimaryValue>12.3750 Deg C</PrimaryValue>

 <Temperature Units="Centigrade">12.3750</Temperature>

 <UserByte1 Writable="True">75</UserByte1>

 <UserByte2 Writable="True">70</UserByte2>

 <Resolution>12</Resolution>

 <PowerSource>0</PowerSource>

 </owd_DS18B20>

 </Devices-Detail-Response>


 ------------------------------3cbec9ce8f05--

所以我试图在它到达动作方法之前删除'--------...'和Content-Type,以及最后的'--------..'。


慕容708150
浏览 148回答 2
2回答

慕的地6264312

请求正文表明嵌入式软件正在发布多部分数据。以下content-disposition意味着它正在发送一个文件details.xml:------------------------------3cbec9ce8f05Content-Disposition: form-data; name="ServerData"; filename="details.xml"Content-Type: text/plain所以你不需要手动删除 '-----------------------------3cbec9ce8f05' 和Content-Type=.... 只需使用Request.Form.Files.此外,正如@ivan-valadares所建议的,您可以使用模型活页夹来提升重物。但似乎他将所有请求正文视为字符串,然后构造一个XDocument. 一种更优雅的方式是用于XmlSerializer创建强类型对象。此外,IModelBinder 接口没有public bool BindModel(HttpActionContext actionContext, ModelBindingContext bindingContext). 我们应该BindModelAsync(ModelBindingContext bindingContext)改用。所以创建一个模型活页夹如下:public class EmbededServerDataBinder<T> : IModelBinder{&nbsp; &nbsp; public Task BindModelAsync(ModelBindingContext bindingContext)&nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; if (bindingContext == null) { throw new ArgumentNullException(nameof(bindingContext)); }&nbsp; &nbsp; &nbsp; &nbsp; var modelName = bindingContext.BinderModelName ?? "ServerData";&nbsp; &nbsp; &nbsp; &nbsp; XmlSerializer serializer = new XmlSerializer(typeof(T));&nbsp; &nbsp; &nbsp; &nbsp; var data= bindingContext.HttpContext.Request.Form.Files[modelName];&nbsp; &nbsp; &nbsp; &nbsp; if(data == null){&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; bindingContext.ModelState.AddModelError(modelName,"invalid error");&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return Task.CompletedTask;&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; using(var stream = data.OpenReadStream()){&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; var o = serializer.Deserialize(stream);&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; bindingContext.Result = ModelBindingResult.Success(o);&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; return Task.CompletedTask;&nbsp; &nbsp; }}现在您可以在 Action 方法中使用它:&nbsp; &nbsp; [HttpPost]&nbsp; &nbsp; public IActionResult Post([ModelBinder(typeof(EmbededServerDataBinder<Ow_ServerModel>))] Ow_ServerModel ServerData)&nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; return Ok("Working");&nbsp; &nbsp; }注意事项的名称ServerData。模型绑定器将在 content-disposition 中查找此名称。我用你的有效载荷测试它,它按预期工作:

qq_笑_17

您正在尝试使用 ActionFilter 来做到这一点,我建议使用自定义 Binder 并使用正则表达式从请求中提取 de xml。在 WebApiConfig.cs 中注册新的自定义 xml 绑定器public static void Register(HttpConfiguration config){&nbsp; &nbsp; config.Services.Insert(typeof(ModelBinderProvider), 0,&nbsp; &nbsp; new SimpleModelBinderProvider(typeof(XDocument), new XmlCustomBinder()));}创建一个自定义活页夹,它将获取内容主体并仅提取 xmlpublic class XmlCustomBinder : IModelBinder{&nbsp; &nbsp; public bool BindModel(HttpActionContext actionContext, ModelBindingContext bindingContext)&nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; try&nbsp; &nbsp; &nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; var parsedXml = actionContext.Request.Content.ReadAsStringAsync().Result;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; Regex regex = new Regex(@"<\?xml.*>", RegexOptions.Singleline);&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; Match match = regex.Match(parsedXml);&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if (!match.Success) return false;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; parsedXml = match.Groups[0].Value;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; TextReader textReader = new StringReader(parsedXml);&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; XDocument xDocument = XDocument.Load(textReader);&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; bindingContext.Model = xDocument;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return true;&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; catch(Exception ex)&nbsp; &nbsp; &nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; bindingContext.ModelState.AddModelError("XmlCustomBinder", ex);&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return false;&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; }}控制器代码,获取 XDocument (XML) 值[HttpPost][OwServer]public IActionResult Post([ModelBinder(typeof(XmlCustomBinder))] XDocument xDocument){&nbsp; &nbsp; &nbsp;return Ok("Working");}https://docs.microsoft.com/en-us/dotnet/api/system.xml.linq.xdocument?view=netframework-4.7.2
随时随地看视频慕课网APP
我要回答