我正在关注Microsoft Contoso University Tutorial学习MVC。
到目前为止,我已经创建了3个模型
我有2个控制器
我可以查看学生列表,有关学生的详细信息,包括课程中的内容和成绩,编辑学生详细信息以及添加新学生。
此时,我想了解更多有关路由的信息,因为我使用的是默认的Map Route
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
我有一个学生数据库,都有唯一的姓氏。我知道通常不建议这样做,因为姓氏不是唯一的,但它适用于这个小型学习项目。所以我想要实现的是能够输入/students/{action}/{lastname}
并查看有关学生的详细信息。所以我在学生控制器中创建了一个新的动作方法。
public ActionResult Grab(string studentName)
{
if (studentName == null)
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
var student = db.Students.FirstOrDefault(x => x.LastName.ToLower() == studentName.ToLower());
if (student == null)
return HttpNotFound();
return View(student);
}
我在RouteConfig.cs文件中添加了一个新路由
//Custom route
routes.MapRoute(
name: null,
url: "{controller}/{action}/{studentName}",
defaults: new { controller = "Student", action = "Grab", id = UrlParameter.Optional }
);
最后我创建了一个名为Grab的新视图,其中显示了有关该学生的详细信息。
现在当我输入/student/grab/Norman
时,它会向我提供姓氏为Norman的学生的详细信息
这很棒。但现在我有一个问题。当我尝试使用我的一些原始网址时/Student/Details/1
他们不再工作了。我收到400错误。
我做的第一件事就是将我的默认路线移到我制作的自定义路线之上
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
//Custom route
routes.MapRoute(
name: null,
url: "{controller}/{action}/{studentName}",
defaults: new { controller = "Student", action = "Grab", id = UrlParameter.Optional }
);
这解决了这个问题,但在我之前工作的抓取路线上导致400错误。如何在不收到400错误的情况下同时使用这两个?
这是我的完整RouteConfig.cs文件
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using System.Web.Routing;
namespace ContosoUniversity
{
public class RouteConfig
{
public static void RegisterRoutes(RouteCollection routes)
{
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
//Custom route
routes.MapRoute(
name: null,
url: "{controller}/{action}/{studentName}",
defaults: new { controller = "Student", action = "Grab", id = UrlParameter.Optional }
);
}
}
}
这是我的整个StudentController.cs文件
using System;
using System.Collections.Generic;
using System.Data;
using System.Data.Entity;
using System.Linq;
using System.Net;
using System.Web;
using System.Web.Mvc;
using ContosoUniversity.DAL;
using ContosoUniversity.Models;
namespace ContosoUniversity.Controllers
{
public class StudentController : Controller
{
private SchoolContext db = new SchoolContext();
// GET: Student
public ActionResult Index()
{
return View(db.Students.ToList());
}
// GET: Student/Details/5
public ActionResult Details(int? id)
{
if (id == null)
{
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
}
Student student = db.Students.Find(id);
if (student == null)
{
return HttpNotFound();
}
return View(student);
}
public ActionResult Grab(string studentName)
{
if (studentName == null)
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
var student = db.Students.FirstOrDefault(x => x.LastName.ToLower() == studentName.ToLower());
if (student == null)
return HttpNotFound();
return View(student);
}
// GET: Student/Create
public ActionResult Create()
{
return View();
}
// POST: Student/Create
// To protect from overposting attacks, please enable the specific properties you want to bind to, for
// more details see http://go.microsoft.com/fwlink/?LinkId=317598.
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Create([Bind(Include = "LastName, FirstMidName, EnrollmentDate")]Student student)
{
try
{
if (ModelState.IsValid)
{
db.Students.Add(student);
db.SaveChanges();
return RedirectToAction("Index");
}
}
catch (DataException /* dex */)
{
//Log the error (uncomment dex variable name and add a line here to write a log.
ModelState.AddModelError("", "Unable to save changes. Try again, and if the problem persists see your system administrator.");
}
return View(student);
}
// GET: Student/Edit/5
public ActionResult Edit(int? id)
{
if (id == null)
{
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
}
Student student = db.Students.Find(id);
if (student == null)
{
return HttpNotFound();
}
return View(student);
}
// POST: Student/Edit/5
// To protect from overposting attacks, please enable the specific properties you want to bind to, for
// more details see http://go.microsoft.com/fwlink/?LinkId=317598.
[HttpPost, ActionName("Edit")]
[ValidateAntiForgeryToken]
public ActionResult EditPost(int? id)
{
if (id == null)
{
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
}
var studentToUpdate = db.Students.Find(id);
if (TryUpdateModel(studentToUpdate, "",
new string[] { "LastName", "FirstMidName", "EnrollmentDate" }))
{
try
{
db.SaveChanges();
return RedirectToAction("Index");
}
catch (DataException /* dex */)
{
//Log the error (uncomment dex variable name and add a line here to write a log.
ModelState.AddModelError("", "Unable to save changes. Try again, and if the problem persists, see your system administrator.");
}
}
return View(studentToUpdate);
}
// GET: Student/Delete/5
public ActionResult Delete(int? id)
{
if (id == null)
{
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
}
Student student = db.Students.Find(id);
if (student == null)
{
return HttpNotFound();
}
return View(student);
}
// POST: Student/Delete/5
[HttpPost, ActionName("Delete")]
[ValidateAntiForgeryToken]
public ActionResult DeleteConfirmed(int id)
{
Student student = db.Students.Find(id);
db.Students.Remove(student);
db.SaveChanges();
return RedirectToAction("Index");
}
protected override void Dispose(bool disposing)
{
if (disposing)
{
db.Dispose();
}
base.Dispose(disposing);
}
}
}
我将提供所需的任何其他详细信息。我希望能够输入http://localhost:49706/Student/Details/1
或http://localhost:49706/Student/Grab/Alexander
并获得相同的详细信息,因为Alexander的学生ID为1。
答案 0 :(得分:1)
您希望区分自定义路由与默认路由网址
public static void RegisterRoutes(RouteCollection routes) {
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
//Custom route
routes.MapRoute(
name: "Students",
url: "Student/{action}/{id}",
defaults: new { controller = "Student", action = "Grab", id = UrlParameter.Optional }
);
//General default route
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
}
动作参数也应与路径模板参数匹配
// GET: Student/Details/5
public ActionResult Details(int? id) {
if (id == null) {
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
}
var student = db.Students.Find(id);
if (student == null) {
return HttpNotFound();
}
return View(student);
}
public ActionResult Grab(string id) {
if (id == null)
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
var student = db.Students.FirstOrDefault(x => x.LastName.ToLower() == id.ToLower());
if (student == null)
return HttpNotFound();
return View(student);
}
现在可以使以下内容正确匹配
Student/Details/1
Student/Grab/Alexander
为姓名为Alexander的学生提供1岁的studentId
答案 1 :(得分:1)
两条路线都是相同的(从模式匹配的角度来看):
{controller}/{action}/{id}
{controller}/{action}/{studentName}
id
和studentName
只是占位符。除此之外,它们没有任何意义,因此您基本上只定义了两条路线:
{controller}/{action}/{someindicator}
最终发生的事情是,首先命中的任何路线都将满足请求。
因此,如果你想使用相同的“模式”,你需要以某种方式区分路线。我建议直接在路线中指明行动:
routes.MapRoute(
name: "StudentDetails",
url: "{controller}/Details/{id}",
defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
);
//Custom route
routes.MapRoute(
name: "GrabStudent",
url: "{controller}/Grab/{studentName}",
defaults: new { controller = "Student", action = "Grab", id = UrlParameter.Optional }
);