如何从HTTPPOST,字典或检索表单值?


112

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

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

该表单是具有简单文本框的非平凡表单。

如何访问参数值?

我不是从View发布,而是从外部发布。我假设有一组我可以访问的键/值对。

我尝试过,Request.Params.Get("simpleTextBox");但返回错误“对不起,处理您的请求时出错。”。

Answers:


155

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

[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 ...
}

5
我只想指出,您在选项2中丢失了编译器的备份。如果模型发生更改,则编译器将无法捕获相关控制器中的更改。选项2有很好的案例,但我不鼓励广泛使用。
Serguei Fedorov'3

1
有时候您需要丑陋的东西,当您已经知道最佳实践是什么时,最好有一个选择
Oscar Ortiz

当仍在学习点网的人时,为什么第二种方法更难看?

3
@Goose,因为它是魔术弦。您没有任何编译时安全性。如果您在变量名称中输入错字,则代码将在运行时失败,而如果您使用强类型输入,则编译器将是您的朋友。
Darin Dimitrov

@DarinDimitrov很有道理。与我来自的世界不同。非常好用的功能。
Goose

104

简而言之,您可以这样使用FormCollection

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

您还可以使用与Form值映射的类,而asp.net mvc引擎自动填充该类:

//Defined in another file
class MyForm
{
  public string var1 { get; set; }
}

[HttpPost]
public ActionResult SubmitAction(MyForm form)
{      
  string var1 = form1.Var1;
}

我喜欢简单易用的课堂解决方案
Basheer AL-MOMANI

36

答案非常好,但是我真的很喜欢使用最新版本的MVC和.NET,而不是“老派”的FormCollection和Request键。


考虑一个包含在AJAX或FORM POST表单标签中的HTML代码段。

<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。但是,要求是这些定义的变量必须存在(除非为nullable(请记住,尽管可以string为null)),否则AJAX或POST back将失败。

[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 Engine)将截取表单变量“ variableName”(名称随心所欲,但保持一致),并尝试进行构建并将其转换为MyModel。

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

当控制器期望模型(在本例中为HomeModel)时,您不必定义所有字段,因为解析器只会将它们保留为默认值,通常为NULL。令人高兴的是,您可以在Mark-up上混合并匹配各种模型,并且将尽可能多地填充回发解析。您无需在页面上定义模型或使用任何帮助程序。

提示:控制器中参数的名称是HTML标记“ name =“中定义的名称,而不是模型名称,而是!中期望变量的名称。


使用List<>它的标记要复杂一些。

<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">

List <>上的索引必须始终基于零并且是连续的。0、1、2、3。

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

使用IEnumerable<>非零基和非循序索引后回来。我们需要添加额外的隐藏输入以帮助活页夹。

<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)
     { ... }
}

建议每页使用单个模型或ViewModel(包含其他模型的模型以创建复杂的“ View”模型)。提议的混合和匹配可能被认为是不好的作法,但只要可行且可读即可,而不是不良的。但是,它确实证明了Razor引擎的强大功能和灵活性。

因此,如果您需要随意添加一些东西或从Razor帮助程序中覆盖另一个值,或者只是不想自己创建帮助程序,则对于使用某些不寻常数据组合的单个表单,您可以快速使用这些方法来接受额外的数据数据。


使用索引选项是晦涩的。在上帝的绿色地球上,谁会知道会使用它甚至存在它?但是,很高兴我找到了这篇文章。这将节省大量的网络流量。
Michael Silver

1
这对我有用,但只有在我将<input type =“ hidden” id =“ myId”>更改为@ Html.Hidden(“ myId”)
radkan '17

@Piotr-请修复您与MyModel和MyHomes的引用不一致之处。当前情况令人困惑。
斯潘塞·沙利文

15

如果要直接从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]);
}

2
警告这可能是不好的形式(无双关语),但有时您只需要表单值,而不能干净地更改函数签名。这是这里唯一适合我特定情况的解决方案。
瑞安

如何用那些静态引用对该方法进行单元测试?进行测试时,FormCollection会更理想。
Kees de Wit

@KeesdeWit如果您阅读前面的评论,这不是最好的方法,但有时可以用作解决方法。要进行单元测试,可能可以模拟Request并将其注入到方法中。
A-Sharabiani
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.