【问题标题】:Passing Multiple Parameter Values via a Razor Page通过 Razor 页面传递多个参数值
【发布时间】: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 操作以处理具有需要两个值的复合键的实体?

谢谢!

【问题讨论】:

    标签: c# asp.net-core entity-framework-6 razor-pages asp.net-core-3.0


    【解决方案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 TinkerJeremy 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] 链接。
        • 除此之外,请务必将您的答案标记为已接受的答案,以便将您的问题标记为已回答。这将使未来的读者知道这个问题已经解决,并让他们轻松找到您认为最有用的解决方案。 (接受您自己的答案完全没问题;您不会因此获得任何 积分,但它仍会向读者传达解决您问题的方法。)
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2014-10-30
        • 2014-06-28
        • 2010-11-24
        • 2015-12-04
        • 1970-01-01
        • 2020-04-03
        • 1970-01-01
        相关资源
        最近更新 更多