Trong chương này, tôi sẽ chỉ cho bạn cách sử dụng hệ thống định tuyến để tạo ra sự mạnh mẽ và linh hoạt trong xử lý URL cho các dự án của bạn.. Trong chương này, tôi sẽ tập trung vào việ
Trang 1CHAPTER 15
URL Routing
Trước khi giới thiệu MVC Framework, ASP.NET đã giả định rằng có một mối quan hệ trực tiếp giữa các URL được yêu cầu và các tập tin trên đĩa cứng của máy chủ Công việc của các máy chủ là nhận yêu cầu từ trình duyệt và cung cấp những đầu ra từ các tập tin tương ứng
Cách tiếp cận này chỉ làm tốt ở các Web Form, trong đó mỗi trang ASPX là cả một tập tin và một phản hồi khép kín đến một yêu cầu Nó không có ý nghĩa đối với một ứng dụng MVC, nơi yêu cầu được xử lý bằng phương thức action trong lớp controller và không có
sự tương quan one-to-one với các tập tin trên đĩa
Để xử lý các URL MVC, nền tảng ASP.NET sử dụng hệ thống định tuyến Trong chương này, tôi sẽ chỉ cho bạn cách sử dụng hệ thống định tuyến để tạo ra sự mạnh mẽ và linh hoạt trong xử lý URL cho các dự án của bạn Như bạn sẽ thấy, các hệ thống định tuyến cho phép bạn tạo ra bất kỳ mô hình của các URL mà bạn mong muốn và diễn đạt chúng một cách rõ ràng và súc tích Các hệ thống định tuyến có hai chức năng:
Kiểm tra URL gọi đến và tìm ra controller và action nào yêu cầu được chỉ định
Tạo URL gửi đi Đây là các URL xuất hiện trong HTML được biểu diễn từ các View để một action cụ thể sẽ được gọi khi người dùng nhấp chuột vào liên kết (tại thời điểm đó, nó đã trở thành một URL đến một lần nữa)
Trong chương này, tôi sẽ tập trung vào việc xác định các định tuyến và sử dụng chúng
để xử lý các URL đến để người dùng có thể tiếp cận với các bộ điều khiển và hành động của bạn Có hai cách để tạo ra các định tuyến trong một ứng dụng MVC Framework: ước dựa trên định tuyến và thuộc tính định tuyến Bạn sẽ được làm quen với quy ước dựa trên định tuyến nếu bạn đã sử dụng phiên bản trước của MVC Framework, nhưng thuộc tính định tuyến mới để MVC 5 Tôi giải thích cả hai phương pháp trong chương này
Sau đó, trong các chương tiếp theo, tôi sẽ cho bạn thấy làm thế nào để sử dụng các định tuyến tương tự để tạo ra các URL đi bạn sẽ cần đưa vào quan điểm của bạn, cũng như cho bạn thấy làm thế nào để tùy chỉnh hệ thống định tuyến và sử dụng một tính năng liên quan gọi là khu vực Bảng 15-1 cung cấp bản tóm tắt cho chương này
Trang 2Chuẩn bị một ví dụ
Để chứng minh các hệ thống định tuyến, tôi cần một dự án mà tôi có thể thêm các định tuyến Tôi tạo ra một ứng dụng MVC mới bằng cách sử dụng the Empty template, và tôi gọi là dự án UrlsAndRoutes Tôi đã thêm một dự án thử nghiệm đển the Visual Studio solution được gọi là UrlsAndRoutes Thử nghiệm bằng cách kiểm tra các tùy chọn the Add Unit Tests, như thể hiện trong hình 15-1
Trang 3Hình 15-1 Tạo một dự án ứng dụng MVC Empty với các kỹ thuật kiểm nghiệm
Tôi chỉ cho bạn làm thế nào để tạo ra các kỹ thuật kiểm nghiệm bằng tay cho các chương SportsStore, nhưng điều này tạo ra kết quả và xử lý các tham chiếu giữa các dự án
tự động thì tương tự Bạn vẫn sẽ cần thêm Moq, và do đó, nhập vào lệnh sau đây trong giao diện điều khiển NuGet:
Install-Package Moq -version 4.1.1309.1617 -projectname
UrlsAndRoutes.Tests
Tạo các Controllers Ví dụ:
Để chứng minh tính năng định tuyến, tôi sẽ thêm một số controller đơn giản vào ứng dụng
ví dụ này Tôi chỉ quan tâm đến cách thức mà các URL được diễn giải để gọi các phương thức action, do đó, các mô hình view tôi sử dụng là giá trị chuỗi trong view bag có gọi controller và tên phương thức action Đầu tiên, tạo một Home controller và thiết lập nội dung của nó để phù hợp với những thứ trong Liệt kê 15-1
Bảng liệt kê 15-1 Nội dung của tập tin HomeController.cs
Trang 4namespace UrlsAndRoutes.Controllers { public
class CustomerController : Controller {
public ActionResult Index() {
Trang 5Bảng liệt kê 15-3 Nội dung của tập tin AdminController.cs
using System.Web.Mvc;
namespace UrlsAndRoutes.Controllers {
public class AdminController : Controller {
public ActionResult Index() {
ActionName.cshtml vào nó, thiết lập các nội dung của quan điểm để phù hợp với Liệt kê 15-4
Bảng liệt kê 15-4 Nội dung của File ActionName.cshtml
<div>The controller is: @ViewBag.Controller</div>
<div>The action is: @ViewBag.Action</div>
</body>
</html>
Trang 6Thiết lập các URL bắt đầu và kiểm thử các ứng dụng
Như tôi đã giải thích trong phần 1 trong cuốn sách này, Visual Studio sẽ cố gắng tìm ra các URL mà bạn muốn trình duyệt yêu cầu dựa trên các tập tin bạn đang chỉnh sửa khi bạn bắt đầu debugger Đây là một ý tưởng tốt mà nhanh chóng trở nên khó chịu và là một tính năng
mà tôi luôn luôn vô hiệu hóa Chọn UrlsAndRoutes Properties từ menu Project Studio Visual, chuyển sang tab Web và kiểm tra các tùy chọn Specific Page trong phần Start Action Bạn không cần phải cung cấp một giá trị chỉ kiểm tra các tùy chọn là đủ Nếu bạn bắt đầu ứng dụng ví dụ, bạn sẽ thấy câu trả lời thể hiện trong hình 15-2
Hình 15-2 Chạy các ứng dụng ví dụ
Giới thiệu Mẫu URL
Các hệ thống định tuyến làm nó kỳ diệu bằng cách sử dụng một tập hợp các định tuyến Những bộ định tuyến đó bao gồm các lược đồ URL hoặc lược đồ cho một ứng dụng, trong
đó là tập hợp các URL mà ứng dụng của bạn sẽ nhận ra và đáp ứng
Tôi không cần phải tự loại ra tất cả các URL riêng biệt tôi sẵn sàng để hỗ trợ trong các ứng dụng của tôi Thay vào đó, mỗi định tuyến có chứa một mẫu URL, được so sánh với các URL đến Nếu một URL phù hợp với mô hình, sau đó nó được sử dụng bởi các hệ thống định tuyến để xử lý URL đó Hãy bắt đầu với một URL cho các ứng dụng ví dụ: http://mysite.com/Admin/Index
URL có thể được chia thành phân đoạn Đây là những bộ phận của URL, không bao gồm hostname và chuỗi truy vấn, được phân cách bởi các ký tự / Trong URL ví dụ, có hai phân đoạn, như thể hiện trong hình 15-3
Hình 15-3 Những đoạn trong một URL ví dụ
Trang 7Phân đoạn đầu tiên chứa từ Admin, và phân đoạn thứ hai chứa từ Index Tinh mắt hơn,
rõ ràng là phân đoạn đầu tiên liên quan đến controller và phân đoạn thứ hai liên quan đến action Nhưng, tất nhiên, tôi cần phải thể hiện mối quan hệ này trong một cách mà các hệ thống định tuyến có thể hiểu được Dưới đây là một mẫu URL mà thực hiện điều này: {controller}/{action}
Khi xử lý một yêu cầu gửi đến, công việc của các hệ thống định tuyến là kết hợp các URL đã được yêu cầu đến một mô hình và giải nén các giá trị từ các URL cho các biến mảng được xác định trong mô hình Các biến mảng được biểu diễn bằng cách sử dụng dấu ngoặc (các ký tự { và } ) Các mẫu ví dụ có hai biến mảng với tên controller và action, và
do đó giá trị của biến mảng controller sẽ là Admin và các giá trị của biến mảng action sẽ
là Index
Tôi nói phù hợp với một mô hình, vì một ứng dụng MVC thường sẽ có một số định tuyến và hệ thống định tuyến sẽ so sánh URL gọi đến đến các mẫu URL của từng định tuyến cho đến khi nó tìm thấy một sự phù hợp
Lưu ý Các hệ thống định tuyến không có bất kỳ kiến thức đặc biệt của các controller
và action Nó chỉ trích các giá trị cho các biến mảng Đó là sau này trong quá trình giải quyết yêu cầu, khi yêu cầu đến được MVC Framework thích hợp, có nghĩa là được gán cho các biến số controller và action Đây là lý do tại sao các hệ thống định tuyến có thể được sử dụng với Web Forms và các API Web (Tôi giới thiệu các API Web trong Chương
27 và tôi mô tả các yêu cầu quá trình xử lý ASP.NET trong chi tiết trong cuốn sách Pro ASP.NET MVC 5 Platform của tôi.)
Theo mặc định, một mẫu URL sẽ phù hợp với bất kỳ URL mà có số lượng chính xác của phân đoạn Ví dụ, mô hình {controller} / {action} sẽ phù hợp với bất kỳ URL mà có hai phân đoạn, được minh họa bằng Bảng 15-2
Bảng 15-2 URL Phù hợp
http://mysite.com/Admin/Index controller = Adminaction =
Index http://mysite.com/Index/Admin controller = Indexaction =
Admin http://mysite.com/Apples/Oranges controller = Applesaction =
Oranges http://mysite.com/Admin No match—too few segments
http://mysite.com/Admin/Index/Soccer No match—too many segments
Bảng 15-2 nhấn mạnh hai hành vi quan trọng của các mẫu URL:
Trang 8 Mô hình URL rất bảo thủ, và chỉ sẽ phù hợp với URL có cùng số phân đoạn như mô hình Bạn có thể thấy điều này trong các ví dụ thứ tư và thứ năm trong bảng
Mô hình URL là tự do Nếu một URL không có con số chính xác của phân đoạn,
mô hình sẽ trích xuất các giá trị cho các biến mảng, bất cứ điều gì có thể được Đây là những hành vi mặc định, trong đó là chìa khóa để hiểu được như thế nào là Mô hình URL chức năng Tôi chỉ cho bạn làm thế nào để thay đổi mặc định sau trong chương này
Như đã đề cập, các hệ thống định tuyến không biết bất cứ điều gì về một ứng dụng MVC, và do đó Mô hình URL sẽ phù hợp ngay cả khi không có controllerhoặc action tương ứng với giá trị chiết xuất từ một URL Bạn có thể thấy điều này được chứng minh trong ví dụ thứ hai trong Bảng 15-2 Tôi hoán Admin và phân đoạn Index trong URL, và
do đó, các giá trị chiết xuất từ các URL cũng đã được hoán đổi, mặc dù không có controller Index trong dự án ví dụ
Tạo và Đăng ký Định tuyến đơn giản
Một khi bạn có một mẫu URL trong tâm trí, bạn có thể sử dụng nó để xác định một định tuyến Định tuyến được định nghĩa trong file RouteConfig.cs, đó là trong thư mục dự án App_Start Bạn có thể xem các nội dung ban đầu mà Visual Studio xác định cho tập tin này trong Liệt kê 15-5
Bảng liệt kê 15-5 Nội dung mặc định của tập tin RouteConfig.cs
Trang 9Phương thức RegisterRoutes tĩnh được định nghĩa trong file RouteConfig.cs được gọi
là từ các tập tin Global.asax.cs, trong đó thiết lập một số các tính năng cốt lõi MVC khi ứng dụng được bắt đầu chạy Bạn có thể xem nội dung mặc định của tập tin Global.asax.cs trong Liệt kê 15-6, và tôi đã làm nổi bật lời gọi đến phương thức RouteConfig.RegisterRoutes, được làm từ các phương thức Application_Start
Bảng liệt kê 15-6 Nội dung mặc định của File Global.asax.cs
public class MvcApplication : System.Web.HttpApplication { protected
void Application_Start() { AreaRegistration.RegisterAllAreas();
tả ngay
Trang 10Bảng liệt kê 15-7 cho thấy làm thế nào để tạo ra một định tuyến sử dụng các mẫu ví
dụ URL từ phần trước trong phương thức RegisterRoutes của tập tin RouteConfig.cs (Tôi
đã gỡ bỏ các báo cáo khác trong phương thức này để tôi có thể tập trung vào các ví dụ.)
Bảng liệt kê 15-7 Đăng ký một Route trong RouteConfig.cs file
public static void RegisterRoutes(RouteCollection routes) { Route myRoute
= new Route("{controller}/{action}", new MvcRouteHandler());
vi định tuyến, và đây là các lớp được sử dụng cho các ứng dụng ASP.NET MVC Một khi tôi đã tạo ra các định tuyến, tôi thêm vào các đối tượng RouteCollection sử dụng phương thức Add, truyền vào tên tôi muốn route được biết đến bởi các định tuyến của chính nó
Mẹo: đặt tên định tuyến của bạn là không bắt buộc và có một cuộc tranh luận triết học
mà làm như vậy sẽ hi sinh một số phân chia ngắn gọn của các mối lo ngại mà nếu không xuất phát từ định tuyến Tôi thoải mái về việc đặt tên, nhưng tôi sẽ giải thích tại sao điều này có thể là một vấn đề trong các "Tạo ra một URL từ một cụ Route" trong Chương 16 Một cách thuận tiện hơn trong việc đăng ký các định tuyến là sử dụng phương thức MapRoute xác định bởi lớp RouteCollection Liệt kê 15-8 cho thấy làm thế nào tôi có thể
sử dụng phương pháp này để đăng ký một định tuyến, trong đó có tác dụng tương tự như
ví dụ trước, nhưng có một cú pháp ngắn gọn hơn
Trang 11Bảng liệt kê 15-8 Đăng ký một Route Sử dụng phương thức MapRoute trong RouteConfig.cs file
có thể sử dụng phương thức MapPageRoute, cũng được định nghĩa trong lớp RouteCollection
Sử dụng các Route đơn giản
Bạn có thể xem hiệu quả của những thay đổi tôi thực hiện cho định tuyến bằng cách khởi động ứng dụng ví dụ Bạn sẽ thấy một lỗi khi trình duyệt cố gắng điều hướng đến các URL gốc cho ứng dụng, nhưng nếu bạn điều hướng đến một định tuyến phù hợp với {controller} / {action} mô hình, bạn sẽ thấy một kết quả giống như thể hiện trong hình 15 -4, minh họa ảnh hưởng của điều hướng đến / Admin / Index
Trang 12Hình 15-4 Điều hướng bằng một con đường đơn giản
Route đơn giản của tôi trong Liệt kê 15-8 không nói MVC Framework đến cách đáp ứng yêu cầu cho các URL gốc như thế nào và chỉ hỗ trợ đơn lẻ, cụ thể, mẫu URL Tôi đã tạm thời đưa một bước trở lại từ các chức năng mà Visual Studio thêm vào các tập tin RouteConfig.cs khi nó tạo ra dự án, nhưng tôi sẽ cho bạn thấy làm thế nào để xây dựng các
mô hình phức tạp hơn và các định tuyến trong suốt phần còn lại của chương này
Tôi đã tạm thời đưa một bước lùi lại từ các chức năng mà Visual Studio thêm vào các tập tin RouteConfig.cs khi nó tạo ra dự án, nhưng tôi sẽ cho bạn thấy làm thế nào để xây dựng các mô hình và các định tuyến phức tạp hơn trong suốt phần còn lại của chương này
UNIT TEST: Thử nghiệm các URL gửi đến
Tôi khuyên bạn nên kiểm tra đơn vị định tuyến của bạn để chắc chắn rằng họ xử lý các URL gửi đến như mong đợi, thậm chí nếu bạn không chọn đến đơn vị kiểm tra phần còn lại của ứng dụng của bạn Các schema URL có thể trở nên khá phức tạp trong các ứng dụng lớn, và nó rất dễ dàng để tạo ra một kết quả bất ngờ
Trong chương trước, tôi đã tránh tạo ra phương thức hổ trợ phổ biến để được chia sẻ giữa các thử nghiệm để giữ cho mỗi đơn vị thử nghiệm mô tả khép kín Trong chương này, tôi đang tiếp cận khác nhau Kiểm tra sơ đồ định tuyến cho một ứng dụng thì làm
dễ dàng nhất khi bạn có thể trộn một số thử nghiệm trong một phương thức duy nhất,
và đây trở nên dễ dàng hơn nhiều với một số phương thức hỗ trợ
Để kiểm tra các định tuyến, tôi cần phải thử ba lớp từ MVC Framework:
HttpRequestBase, HttpContextBase, và HttpResponseBase (Lớp cuối cùng này là cần
thiết để kiểm tra các URL gửi đi, mà tôi giới thiệu trong chương tiếp theo.) Dù sao, các lớp này tạo đủ cơ sở hạ tầng MVC để hỗ trợ hệ thống định tuyến Tôi đã thêm một file
mới đơn vị thử nghiệm được gọi là RouteTests.cs để các dự án thử nghiệm UrlsAndRoutes.Các đơn vị thử nghiệm kiểm tra dự án và bổ sung đầu tiên của tôi là các phương thức trợ giúp tạo ra các đối tượng HttpContextBase giả, như sau:
Trang 13using Microsoft.VisualStudio.TestTools.UnitTesting;
using Moq; using System; using System.Reflection;
using System.Web; using System.Web.Routing;
namespace UrlsAndRoutes.Tests {
[TestClass]
public class
RouteTests {
private HttpContextBase CreateHttpContext(string targetUrl = null,
string httpMethod = "GET") {
// create the mock request
Mock<HttpRequestBase> mockRequest = new Mock<HttpRequestBase>(); mockRequest.Setup(m => m.AppRelativeCurrentExecutionFilePath)
Returns(targetUrl);
mockRequest.Setup(m => m.HttpMethod).Returns(httpMethod);
// create the mock response
Mock<HttpResponseBase> mockResponse = new
Mock<HttpResponseBase>
();
mockResponse.Setup(m => m.ApplyAppPathModifier(
It.IsAny<string>())).Returns<string>(s => s);
// create the mock context, using the request and response
Mock<HttpContextBase> mockContext = new Mock<HttpContextBase>(); mockContext.Setup(m => m.Request).Returns(mockRequest.Object);
theo của tôi cho phép tôi thử nghiệm một định tuyến:
private void TestRouteMatch(string url, string controller, string action,
Trang 14object routeProperties = null, string httpMethod = "GET") {
Các tham số của phương thức này cho phép tôi chỉ định URL để kiểm tra, giá trị dự
kiến cho controller và action biến mảng, và một đối tượng có chứa các giá trị dự kiến
cho bất kỳ biến số bổ sung tôi đã xác định Tôi sẽ chỉ cho bạn cách để tạo ra các biến như sau trong chương này và trong các chương tiếp theo Tôi cũng xác định một tham
số cho phương thức HTTP, mà tôi sẽ giải thích trong phần "Ràng buộc định tuyến " Phương thức TestRouteMatch dựa vào một phương thức khác,
TestIncomingRouteResult, để so sánh các kết quả thu được từ hệ thống định tuyến với
các giá trị biến mảng mà tôi mong đợi Phương thức này sử dụng NET phản ánh để tôi
có thể sử dụng một loại nặc danh để trình bày bất kỳ biến mảng bổ sung Đừng lo lắng nếu phương thức này không có ý nghĩa, vì đây chỉ là để làm cho thử nghiệm thuận tiện hơn; nó không phải là một yêu cầu cho sự tìm hiểu MVC Đây là phương pháp
TestIncomingRouteResult:
private bool TestIncomingRouteResult(RouteData routeResult, string
controller, string action, object propertySet = null) {
Func<object, object, bool> valCompare = (v1, v2) => {
return StringComparer.InvariantCultureIgnoreCase
Compare(v1, v2) == 0;
};
Trang 15bool result = valCompare(routeResult.Values["controller"], controller)
&& valCompare(routeResult.Values["action"], action);
if (propertySet != null) {
PropertyInfo[] propInfo = propertySet.GetType().GetProperties();
foreach (PropertyInfo pi in propInfo) { if
// Act - process the route
RouteData result = routes.GetRouteData(CreateHttpContext(url));
// Assert
Assert.IsTrue(result == null || result.Route == null); }
TestRouteMatch và TestRouteFail chứa các lệnh gọi đến các phương thức Assert, mà
chuyển vào một ngoại lệ nếu khẳng định thất bại Bởi vì trường hợp ngoại lệ trong C
# được truyền lên các lệnh gọi stack, tôi có thể tạo ra phương thức thử nghiệm đơn giản để thử nghiệm một tập hợp các URL và nhận được những hành vi kiểm thử tôi yêu cầu Dưới đây là một phương thức kiểm thử định tuyến mà tôi định nghĩa trong
Liệt kê 15-8:
Trang 16
[TestMethod]
public void TestIncomingRoutes() {
// check for the URL that is hoped for
TestRouteMatch("∼/Admin/Index", "Admin", "Index");
// check that the values are being obtained from the segments
TestRouteMatch("∼/One/Two", "One", "Two");
// ensure that too many or too few segments fails to match
Kiểm thử này sử dụng các phương thức TestRouteMatch để kiểm tra các URL Tôi đang
mong đợi và cũng kiểm tra một URL trong các dạng tương tự để đảm bảo rằng các giá
trị controller và action đang nhận được cách sử dụng thích hợp phân đoạn URL Tôi
sử dụng phương thức TestRouteFail để đảm bảo rằng các ứng dụng sẽ không chấp
nhận các URL có một số lượng khác nhau của phân đoạn Khi kiểm thử , tôi phải thêm tiền tố URL với ký tự dấu ngã (~), bởi vì đây là cách Framework ASP.NET trình bày các URL đến hệ thống định tuyến
Chú ý là tôi không cần phải xác định các định tuyến trong các phương thức kiểm thử Điều này là bởi vì tôi đang tải chúng trực tiếp bằng cách sử dụng phương thức
RegisterRoutes trong lớp RouteConfig
Xác định giá trị mặc định
Lý do mà tôi đã nhận ra lỗi khi tôi yêu cầu các URL mặc định cho các ứng dụng là do nó không phù hợp với định tuyến tôi đã xác định
Các URL mặc định được biểu diễn theo ~ / đến các hệ thống định tuyến và không có
phân đoạn trong chuỗi này có thể được kết hợp với các giá trị controller và action được
xác định bởi mô hình định tuyến đơn giản
Tôi đã giải thích rằng các mẫu URL là bảo thủ, trong đó chúng sẽ phù hợp với URL duy nhất với số quy định của phân đoạn Tôi cũng cho rằng, đây là hành vi mặc định và một cách để thay đổi hành vi này là sử dụng các giá trị mặc định Một giá trị mặc định
Trang 17được áp dụng khi các URL không chứa một phân khúc có thể được kết hợp với các giá trị
Bảng liệt kê 15-9 cung cấp một ví dụ về một định tuyến có chứa một giá trị mặc định
Bảng liệt kê 15-9 Cung cấp một giá trị mặc định trong các tập tin RouteConfig.cs
public static void RegisterRoutes(RouteCollection routes) {
routes.MapRoute("MyRoute", "{controller}/{action}", new {
hợp với tất cả các URL hai phân khúc, như nó đã làm trước đây Ví dụ, nếu
http://mydomain.com/Home/Index URL được yêu cầu, định tuyến này sẽ giải nén Home như là biến cho các controller và Index như biến cho các action
Bây giờ tôi đã cung cấp một giá trị mặc định cho phân đoạn action, các định tuyến
cũng sẽ kết hợp các URL đơn phân khúc Khi xử lý một URL đơn phân khúc, các hệ thống
định tuyến sẽ trích xuất các giá trị controller từ phân khúc URL đơn, và sử dụng các giá trị mặc định cho biến action Bằng cách này, tôi có thể yêu cầu các URL
http://mydomain.com/Home và gọi phương thức action Index trên controller Home
Tôi có thể đi xa hơn và xác định các URL không chứa bất kỳ biến ở tất cả phân đoạn,
chỉ dựa trên là những giá trị mặc định để xác định các action và controller Và như là một
ví dụ, Liệt kê 15-10 cho thấy làm thế nào tôi đã ánh xạ URL gốc cho ứng dụng bằng cách cung cấp các giá trị mặc định cho cả hai phân đoạn
Bảng liệt 15-10 Cung cấp các Action và controller giá trị mặc định trong file RouteConfig.cs
using System;
Trang 18public static void RegisterRoutes(RouteCollection routes) {
routes.MapRoute("MyRoute", "{controller}/{action}", new {
controller = "Home", action = "Index" });
}
}
}
Bằng cách cung cấp các giá trị mặc định cho cả biến controller và Action, tôi đã tạo ra
một định tuyến sẽ phù hợp với URL có không, một, hoặc hai đoạn, như thể hiện trong
Bảng 15-3
Bảng 15-3 URL Matching
0 mydomain.com controller = Homeaction = Index
1 mydomain.com/Customer controller = Customeraction =
Framework đến lời gọi phương thức action Index trên controller Home, như thể hiện trong
hình 15 -5
Trang 19Hình 15-5 Sử dụng các giá trị mặc định để mở rộng phạm vi của một định tuyến
ĐƠN VỊ KIỂM ĐỊNH: GIÁ TRỊ MẶC ĐỊNH
Tôi không cần phải thực hiện bất kỳ action đặc biệt để sử dụng các phương thức hỗ trợ để kiểm thử định tuyến mà xác định các giá trị mặc định Dưới đây là các phiên
bản tôi đã thực hiện các phương thử kiểm thử TestIncomingRoutes trong file RouteTests.cs cho định tuyến mà tôi định nghĩa trong Liệt kê 15-10:
Sử dụng phân đoạn URL tĩnh
Trang 20Không phải tất cả phân đoạn trong một mẫu URL cần các biến số Bạn cũng có thể tạo ra các mẫu có phân đoạn tĩnh Giả sử rằng tôi muốn kết hợp một URL như thế này để hỗ trợ
các URL được bắt đầu với Public:
new { controller = "Home", action = "Index" });
routes.MapRoute("", "Public/{controller}/{action}", new
{ controller = "Home", action = "Index" });
}
}
}
Mô hình mới này sẽ phù hợp với URL duy nhất có chứa ba phân đoạn, phần đầu tiên
trong số đó phải là Public Hai phân đoạn khác có thể chứa bất kỳ giá trị nào, và sẽ được
sử dụng cho các giá trị controller và action Nếu hai phân đoạn cuối cùng bị bỏ qua, sau
Trang 21routes.MapRoute("MyRoute", "{controller}/{action}", new
{ controller = "Home", action = "Index" });
routes.MapRoute("", "Public/{controller}/{action}", new {
controller = "Home", action = "Index" });
}
}
}
Các mô hình trong định tuyến này kết hợp với bất kỳ hai phân khúc URL mà phân
đoạn đầu tiên bắt đầu bằng chữ X Giá trị của controller được lấy từ phân đoạn đầu tiên, không bao gồm giá trị X Các action được lấy từ phân đoạn thứ hai Bạn có thể xem hiệu quả của định tuyến này nếu bạn khởi động ứng dụng và điều hướng đến / XHome / Index,
và kết quả là được minh họa bằng hình 15-6
Hình 15-6 Trộn thành phần tĩnh và biến trong một phân khúc duy nhất
Trang 22ĐỊNH TUYẾN ĐẶT HÀNG
Trong Liệt kê 15-12, tôi xác định một định tuyến mới và đặt nó trước tất cả những
định tuyến khác trong các phương thức RegisterRoutes Tôi đã làm điều này bởi vì
các định tuyến được áp dụng trong thứ tự mà chúng xuất hiện trong các đối tượng
RouteCollection Phương thức MapRoute thêm một định tuyến đến cuối của bộ sưu
tập, có nghĩa là định tuyến thường được áp dụng trong thứ tự mà chúng được định nghĩa Tôi nói "thường" vì có những phương thức chèn các định tuyến tại các vị trí
cụ thể Tôi có xu hướng không sử dụng những phương thức này, bởi vì có định tuyến áp dụng thứ tự mà chúng được xác định làm cho sự hiểu biết định tuyến về một ứng dụng đơn giản hơn
Hệ thống định tuyến cố gắng để kết hợp với một URL đến với mẫu URL của định tuyến đã được xác định từ trước, và tiến tới định tuyến duy nhất tiếp theo nếu không phù hợp Định tuyến này được thử nghiệm theo trình tự đến khi định tuyến phù hợp được tìm thấy hoặc tập hợp các định tuyến đã hết Kết quả của việc này là định tuyến
cụ thể nhất phải được xác định trước tiên Định tuyến tôi thêm vào trong Listing
15-12 đặc trưng hơn là định tuyến theo sau Giả sử rằng tôi đảo ngược thứ tự của các định tuyến, như thế này:
routes.MapRoute("MyRoute",
"{controller}/{action}", new { controller =
"Home", action = "Index" }); routes.MapRoute("",
để bất kỳ URL ưa thích, macro hoặc các scripts mà người dùng đã tạo ra để tiếp tục làm
Trang 23việc Hãy tưởng tượng rằng tôi đã từng có controller được gọi là Shop, mà bây giờ đã được thay thế bằng controller Home Liệt kê 15-13 cho thấy làm thế nào tôi có thể tạo ra một con đường để bảo tồn các schema URL cũ
Bảng liệt 15-13 Trộn đoạn URL tĩnh và giá trị mặc định trong File RouteConfig.cs
routes.MapRoute("MyRoute", "{controller}/{action}", new
{ controller = "Home", action = "Index" });
routes.MapRoute("", "Public/{controller}/{action}",
new { controller = "Home", action = "Index" }); }
}
}
Định tuyến tôi thêm kết hợp với bất kỳ URL hai phân khúc mà các phân đoạn đầu tiên
là Shop Các giá trị action được lấy từ đoạn URL thứ hai Các mẫu URL không chứa một biến mảng controller, do đó, các giá trị mặc định tôi đã cung cấp thì được sử dụng Điều này có nghĩa rằng một yêu cầu cho một action trên controller Shop được chuyển sang một yêu cầu cho controller Home Bạn có thể xem tác dụng của định tuyến này bằng cách khởi động ứng dụng và điều hướng đến URL / Shop / Index Như Hình 15-7 cho thấy, định tuyến mới khiến MVC Framework nhắm mục tiêu đến phương thức action Index trong controller Home
Trang 24Hình 15-7 Tạo một bí danh để bảo tồn schemas URL
Tôi có thể đi một bước xa hơn và tạo các bí danh cho các phương thức action đó đã
được tái cấu trúc lại tốt hơn và không còn hiện diện trong controller Để làm điều này, tôi tạo ra một URL tĩnh và cung cấp các giá trị controller và action như mặc định, như trong
routes.MapRoute("MyRoute", "{controller}/{action}", new
{ controller = "Home", action = "Index" });
Trang 25routes.MapRoute("", "Public/{controller}/{action}", new {
controller = "Home", action = "Index" });
}
}
}
Chú ý rằng, một lần nữa, tôi đã đặt định tuyến mới để nó được xác định đầu tiên Điều
này là bởi vì nó có đặc trưng hơn các định tuyến theo sau Nếu một yêu cầu cho Shop / OldAction đã được xử lý bởi định tuyến được xác định tiếp theo, ví dụ, tôi sẽ có được một
kết quả khác nhau từ một trong những thứ tôi muốn Các yêu cầu này sẽ được xử lý bằng
cách sử dụng một lỗi 404—Not Found, chứ không phải được dịch để bảo toàn một hợp
đồng với khách hàng của tôi
UNIT TEST: KIỂM THỬ PHẬN ĐOẠN TĨNH
Một lần nữa, tôi có thể sử dụng phương thức hỗ trợ của tôi để các định tuyến có các mẫu URL có chứa phân đoạn tĩnh Đây là sự bổ sung tôi đã thực hiện phương thức đơn vị kiểm thử TestIncomingRoutes để kiểm tra định tuyến được thêm vào trong liệt kê 15-14:
TestRouteMatch("∼/Customer", "Customer", "Index");
TestRouteMatch("∼/Customer/List", "Customer", "List");
Định nghĩa biến mảng Tuỳ chỉnh
Các biến mảng controller và action có ý nghĩa đặc biệt với MVC Framework và, rõ
ràng, chúng tương ứng với phương thức controller và action sẽ được sử dụng để phục vụ yêu cầu Nhưng đây chỉ là được xây dựng trong các giá trị phân khúc Tôi cũng có thể định
Trang 26nghĩa các biến riêng của tôi, như thể hiện trong Liệt kê 15-15 (Tôi đã gỡ bỏ định tuyến hiện có từ các phần đoạn trước để tôi có thể bắt đầu lại.)
Bảng liệt 15-15 Định nghĩa biến bổ sung trong một mẫu URL trong RouteConfig.cs file
public static void RegisterRoutes(RouteCollection routes) {
routes.MapRoute("MyRoute", "{controller}/{action}/{id}", new {
controller = "Home", action = "Index", id = "DefaultId" });
ba, giá trị mặc định sẽ được sử dụng
Cảnh cáo :Một số tên được dành riêng và không có sẵn cho các phân đoạn tùy chỉnh
tên biến Đây là controller, action, và area Ý nghĩa của hai phần đầu tiên là hiển nhiên,
và tôi sẽ giải thích area trong chương tiếp theo
Tôi có thể truy cập vào bất kỳ của các biến mảng trong một phương thức action bằng
cách sử dụng thuộc tính RouteData.Values Để chứng minh điều này, tôi đã thêm một phương thức action đến controller Home được gọi là CustomVariable, như thể hiện trong
Trang 27` public ActionResult Index() {
Phương thức này có được các giá trị của biến tùy chỉnh trong mô hình định tuyến URL
và truyền qua nó đến view bằng cách sử dụng ViewBag
Để tạo view cho các phương thức action, tạo ra các thư mục Views / Home, nhấn chuột phải vào nó, chọn Add MVC 5 View Page (Razor)từ trình đơn pop-up và đặt tên là CustomVariable.cshtml Nhấp vào nút OK để tạo view và chỉnh sửa nội dung kết hợp liệt
<div>The controller is: @ViewBag.Controller</div>
<div>The action is: @ViewBag.Action</div>
<div>The custom variable is: @ViewBag.CustomVariable</div>
Trang 28</body>
</html>
Để xem ảnh hưởng của các biến mảng tùy chỉnh, khởi động ứng dụng và điều hướng
đến URL / Home / CustomVariable / Hello Phương thức hành động CustomVariable trong controller Home được gọi, và giá trị của các biến mảng tùy chỉnh được lấy từ ViewBag và
truyền đến view Bạn có thể xem kết quả trong hình 15-8
Hình 15-8 Hiển thị các giá trị của một biến mảng tùy chỉnh
Tôi đã cung cấp một giá trị mặc định cho biến mảng id trong định tuyến, có nghĩa là
bạn sẽ thấy những kết quả thể hiện trong hình 15-9 nếu bạn điều hướng đến / Home / CustomVariable
Hình 15-9 Giá trị mặc định cho một biến mảng tùy chỉnh
UNIT TEST: KIỂM THỬ BIẾN PHẬN ĐOẠN TUỲ CHỈNH
Tôi giới thiệu cách hỗ trợ để kiểm thử các biến số phân đoạn tùy chỉnh trong các
phương thức trợ giúp kiểm thử Phương thức TestRouteMatch có một tham số tùy
chọn mà có thể chấp nhận một loại nặc danh có chứa tên của các thuộc mà tôi muốn kiểm thử cho các giá trị mà tôi mong đợi Dưới đây là những thay đổi mà tôi đã thực
Trang 29hiện phương thức kiểm thử TestIncomingRoutes để kiểm thử định tuyến được xác
định trong Liệt kê 15-15:
[Testmethod]
public void TestIncomingRoutes() {
TestRouteMatch("∼/", "Home", "Index", new {
id = "DefaultId" });
TestRouteMatch("∼/Customer", "Customer",
"index", new { id = "DefaultId" });
TestRouteMatch("∼/Customer/List", "Customer",
"List", new { id = "DefaultId" });
Sử dụng biến tùy chỉnh như các tham số phương thức Action
Sử dụng thuộc tính RouteData.Values là chỉ có một cách để truy cập các biến định tuyến
Một cách khác là rõ ràng hơn nhiều Nếu tôi xác định các tham số cho phương thức action với những cái tên kết hơp với các giá trị mẫu URL, MVC Framework sẽ truyền qua các giá trị thu được từ các URL như tham số cho phương thức action Ví dụ, các biến tùy chỉnh tôi quy định tại định tuyến trong Listing 15-15 được gọi là id Tôi có thể sửa đổi phương thức action CustomVariable trong controller Home để nó có một tham số phù hợp, như
trong Liệt kê 15-18
Bảng liệt 15-18 Thêm một tham số phương thức Action trong tập tin HomeController.cs
Trang 30public ActionResult Index() {
Tôi đã xác định các tham số id như là string, nhưng MVC Framework sẽ cố gắng để
chuyển đổi các giá trị URL đế bất cứ kiểu tham số tôi định nghĩa Nếu tôi khởi tạo tham số
id là một int hoặc một DateTime, sau đó tôi sẽ nhận được giá trị từ URL đã phân tích một
thực thể của loại đó Đây là một tính năng đơn giản và hữu ích mà loại bỏ sự cần thiết cho tôi để xử lý các chuyển đổi bản thân mình
Chú ý: MVC Framework sử dụng các tính năng ràng buộc mô hình để chuyển đổi các
giá trị chứa trong URL đến loại NET và có thể xử lý các tình huống phức tạp hơn nhiều
so với trình bày trong ví dụ này Tôi bao hàm mô hình ràng buộc trong Chương 24
Định nghĩa phân đoạn Tùy chọn URL
Một phân đoạn tùy chọn URL là một trong những người dùng không cần phải xác định,
nhưng mà không có giá trị mặc định là cụ thể Bảng liệt kê 15-19 cho thấy một ví dụ, và bạn có thể thấy rằng tôi xác định rằng một biến mảng là tùy chọn bằng cách thiết lập các