Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/asp.net-core/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 在到达操作方法之前修剪Request.Body,用于XML中的模型绑定_C#_Asp.net Core_Asp.net Core Mvc - Fatal编程技术网

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

C# 在到达操作方法之前修剪Request.Body,用于XML中的模型绑定,c#,asp.net-core,asp.net-core-mvc,C#,Asp.net Core,Asp.net Core Mvc,我有一个以太网到1线的接口,它定期发送一个带有传感器数据的HTTP post。数据体是XML格式的,只是它不是完全有效的XML。我无法更改HTTP主体,因为它位于嵌入式软件中。完整的请求正文如下所示: ------------------------------3cbec9ce8f05 Content-Disposition: form-data; name="ServerData"; filename="details.xml" Content-Type: text/plain &l

我有一个以太网到1线的接口,它定期发送一个带有传感器数据的HTTP post。数据体是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--
------------------------------------3cbec9ce8f05
内容配置:表单数据;name=“ServerData”;filename=“details.xml”
内容类型:文本/纯文本
2739
1.
1.022
0
0
1.
0
0
0
4.91
4.92
4.92
5.16
第三单元OW2
EDSOWSERVER2
00:00:00:00:00:00
2018-12-12 16:44:48
DS18B20
28
F77000024D85E528
7.
3.
C6004B467FFF0A102000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
12.3750摄氏度
12.3750
75
70
12
0
------------------------------3cbec9ce8f05--
因此,我试图在它到达action方法之前删除'----------…'和内容类型,以及结尾处的'-------…'

这是我的控制器:

 using Microsoft.AspNetCore.Mvc;
 using Microsoft.AspNetCore.Mvc.Filters;
 using Microsoft.Extensions.Logging;
 using Monitor.Models;
 using System;
 using System.IO;

 namespace Monitor.Controllers
 {
     [ApiController]
     [Route("api/[controller]")]
     public class SensorController : Controller
     {
         private readonly ILogger _log;

         public SensorController(ILogger<SensorController> logger)
         {
             _log = logger;
         }

         [HttpPost]
         [OwServer]
         public IActionResult Post([FromBody] Ow_ServerModel model)
         {
             return Ok("Working");
         }
     }

     public class OwServer : Attribute, IResourceFilter
     {
         public void OnResourceExecuting(ResourceExecutingContext context)
         {
             context.HttpContext.Request.Headers["Content-Type"] = "application/xml";

             using (StreamReader stream = new StreamReader(context.HttpContext.Request.Body))
             {
                 string body = stream.ReadToEnd();

                 int start = body.IndexOf('<');
                 int last = body.LastIndexOf('>') + 1;

                 string parsedBody = body.Substring(start, (last - start));


                 // context.HttpContext.Request.Body = 
             }

         }

         public void OnResourceExecuted(ResourceExecutedContext context)
         {
         }
     }
 }


 using System;
 using System.Xml.Serialization;

 namespace Monitor.Models
 {
     [Serializable]
     [XmlRoot("Devices-Detail-Response", Namespace = "http://www.example.com")]
     public class Ow_ServerModel
     {
         public int PollCount { get; set; }
     }
 }
