ASP.NET MVC通过ActionLink传递模型

25

我希望在点击一个 ActionLink 后,能够将一个模型和一个 int 传递给控制器。

@Html.ActionLink("Next", "Lookup", "User", new { m = Model.UserLookupViewModel, page = Model.UserLookupViewModel.curPage }, null)

不起作用,相反地它会传递模型的空实例,这是使用 new 时预期的结果。

@Html.ActionLink("Next", "Lookup", "User", Model.UserLookupViewModel, null)

有效。

控制器

[HttpGet]
public ActionResult Lookup(UserLookupViewModel m, int page = 0)
{
    return this.DoLookup(m, page);
}

视图模型

public class UserLookupViewModel
{
    public int curPage { get; set; }

    [Display(Name = "Forenames")]
    public string Forenames { get; set; }

    [Display(Name = "Surname")]
    public string Surname { get; set; }

    [Display(Name = "DOB")]
    public DateTime? DoB { get; set; }

    [Display(Name = "Post code")]
    public string Postcode { get; set; }
}

我该如何同时传递它们呢?Lookup方法的参数与ActionLink中命名的属性匹配。


2
你不能使用ActionLink传递模型。 - Satpal
1
MVC4允许您通过URL变量自动传递模型,这在我的第二个示例中可以看到。 - Lee
1
ActionLink的文档显示,该方法的所有重载都不接受viewmodel对象。http://msdn.microsoft.com/en-us/library/system.web.mvc.html.linkextensions.actionlink(v=vs.118).aspx 您可以像第二个示例一样传递RouteValues,但不能传递整个对象。 - Jason Evans
1
假设视图模型的属性是由页面上的控件填充的,那么我只需提交一个表单,展示你的 Razor 代码。 - Maess
2
为什么你想使用ActionLink而不是提交表单? - Robert
显示剩余2条评论
4个回答

16

您无法使用ActionLink将属性传递给链接,但是您可以执行以下操作以获得相同的行为。

<form action="/url/to/action" Method="GET">
  <input type="hidden" name="Property" value="hello,world" />
  <button type="submit">Go To User</button>
</form>
如果您创建了一个辅助工具来生成这些GET表单,您将能够像普通链接按钮一样对它们进行样式设置。我唯一要警告的是页面上的所有表单都容易被修改,所以我不会信任数据。我宁愿在到达目的地时再次获取数据。

当我创建搜索操作并希望保留搜索历史记录并使后退按钮正常工作时,我使用上述技术。

希望对您有所帮助,

Khalid :)


P.S.

这个方法有效的原因。

@Html.ActionLink("Next", "Lookup", "User", Model.UserLookupViewModel, null)

之所以ActionLink方法的参数列表被泛化为接受一个对象,是因为它将接受任何东西。它将使用该对象传递给一个RouteValueDictionary,并尝试基于该对象的属性创建查询字符串。

如果你认为该方法已经起作用,你也可以尝试向视图模型添加一个名为Id的新属性,这样它将按你所期望的方式工作。


12

您需要将模型序列化为JSON字符串,并将其发送到控制器以转换为对象。

这是您的操作链接:

@Html.ActionLink("Next", "Lookup", "User", new { JSONModel = Json.Encode(Model.UserLookupViewModel), page = Model.UserLookupViewModel.curPage }, null)
在你的控制器中,你需要一个方法将你的JSON数据转换为MemoryStream:
private Stream GenerateStreamFromString(string s)
{
  MemoryStream stream = new MemoryStream();
  StreamWriter writer = new StreamWriter(stream);
  writer.Write(s);
  writer.Flush();
  stream.Position = 0;
  return stream;
}

在您的 ActionResult 中,您将 JSON 字符串转换为对象:

public ActionResult YourAction(string JSONModel, int page)
{
  DataContractJsonSerializer ser = new DataContractJsonSerializer(typeof(Model.UserLookupViewModel));
  var yourobject =  (UserLookupViewModel)ser.ReadObject(GenerateStreamFromString(JSONModel));
}

请不要在无法显示语言的情况下使用代码片段进行格式化。这并不能提高答案的质量,反而会使您的答案更加混乱。普通的代码块就可以很好地工作。 - Grice

4
虽然出于安全原因,我强烈建议您使用表单来完成您在此处尝试完成的任务。
 @Html.ActionLink("Next", "Lookup", "User", new 
      { Forenames = Model.UserLookupViewModel.Forenames, 
        Surname = Model.UserLookupViewModel.Surname, 
        DOB = Model.UserLookupViewModel.DOB,  
        PostCode = Model.UserLookupViewModel.PostCode, 
        page = Model.UserLookupViewModel.curPage }, null)

MVC会自动将属性映射到相应位置;但是,这将使用您的URL将值传递给控制器。这将公开所有人都可以看到的值。

出于安全考虑,我强烈建议使用表单,特别是在处理敏感数据(如DOB)时。

个人而言,我会这样做:

 @using (Html.BeginForm("Lookup", "User")
 {
     @Html.HiddenFor(x => x.Forenames)
     @Html.HiddenFor(x => x.Surname)
     @Html.HiddenFor(x => x.DOB)
     @Html.HiddenFor(x => x.PostCode)
     @Html.HiddenFor(x => x.curPage)

     <input type="submit" value="Next" />
  }

如果需要,您可以在页面上拥有多个此类型的表单。

然后,您的控制器接受一个提交,但功能相同:

 [HttpPost]
 public ActionResult Lookup(UserLookupViewModel m, int page = 0)
 {
     return this.DoLookup(m, page);
 }

1
抱歉,HiddenFor并不安全。它仍然会将数据发送到页面供用户查看,虽然在页面上不可见,但在源代码中可以看到。 - Worthy7
如果没有“安全”提示,这个答案会是一个不错的补充,因为它是唯一使用 Html.BeginFormHtml.HiddenFor 的答案。 - Jack Miller

0
请尝试这个解决方案:
@{
var routeValueDictionary = new RouteValueDictionary("");
routeValueDictionary.Add("Forenames",Forenames);
routeValueDictionary.Add("Surname",Surname);
routeValueDictionary.Add("DoB ",DoB );
routeValueDictionary.Add("Postcode",Postcode );
routeValueDictionary.Add("Page",PageNum );
// Add any item you want!
}
@html.ActionLink("LinkName", "ActionName", "ControllerName",
routeValueDictionary , new{@class="form-control"})

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接