【问题标题】:Handling post requests in ASP.NET MVC在 ASP.NET MVC 中处理 post 请求
【发布时间】:2025-11-24 13:35:01
【问题描述】:

最近我开始使用 MVC,在此之前我使用“经典” ASP.NET。

在使用 Ruby on Rails (RoR) 之后,我想知道如何在 MVC 中实现 POST 请求处理,类似于 RoR 的操作方式。在 RoR 中,您使用 Post 方法,因此您只需要一个视图函数。

在 ASP.NET MVC 中,我需要为 GETPOST 使用 2 个单独的函数,因此我需要将相同的数据初始化两次,并且我不喜欢在我的代码中重复某些内容。

如何通过一种方法检查请求是否为POST

更新:

找到解决方案:我必须使用 Request.HttpMethod。

谢谢!

【问题讨论】:

    标签: c# .net asp.net-mvc post httprequest


    【解决方案1】:

    我遇到了这个问题,想知道同样的事情。下面是对我的情况和我使用的解决方案的详细描述(它利用了此处提供的其他答案)。我最初尝试使用两个单独的方法方法,但是当这些方法的方法签名变得相同时,我遇到了问题。

    我有一个显示报告数据的页面。页面顶部有一个包含一些字段的表单,允许用户指定报告参数,例如开始日期、结束日期等。

    我最初通过创建两个单独的方法来处理 Get 和 Post 方法来解决这个问题。 post 方法会将浏览器重定向到 get 方法,以便将指定的任何参数添加到查询字符串中,这样浏览器就不会通过对话框提示用户将重新发送他们输入的数据如果他们刷新。注意:我后来意识到我可以通过将表单元素的方法属性设置为“Get”来实现这一点,但我认为理想情况下控制器不应该知道视图是如何实现的,所以在我看来这无关紧要。

    当我开发这两种方法时,我最终发现自己处于方法签名相同的情况。此外,这两种方法的代码几乎相同,因此我决定将它们合并到一个方法中并仅检查请求动词,以便在请求不是“获取”时可以做一些稍微不同的事情。我的两种方法的提炼示例如下所示:

        // this will not compile because the method signatures are the same
    
        public ActionResult MyReport(DateRangeReportItem report)
        {
            // if there are no validation errors and the required report parameters are completed
            if (ModelState.IsValid && report.ParametersAreComplete)
            {
                // retrieve report data and populate it on the report model
                report.Result = GetReportData(report.CreateReportParameters());
            }
    
            return View(report);
        }
    
        [AcceptVerbs(HttpVerbs.Post)]
        public ActionResult MyReport(DateRangeReportItem report)
        {
            if (ModelState.IsValid && report.ParametersAreComplete)
            {
                // redirect to the same action so that if the user refreshes the browser it will submit a get request instead of a post request
                // this avoids the browser prompting the user with a dialog saying that their data will be resubmitted
                return RedirectToAction("MyReport", new { StartDate = report.StartDate, EndDate = report.EndDate });
            }
            else
            {
                // there were validation errors, or the report parameters are not yet complete
                return View(report);
            }
        }
    

    为什么我接受一个模型对象作为我的 get 方法的参数?原因是我想利用模型对象中已经内置的验证逻辑。如果有人使用查询字符串中已经指定的所有参数直接导航到我的页面,那么我想继续检索报告数据并将其显示在页面上。但是,如果查询字符串中指定的参数无效,那么我还希望验证错误出现在页面上。通过将我的模型对象作为参数,MVC 框架将自动尝试填充它并捕获任何验证错误,而无需我进行任何额外的工作。

    我使用针对此问题发布的其他答案在我的项目中的基本控制器类上创建 RequestHttpVerb 属性:

        public HttpVerbs RequestHttpVerb
        {
            get { return (HttpVerbs)Enum.Parse(typeof(HttpVerbs), this.Request.HttpMethod, true); }
        }
    

    所以最后我的合并方法如下所示:

        [AcceptVerbs(HttpVerbs.Get | HttpVerbs.Post)]
        public ActionResult MyReport(DateRangeReportItem report)
        {
            // check if there are any validation errors in the model
            // and whether all required report parameters have been completed
            if (ModelState.IsValid && report.ParametersAreComplete)
            {
                // this is unnecessary if the form method is set to "Get"
                // but within the controller I do not know for sure if that will be the case in the view
                if (HttpVerbs.Get != this.RequestHttpVerb)
                {
                    // redirect to the same action so that if the user refreshes the browser it will submit a get request instead of a post request
                    // this avoids the browser prompting the user with a dialog saying that their data will be resubmitted
                    return RedirectToAction("MyReport", new { StartDate = report.StartDate, EndDate = report.EndDate });
                }
    
                // there were no validation errors and all required report parameters are complete
                // retrieve report data and populate that data on the model
                report.Result = GetReportData(report.CreateReportParameters());
            }
    
            // display the view with the report object
            // Any model state errors that occurred while populating the model will result in validation errors being displayed
            return View(report);
        }
    

    这是我目前解决问题的方法。我宁愿不必检查 Request.HttpMethod 属性来确定是否需要执行重定向,但我没有看到解决我的问题的其他方法。我本来可以保留两个单独的方法来处理 Get 和 Post 请求,但是相同的方法签名阻止了这一点。我宁愿重命名我的 Post 操作处理程序方法以避免方法签名冲突,并使用某种机制向 MVC 框架指示我重命名的方法仍应处理“MyReport”操作,但我不知道有任何此类机制在 MVC 框架中。

    【讨论】:

    • 您可以将 [ActionName("MyReport")] 属性添加到名为 MyReportPost(DateRangeReportItem report) 的新方法中,以便两个不同的方法可以使用相同的“MyReport”操作。
    • @James 感谢您的建议。我认为在许多情况下这可能是一个好主意,也许也包括这种情况。在这种情况下,我决定使用单一方法,因为两种情况(Get 和 Post)的逻辑几乎相同。但是,我可以通过定义两个不同的操作方法并让它们都调用包含实际功能的通用方法来使用您建议的方法。
    【解决方案2】:

    如果 GET 和 POST 的方法签名不同,您只需要单独的方法,没有理由为什么一个操作方法不能处理 GET 和 POST 方法。

    如果您需要知道它是 GET 还是 POST,您可以在您的操作中使用 Request.HttpMethod 进行检查,但我建议您使用由 [AcceptVerbs(HttpVerbs.Post)] 属性修饰的单独方法,如其他海报。

    【讨论】:

    • 正是我要说的。这两种方法也做不同的事情。一个返回 GET 视图,另一个进行处理,然后返回适当的视图。
    • 谢谢!这正是我想要的。
    【解决方案3】:

    您不签入 ASP.NET MVC。您使用[AcceptVerbs(HttpVerbs.Post)] 属性装饰您的方法以指示该方法仅适用于帖子,并接受用于处理帖子的方法中的模型。

    我强烈建议对NerdDinner 进行演练,以了解有关 ASP.NET MVC 框架的更多信息。

    【讨论】:

    • 我知道。这就是我所说的。我不希望 GET 和 POST 有两个单独的方法,我只想有 1 个。
    • 作为master,我同时使用了RoR和ASP.NET MVC,我不禁觉得后者的方法装饰方法要优越得多。你不必使用它,但你真的应该使用它。生成的代码将更加简洁、易于阅读和维护,并且不易出错。
    【解决方案4】:

    您可以查看Request.HttpMethod 属性。

    【讨论】:

      【解决方案5】:

      正确的做法是在 Post 请求期间使用 ModelBinding。

      [AcceptVerbs(HttpVerbs.Post)]
      public ActionResult Edit(EmployeeViewModel model)
      {
       //validate data, save employee, handle validation errors...
      }
      

      这样您就不必再次初始化数据。

      【讨论】: