通过 Razor 页面传递多个参数值

Posted

技术标签:

【中文标题】通过 Razor 页面传递多个参数值【英文标题】:Passing Multiple Parameter Values via a Razor Page 【发布时间】:2020-04-21 12:27:51 【问题描述】:

我正在尝试使用 ASP.NET Core 3.0 和 Entity Framework 6 对 Razor 页面上具有复合键的实体进行删除操作。有问题的实体是 CourseAssignment,其复合键由InstructorID 值和 CourseID 值。

对于具有普通单字段键的实体(例如,具有 CourseID 主键的 Course 实体),剃刀页面上的代码如下:

<form method="post">
  <input type="hidden" asp-for="Course.CourseID" />
  <input type="submit" value="Delete" class="btn btn-danger" /> |
  <a asp-page="./Index">Back to List</a>
</form>

生成这样的 URL: https://localhost:44388/Courses/Delete?id=1045

作用于此的 C# 代码是:

public async Task<IActionResult> OnPostAsync(int? id) 

  if (id == null) 
    return NotFound();
  

  Course = await _context.Courses.FindAsync(id);

  if (Course != null) 
    _context.Courses.Remove(Course);
    await _context.SaveChangesAsync();
  

  return RedirectToPage("./Index");


如何更改 razor 页面和 C# OnPostAsync 操作以处理具有需要两个值的复合键的实体?

谢谢!

【问题讨论】:

【参考方案1】:

您可以通过添加额外的隐藏字段来传递表单中的多个值。因此,假设您的复合主键中的辅助字段是Course.Instructor;在这种情况下,您可以添加:

<input type="hidden" asp-for="Course.Instructor" />

然后,您可以扩展 OnPostAsync() 操作的签名以包含该字段:

public async Task<IActionResult> OnPostAsync(int? id, string instructor)  … 

注意:如果您使用 C# 8.0 的可空注释上下文,那么您可能需要 string? 作为参数类型。

此时,您应该可以将值作为第二个参数传递给FindAsync()

Course = await _context.Courses.FindAsync(id, instructor);

注意:这是可行的,因为FindAsync() 方法接受与主键约束相对应的params Object[] keyValues

显然,您需要确认为隐藏字段生成的name 与您的操作参数名称匹配,或者提供绑定提示。

【讨论】:

【参考方案2】:

将您的 html 表单更新为如下内容:

<form method="post">
    <input type="hidden" asp-for="Course.CourseID" />
    <input type="hidden" asp-for="Course.InstructorID" />
    <input type="submit" value="Delete" class="btn btn-danger" /> |
    <a asp-page="./Index">Back to List</a>
</form>

创建一个新类来处理复合键。您也可以使用现有的视图模型类。

public class DeleteCourseRequest 
  public int CourseId  get; set; 
  public int InstructorId  get; set; 

然后将控制器的 OnPostAsync 操作更新为如下内容:

public async Task<IActionResult> OnPostAsync(DeleteCourseRequest request) 
  if (request == null) 
    return NotFound();
  

  Course = await _context.Courses.FirstOrDefaultAsync(c => c.CourseID == request.CourseID && c.InstructorID == request.InstructorID);

  if (Course != null) 
    _context.Courses.Remove(Course);
    await _context.SaveChangesAsync();
  

  return RedirectToPage("./Index");

问题在于,当使用多个参数执行 Post 时,您必须在参数上使用 [FromBody][FromUri] 绑定。这告诉 ASP.NET Web API 在哪里解析参数。另一种选择是使用视图模型将信息从表单传递到控制器。

【讨论】:

【参考方案3】:

好吧,碰巧,我的问题出在Index.cshtml 的 POST 代码中,它调用删除页面,而不是在 的 POST 代码中删除页面本身。在Delete.cshtml.cs 页面的OnGetAsync() 方法中也存在一个问题,而不是它的OnPostAsnc() 方法(尽管也必须调整它以接受两个参数)。

通过Cameron Tinker 和Jeremy Caney 答案中提供的提示,我明白了。 非复合主键的实体的删除页面链接如下所示:

 <a asp-page="./Delete" asp-route-id="@item.CourseID">Delete</a>-->

对于具有复合键的实体,它需要看起来像这样:

<a asp-page="./Delete" asp-route-courseID="@item.CourseID" asp-route-instructorID="@item.InstructorID">Delete</a>

asp-route 助手的最后一部分是要传递的参数的名称。 (除了 Razor 页面本身的清晰度之外,这可能无关紧要,如果您只是传递一个常量作为值,而不是像我正在做的那样传递命名属性的值,这将是一个问题。)

作用于此的C#代码在被调用页面的OnGetAsync()方法Delete.cshtml.cs中:

public async Task<IActionResult> OnGetAsync(int? courseID, int? instructorID) 
  if (courseID == null || instructorID == null) 
    return NotFound();
  

  CourseAssignment = await _context.CourseAssignments
      .AsNoTracking()
      .Include(c => c.Course)
      .Include(c => c.Instructor)
      .FirstOrDefaultAsync(m => m.CourseID == courseID && m.InstructorID == instructorID);

  if (CourseAssignment == null) 
    return NotFound();
  
  return Page();

【讨论】:

很高兴听到您弄明白了。如果您不需要 [post],请使用标签助手语法构造 [get] 链接。 除此之外,请务必将您的答案标记为已接受的答案,以便将您的问题标记为已回答。这将使未来的读者知道这个问题已经解决,并让他们轻松找到您认为最有用的解决方案。 (接受您自己的答案完全没问题;您不会因此获得任何 积分,但它仍会向读者传达解决您问题的方法。)

以上是关于通过 Razor 页面传递多个参数值的主要内容,如果未能解决你的问题,请参考以下文章

到基础 Razor 页面的多个别名路由

在 MVC/Razor 中,如何获取多个复选框的值并将它们全部传递给控制器​​?

在单个参数中传递多个值

在 .Net Core razor 页面中传递路由参数

MVC Razor 隐藏输入和传递值

在绑定参数中传递了多个值