使用Microsoft.AspNetCore.Mvc;
使用Microsoft.AspNetCore.Mvc.Filters;
使用Microsoft.Extensions.Logging;
使用Monitor.Models;
使用制度;
使用System.IO;
名称空间监视器.控制器
{
[ApiController]
[路由(“api/[控制器]”)]
公共类传感器控制器:控制器
{
私有只读ILogger_日志;
公共传感器控制器(ILogger记录器)
{
_日志=记录器;
}
[HttpPost]
[OwServer]
public IActionResult Post([FromBody]Ow\u服务器模型)
{
返回正常(“工作”);
}
}
公共类OwServer:Attribute,IResourceFilter
{
public void OnResourceExecuting(ResourceExecutingContext上下文)
{
context.HttpContext.Request.Headers[“内容类型”]=“应用程序/xml”;
使用(StreamReader stream=newstreamreader(context.HttpContext.Request.Body))
{
字符串体=stream.ReadToEnd();
int start=body.IndexOf(“”)+1;
string parsedBody=body.Substring(start,(last-start));
//context.HttpContext.Request.Body=
}
}
public void OnResourceExecuted(ResourceExecutedContext上下文)
{
}
}
}
使用制度;
使用System.Xml.Serialization;
名称空间监视器.Models
{
[可序列化]
[XmlRoot(“设备详细信息响应”,命名空间=”http://www.example.com")]
公共类OWU服务器模型
{
公共整数PollCount{get;set;}
}
}

如果您试图使用ActionFilter来实现这一点,我建议您使用一个自定义绑定器,并使用正则表达式从请求中提取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;
        }
    }
}

请求主体表示嵌入式软件正在发布多部分数据。下面的
内容配置
表示它正在发送一个
details.xml文件

------------------------------3cbec9ce8f05
Content-Disposition: form-data; name="ServerData"; filename="details.xml"
Content-Type: text/plain
因此,您不需要手动删除'------------------------------------3cbec9ce8f05'和
内容类型=…
的边界只需使用
Request.Form.Files

此外,正如所建议的,您可以使用模型活页夹来提起重物。但他似乎将所有请求体都视为字符串,然后构造一个
XDocument
。更优雅的方法是使用
XmlSerializer
创建强类型对象。另外,没有
public bool BindModel(HttpActionContext actionContext,ModelBindingContext bindingContext)的方法
。我们应该改用
bindmodelsync(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;
    }
}
公共类EmbeddedServerDataBinder:IModelBinder
{
公共任务BindModelAsync(ModelBindingContext bindingContext)
{
如果(bindingContext==null){抛出新的ArgumentNullException(nameof(bindingContext));}
var modelName=bindingContext.BinderModelName??“ServerData”;
XmlSerializer serializer=新的XmlSerializer(typeof(T));
var data=bindingContext.HttpContext.Request.Form.Files[modelName];
如果(数据==null){
bindingContext.ModelState.AddModelError(modelName,“无效错误”);
返回Task.CompletedTask;
}
使用(var stream=data.OpenReadStream()){
var o=序列化程序。反序列化(流);
bindingContext.Result=ModelBindingResult.Success(o);
}
返回Task.CompletedTask;
}
}
现在,您可以在操作方法中使用它:

    [HttpPost]
    public IActionResult Post([ModelBinder(typeof(EmbededServerDataBinder<Ow_ServerModel>))] Ow_ServerModel ServerData)
    {
        return Ok("Working");
    }
[HttpPost]
公共IActionResult Post([ModelBinder(typeof(EmbeddedServerDataBinder))]Ow_服务器模型服务器数据)
{
返回正常(“工作”);
}
请注意
ServerData
的名称。模型绑定器将在内容配置中查找此名称

我用你的有效载荷测试了它,它对我来说工作正常:


哇,谢谢!我不知道该文件在http请求中的外观如何,这会造成很多问题sense@itminus请注意:public bool BindModel(HttpActionContext actionContext,ModelBindingContext bindingContext)是WebApicController的modelbinder,BindModelAsync(ModelBindingContext bindingContext)是MVC控制器的modelbinder,因为[ApiController][Route(“api/[controller]”),我认为在本例中是webapi,但我没有看到扩展“:controller”而不是“:ApiController”。在这种情况下,不要忘记在global.asax中注册Modelbinder:ModelBinders.Binders.Add(typeof(XDocument),newxmlcustombinder())@IvanValadares您好,恐怕您没有注意到OP使用的是
ASP.NET核心
,而不是ASP.NET(经典版),WebApicController不存在
    [HttpPost]
    public IActionResult Post([ModelBinder(typeof(EmbededServerDataBinder<Ow_ServerModel>))] Ow_ServerModel ServerData)
    {
        return Ok("Working");
    }