为了账号安全,请及时绑定邮箱和手机立即绑定

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

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

C#
慕容708150 2022-06-12 10:18:04
我有一个以太网到 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,以及最后的'--------..'。
查看完整描述

2 回答

?
慕的地6264312

TA贡献1817条经验 获得超6个赞

请求正文表明嵌入式软件正在发布多部分数据。以下content-disposition意味着它正在发送一个文件details.xml:


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

Content-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

{

    public Task BindModelAsync(ModelBindingContext bindingContext)

    {

        if (bindingContext == null) { throw new ArgumentNullException(nameof(bindingContext)); }

        var modelName = bindingContext.BinderModelName ?? "ServerData";


        XmlSerializer serializer = new XmlSerializer(typeof(T));

        var data= bindingContext.HttpContext.Request.Form.Files[modelName];

        if(data == null){ 

            bindingContext.ModelState.AddModelError(modelName,"invalid error");

            return Task.CompletedTask;

        }

        using(var stream = data.OpenReadStream()){

            var o = serializer.Deserialize(stream);

            bindingContext.Result = ModelBindingResult.Success(o);

        }

        return Task.CompletedTask;

    }

}

现在您可以在 Action 方法中使用它:


    [HttpPost]

    public IActionResult Post([ModelBinder(typeof(EmbededServerDataBinder<Ow_ServerModel>))] Ow_ServerModel ServerData)

    {

        return Ok("Working");

    }

注意事项的名称ServerData。模型绑定器将在 content-disposition 中查找此名称。


我用你的有效载荷测试它,它按预期工作:

//img1.sycdn.imooc.com//62a54d3c000179d407750238.jpg

查看完整回答
反对 回复 2022-06-12
?
qq_笑_17

TA贡献1818条经验 获得超7个赞

您正在尝试使用 ActionFilter 来做到这一点,我建议使用自定义 Binder 并使用正则表达式从请求中提取 de xml。


在 WebApiConfig.cs 中注册新的自定义 xml 绑定器


public static void Register(HttpConfiguration config)

{

    config.Services.Insert(typeof(ModelBinderProvider), 0,

    new SimpleModelBinderProvider(typeof(XDocument), new XmlCustomBinder()));

}

创建一个自定义活页夹,它将获取内容主体并仅提取 xml


public class XmlCustomBinder : IModelBinder

{

    public bool BindModel(HttpActionContext actionContext, ModelBindingContext bindingContext)

    {

        try

        {

            var parsedXml = actionContext.Request.Content.ReadAsStringAsync().Result;

            Regex regex = new Regex(@"<\?xml.*>", RegexOptions.Singleline);

            Match match = regex.Match(parsedXml);

            if (!match.Success) return false;

            parsedXml = match.Groups[0].Value;

            TextReader textReader = new StringReader(parsedXml);

            XDocument xDocument = XDocument.Load(textReader);

            bindingContext.Model = xDocument;

            return true;

        }

        catch(Exception ex)

        {

            bindingContext.ModelState.AddModelError("XmlCustomBinder", ex);

            return false;

        }

    }

}

控制器代码,获取 XDocument (XML) 值


[HttpPost]

[OwServer]

public IActionResult Post([ModelBinder(typeof(XmlCustomBinder))] XDocument xDocument)

{

     return Ok("Working");

}

https://docs.microsoft.com/en-us/dotnet/api/system.xml.linq.xdocument?view=netframework-4.7.2


查看完整回答
反对 回复 2022-06-12
  • 2 回答
  • 0 关注
  • 147 浏览

添加回答

举报

0/150
提交
取消
微信客服

购课补贴
联系客服咨询优惠详情

帮助反馈 APP下载

慕课网APP
您的移动学习伙伴

公众号

扫描二维码
关注慕课网微信公众号