读取 ASP.NET 中的请求正文

发布于 2024-12-02 16:08:26 字数 384 浏览 0 评论 0原文

如何读取 ASP.NET 中的请求正文?我正在使用 Firefox 的 REST 客户端插件来形成对我本地托管的站点上的资源的 GET 请求,并且在请求正文中我只是放置字符串“test”以尝试读取它服务器。

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

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

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

How does one read the request body in ASP.NET? I'm using the REST Client add-on for Firefox to form a GET request for a resource on a site I'm hosting locally, and in the Request Body I'm just putting the string "test" to try to read it on the server.

In the server code (which is a very simple MVC action) I have this:

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

But when I debug into it, inputString is always empty. I'm not sure how else (such as in FireBug) to confirm that the request body is indeed being sent properly, I guess I'm just assuming that the add-on is doing that correctly. Maybe I'm reading the value incorrectly?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

难如初 2024-12-09 16:08:26

也许我记错了我的学校教育,但我认为 GET 请求实际上没有主体。 此页面说明

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

那么也许您的做法是正确的,但您必须 POST 数据才能获得消息正文?

更新

响应您的评论,最“正确”的 RESTful 方法是将每个值作为其自己的参数发送:

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

然后,如果您给它一个同名的数组参数,您的操作将自动绑定这些值:

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

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

Maybe I'm misremembering my schooling, but I think GET requests don't actually have a body. This page states.

The HTML specifications technically define the difference between "GET" and "POST" so that former means that form data is to be encoded (by a browser) into a URL while the latter means that the form data is to appear within a message body.

So maybe you're doing things correctly, but you have to POST data in order to have a message body?

Update

In response to your comment, the most "correct" RESTful way would be to send each of the values as its own parameter:

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

Then your action will auto-bind these if you give it an array parameter by the same name:

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

Or if you're a masochist you can maybe try pulling the values out of Request.QueryString one at a time.

思慕 2024-12-09 16:08:26

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

作为参考,我已经就该主题发表了博客 最近。

本质上,这个问题的核心是“如何将更大、更复杂的搜索条件传递给资源以获取经过筛选的对象列表?”最终归结为两个选择:

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

第一个选项并不理想,因为实现很丑陋,并且 URL 在某些时候可能会超过最大长度。第二个选项虽然实用,但从“RESTful”的意义上来说并不适合我。毕竟,我获取数据,对吧?

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

这是纯粹的语义差异,但绝对重要。因为,从最简单的角度来说,这意味着我可以轻松地使用 POST 向服务器发出这些搜索条件。响应是我收到的数据,所以我正在“获取”数据。但我并不是在“获取”数据,因为我实际上是在执行创建行为,创建恰好由预先存在的元素组成的对象列表的新实例。

我完全承认这种限制从来都不是技术上的,而只是语义上的。它只是从来没有“适合”我。非技术问题需要非技术解决方案,在本例中是语义解决方案。从稍微不同的语义角度看待问题会产生一个更清晰的解决方案,这恰好是我最终使用的解决方案。

I was recently reminded of this old question, and wanted to add another answer for completeness based on more recent implementations in my own work.

For reference, I've blogged on the subject recently.

Essentially, the heart of this question was, "How can I pass larger and more complex search criteria to a resource to GET a filtered list of objects?" And it ended up boiling down to two choices:

  1. A bunch of GET query string parameters
  2. A POST with a DTO in the request body

The first option isn't ideal, because implementation is ugly and the URL will likely exceed a maximum length at some point. The second option, while functional, just didn't sit right with me in a "RESTful" sense. After all, I'm GETting data, right?

However, keep in mind that I'm not just GETting data. I'm creating a list of objects. Each object already exists, but the list itself doesn't. It's a brand new thing, created by issuing search/filter criteria to the complete repository of objects on the server. (After all, remember that a collection of objects is still, itself, an object.)

It's a purely semantic difference, but a decidedly important one. Because, at its simplest, it means I can comfortably use POST to issue these search criteria to the server. The response is data which I receive, so I'm "getting" data. But I'm not "GETting" data in the sense that I'm actually performing an act of creation, creating a new instance of a list of objects which happens to be composed of pre-existing elements.

I'll fully admit that the limitation was never technical, it was just semantic. It just never "sat right" with me. A non-technical problem demands a non-technical solution, in this case a semantic one. Looking at the problem from a slightly different semantic viewpoint resulted in a much cleaner solution, which happened to be the solution I ended up using in the first place.

岁月无声 2024-12-09 16:08:26

除了 GET/POST 问题之外,我确实发现您需要将 Request.InputStream 位置设置回开始位置。感谢 这个答案 我成立。

具体评论

Request.InputStream // 确保在读取后重置 Position,否则后面的读取可能会失败

我翻译成

Request.InputStream.Seek(0,0)

Aside from the GET/POST issue, I did discover that you need to set the Request.InputStream position back to the start. Thanks to this answer I found.

Specifically the comment

Request.InputStream // make sure to reset the Position after reading or later reads may fail

Which I translated into

Request.InputStream.Seek(0,0)
肩上的翅膀 2024-12-09 16:08:26

我会尝试使用 HttpClient (可通过 Nuget 获得)来执行此类操作。它比 System.Net 对象容易得多

I would try using the HttpClient (available via Nuget) for doing this type of thing. Its so much easier than the System.Net objects

挽袖吟 2024-12-09 16:08:26

直接从 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);
}

Direct reading from the Request.InputStream dangerous because when re-reading will get null even if the data exists. This is verified in practice.
Reliable reading is performed as follows:

/*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);
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文