【问题标题】:How to retrieve form values from HTTPPOST, dictionary or?如何从 HTTPPOST、字典或检索表单值?
【发布时间】:2011-07-02 14:05:03
【问题描述】:

我有一个具有此操作方法的 MVC 控制器:

[HttpPost]
public ActionResult SubmitAction()
{
     // Get Post Params Here
 ... return something ...
}

表单是一个非平凡的表单,带有一个简单的文本框。

问题

如何访问参数值?

我不是从视图发帖,帖子来自外部。我假设有一组我可以访问的键/值对。

我尝试了Request.Params.Get("simpleTextBox");,但它返回错误“抱歉,处理您的请求时出错。”。

【问题讨论】:

    标签: asp.net asp.net-mvc-3 http-post


    【解决方案1】:

    您可以让您的控制器操作采用反映表单输入名称的对象,默认模型绑定器将自动为您创建此对象:

    [HttpPost]
    public ActionResult SubmitAction(SomeModel model)
    {
        var value1 = model.SimpleProp1;
        var value2 = model.SimpleProp2;
        var value3 = model.ComplexProp1.SimpleProp1;
        ...
    
        ... return something ...
    }
    

    另一种(显然更丑)的方式是:

    [HttpPost]
    public ActionResult SubmitAction()
    {
        var value1 = Request["SimpleProp1"];
        var value2 = Request["SimpleProp2"];
        var value3 = Request["ComplexProp1.SimpleProp1"];
        ...
    
        ... return something ...
    }
    

    【讨论】:

    • 我想指出的是,您在选项2中丢失了编译器的备份。如果模型发生更改,编译器将无法捕获相关控制器中的更改。选项 2 有很好的案例,但我不鼓励广泛使用。
    • 有时你需要丑陋的东西,当你已经知道什么是最佳实践时有一个选择是件好事
    • 作为还在学习.net的人,为什么第二种方式更丑?
    • @Goose,因为它是魔术字符串。您没有任何编译时安全性。如果您在变量名中输入错误,您的代码将在运行时失败,而如果您使用强类型,编译器将是您的朋友。
    • @DarinDimitrov 是有道理的。与我来自的世界不同。非常好的功能。
    【解决方案2】:

    简单地说,你可以使用FormCollectionlike:

    [HttpPost] 
    public ActionResult SubmitAction(FormCollection collection)
    {
         // Get Post Params Here
     string var1 = collection["var1"];
    }
    

    您也可以使用一个类,它与表单值进行映射,asp.net mvc 引擎会自动填充它:

    //Defined in another file
    class MyForm
    {
      public string var1 { get; set; }
    }
    
    [HttpPost]
    public ActionResult SubmitAction(MyForm form)
    {      
      string var1 = form1.Var1;
    }
    

    【讨论】:

    • 我喜欢课堂解决方案的简单和简单
    【解决方案3】:

    答案非常好,但在最新版本的 MVC 和 .NET 中还有另一种我非常喜欢使用的方法,而不是“老派”的 FormCollection 和 Request 键。


    考虑一个包含在执行 AJAX 或 FORM POST 的表单标记中的 HTML sn-p。

    <input type="hidden"   name="TrackingID" 
    <input type="text"     name="FirstName"  id="firstnametext" />
    <input type="checkbox" name="IsLegal"  value="Do you accept terms and conditions?" />
    

    您的控制器实际上会解析表单数据并尝试将其作为已定义类型的参数传递给您。我包括复选框,因为它是一个棘手的。如果选中则返回文本“on”,如果未选中则返回 null。但要求是这些定义的变量必须存在(除非可以为空(请记住,尽管string 可以为空))否则 AJAX 或 POST 返回将失败。

    [HttpPost]
    public ActionResult PostBack(int TrackingID, string FirstName, string IsLegal){
        MyData.SaveRequest(TrackingID,FirstName, IsLegal == null ? false : true);
    }
    

    您也可以在不使用任何剃须刀助手的情况下回发模型。我发现有时需要这样做。

    public Class HomeModel
    {
      public int HouseNumber { get; set; }
      public string StreetAddress { get; set; }
    }
    

    HTML 标记将只是 ...

    <input type="text" name="variableName.HouseNumber" id="whateverid" >
    

    并且您的控制器(Razor 引擎)将拦截表单变量“variableName”(名称如您所愿,但保持一致)并尝试构建它并将其转换为 MyModel。

    [HttpPost]
    public ActionResult PostBack(HomeModel variableName){
        postBack.HouseNumber; //The value user entered
        postBack.StreetAddress; //the default value of NULL.
    }
    

    当控制器需要一个模型(在本例中为 HomeModel)时,您不必定义所有字段,因为解析器只会将它们保留为默认值,通常为 NULL。好消息是您可以在标记上混合和匹配各种模型,并且后回解析将尽可能多地填充。您不需要在页面上定义模型或使用任何帮助程序。

    TIP:控制器中参数的名称就是定义的名称 在 HTML 标记中,“name=”不是模型的名称,而是 !

    中预期变量的名称

    使用List&lt;&gt; 的标记要复杂一些。

    <input type="text" name="variableNameHere[0].HouseNumber" id="id"           value="0">
    <input type="text" name="variableNameHere[1].HouseNumber" id="whateverid-x" value="1">
    <input type="text" name="variableNameHere[2].HouseNumber"                   value="2">
    <input type="text" name="variableNameHere[3].HouseNumber" id="whateverid22" value="3">
    

    列表上的索引 必须始终从零开始且连续。 0,1,2,3。

    [HttpPost]
    public ActionResult PostBack(List<HomeModel> variableNameHere){
         int counter = MyHomes.Count()
         foreach(var home in MyHomes)
         { ... }
    }
    

    IEnumerable&lt;&gt; 用于非零基和非顺序索引回发。我们需要添加一个额外的隐藏输入来帮助活页夹。

    <input type="hidden" name="variableNameHere.Index" value="278">
    <input type="text" name="variableNameHere[278].HouseNumber" id="id"      value="3">
    
    <input type="hidden" name="variableNameHere.Index" value="99976">
    <input type="text" name="variableNameHere[99976].HouseNumber" id="id3"   value="4">
    
    <input type="hidden" name="variableNameHere.Index" value="777">
    <input type="text" name="variableNameHere[777].HouseNumber" id="id23"    value="5">
    

    而代码只需要使用IEnumerable并调用ToList()

    [HttpPost]
    public ActionResult PostBack(IEnumerable<MyModel> variableNameHere){
         int counter = variableNameHere.ToList().Count()
         foreach(var home in variableNameHere)
         { ... }
    }
    

    建议每页使用单个模型或视图模型(模型包含其他模型以创建复杂的“视图”模型)。提议的混合和匹配可能被认为是不好的做法,但只要它有效且可读,它就不是坏事。然而,它确实展示了 Razor 引擎的强大功能和灵活性。

    因此,如果您需要从 Razor 助手中添加任意内容或覆盖另一个值,或者只是不想制作自己的助手,对于使用一些不寻常的数据组合的单个表单,您可以快速使用这些方法接受额外的数据。

    【讨论】:

    • 使用索引选项是晦涩难懂的。在上帝的绿色地球上谁会知道使用它或者它甚至存在?!但是,我很高兴我找到了这篇文章。这将节省大量的网络流量。
    • 这对我有用,但只有在我将 更改为 @Html.Hidden("myId")
    • @Piotr - 请修正您与 MyModel 和 MyHomes 的参考不一致。它目前的情况会引起混乱。
    【解决方案4】:

    如果你想直接从 Http 请求中获取表单数据,没有任何模型绑定或FormCollection,你可以使用这个:

    [HttpPost] 
    public ActionResult SubmitAction() {
    
        // This will return an string array of all keys in the form.
        // NOTE: you specify the keys in form by the name attributes e.g:
        // <input name="this is the key" value="some value" type="test" />
        var keys = Request.Form.AllKeys;
    
        // This will return the value for the keys.
        var value1 = Request.Form.Get(keys[0]);
        var value2 = Request.Form.Get(keys[1]);
    }
    

    【讨论】:

    • 请注意,这可能是错误的形式(没有双关语),但有时您只需要表单值而无法彻底更改函数签名。这是这里唯一适合我的特殊情况的解决方案。
    • 如何使用这些静态引用对该方法进行单元测试?在测试方面,FormCollection 会更受欢迎。
    • @KeesdeWit 如果您阅读了之前的评论,这不是最好的方法,但有时可以用作解决方法。要进行单元测试,您可能可以模拟 Request 并将其注入方法中。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-01-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多