繁体   English   中英

在ASP.NET中读取请求主体

[英]Read Request Body in ASP.NET

如何读取ASP.NET中的请求主体? 我正在使用Firefox的REST客户端插件为我在本地托管的网站上的资源形成GET请求,而在请求正文中我只是将字符串“test”试图读取它服务器。

在服务器代码(这是一个非常简单的MVC动作)我有这个:

var reader = new StreamReader(Request.InputStream);
var inputString = reader.ReadToEnd();

但是当我调试它时, inputString总是为空。 我不确定如何(例如在FireBug中)确认请求正文确实正确发送,我想我只是假设附加组件正确地执行了此操作。 也许我读错了价值?

也许我错误地记得我的学业,但我认为GET请求实际上没有一个机构。 这个页面说明

HTML规范在技术上定义了“GET”和“POST”之间的区别,因此前者意味着表单数据将被(通过浏览器)编码为URL,而后者意味着表单数据将出现在消息正文中。

所以也许你正在做的事情,但你必须POST数据,以便有一个消息体?

更新

在回应您的评论时,最“正确”的RESTful方式是将每个值作为自己的参数发送:

site.com/MyController/MyAction?id=1&id=2&id=3...

然后,如果您使用相同的名称为其指定数组参数,则您的操作将自动绑定它们:

public ActionResult MyAction(int[] id) {...}

或者如果你是一个受虐狂,你可以尝试一次从Request.QueryString提取值。

我最近想起了这个老问题,并希望根据我自己工作中最近的实现添加另一个完整性的答案。

作为参考, 我最近在博客上发表了这个主题

从本质上讲,这个问题的核心是,“如何将更大,更复杂的搜索条件传递给资源,以获取过滤的对象列表?” 它最终沸腾到两个选择:

  1. 一堆GET查询字符串参数
  2. 请求正文中包含DTO的POST

第一个选项并不理想,因为实现很难看,并且URL在某些时候可能会超过最大长度。 第二个选项,虽然功能齐全,但并没有让我坐在“RESTful”意义上。 毕竟,我正在获取数据,对吧?

但是,请记住,我不仅仅是获取数据。 我正在创建一个对象列表。 每个对象都已存在,但列表本身不存在。 这是一个全新的事情,通过向服务器上的完整对象存储库发出搜索/过滤条件来创建。 (毕竟,请记住,对象集合本身仍然是一个对象。)

这是纯粹的语义差异,但却是一个非常重要的差异。 因为,最简单的是,这意味着我可以轻松地使用POST将这些搜索条件发布到服务器。 响应是我收到的数据,因此我“获取”数据。 但我并没有“获取”数据,因为我实际上正在执行创建行为,创建一个恰好由预先存在的元素组成的对象列表的新实例。

我完全承认,限制从来都不是技术性的,只是语义上的。 它永远不会和我“坐在一起”。 非技术问题需要非技术解决方案,在这种情况下是语义解决方案。 从稍微不同的语义观点来看问题导致了一个更清晰的解决方案,这恰好是我最终使用的解决方案。

除了GET / POST问题,我确实发现你需要将Request.InputStream位置设置回到开头。 感谢这个答案,我找到了。

特别是评论

Request.InputStream //确保在读取后重置位置或稍后读取可能失败

我把它翻译成了

Request.InputStream.Seek(0,0)

从Request.InputStream直接读取是危险的,因为即使数据存在,重新读取时也会为null。 这在实践中得到了验证。 可靠读数如下:

/*Returns a string representing the content of the body 
of the HTTP-request.*/
public static string GetFromBodyString(this HttpRequestBase request)
{
    string result = string.Empty;

    if (request == null || request.InputStream == null)
        return result;

    request.InputStream.Position = 0;

    /*create a new thread in the memory to save the original 
    source form as may be required to read many of the 
    body of the current HTTP- request*/
    using (MemoryStream memoryStream = new MemoryStream())
    {
        request.InputStream.CopyToMemoryStream(memoryStream);
        using (StreamReader streamReader = new StreamReader(memoryStream))
        {
            result = streamReader.ReadToEnd();
        }
    }
    return result;
}

/*Copies bytes from the given stream MemoryStream and writes 
them to another stream.*/
public static void CopyToMemoryStream(this Stream source, MemoryStream destination)
{
    if (source.CanSeek)
    {
        int pos = (int)destination.Position;
        int length = (int)(source.Length - source.Position) + pos;
        destination.SetLength(length);

        while (pos < length)
            pos += source.Read(destination.GetBuffer(), pos, length - pos);
    }
    else
        source.CopyTo((Stream)destination);
}

我会尝试使用HttpClient(可通过Nuget获得)来做这种事情。 它比System.Net对象容易得多

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM