Ồ, thực sự là một câu hỏi hay để tôi tự bận rộn trong một giờ. Để đạt được các chức năng cần thiết, chúng ta cần phải móc vào nguồn MVC và một chút phản xạ.
Theo mặc định Tên tuyến không khả dụng, vì vậy chúng tôi cần viết tiện ích mở rộng Tập hợp tuyến đường để lưu Tên tuyến đường trong mã thông báo RouteData.
public static Route MapRouteWithName(this RouteCollection routes,string name, string url, object defaults=null, object constraints=null)
{
Route route = routes.MapRoute(name, url, defaults, constraints);
route.DataTokens = new RouteValueDictionary();
route.DataTokens.Add("RouteName", name);
return route;
}
Sửa đổi các cuộc gọi global.asax maproute để gọi mở rộng trước
routes.MapRouteWithName(
"Default", // Route name
"{controller}/{action}/{id}", // URL with parameters
new { controller = "Home", action = "Index", id = UrlParameter.Optional } // Parameter defaults
);
Modified các PathHelper MVC một chút. (Bao gồm helper này trong dự án)
using System;
using System.Collections.Specialized;
using System.Web;
public static class PathHelpers
{
// this method can accept an app-relative path or an absolute path for contentPath
public static string GenerateClientUrl(HttpContextBase httpContext, string contentPath)
{
if (String.IsNullOrEmpty(contentPath))
{
return contentPath;
}
// many of the methods we call internally can't handle query strings properly, so just strip it out for
// the time being
string query;
contentPath = StripQuery(contentPath, out query);
return GenerateClientUrlInternal(httpContext, contentPath) + query;
}
private static string GenerateClientUrlInternal(HttpContextBase httpContext, string contentPath)
{
if (String.IsNullOrEmpty(contentPath))
{
return contentPath;
}
// can't call VirtualPathUtility.IsAppRelative since it throws on some inputs
bool isAppRelative = contentPath[0] == '~';
if (isAppRelative)
{
string absoluteContentPath = VirtualPathUtility.ToAbsolute(contentPath, httpContext.Request.ApplicationPath);
string modifiedAbsoluteContentPath = httpContext.Response.ApplyAppPathModifier(absoluteContentPath);
return GenerateClientUrlInternal(httpContext, modifiedAbsoluteContentPath);
}
string relativeUrlToDestination = MakeRelative(httpContext.Request.Path, contentPath);
string absoluteUrlToDestination = MakeAbsolute(httpContext.Request.RawUrl, relativeUrlToDestination);
return absoluteUrlToDestination;
}
public static string MakeAbsolute(string basePath, string relativePath)
{
// The Combine() method can't handle query strings on the base path, so we trim it off.
string query;
basePath = StripQuery(basePath, out query);
return VirtualPathUtility.Combine(basePath, relativePath);
}
public static string MakeRelative(string fromPath, string toPath)
{
string relativeUrl = VirtualPathUtility.MakeRelative(fromPath, toPath);
if (String.IsNullOrEmpty(relativeUrl) || relativeUrl[0] == '?')
{
// Sometimes VirtualPathUtility.MakeRelative() will return an empty string when it meant to return '.',
// but links to {empty string} are browser dependent. We replace it with an explicit path to force
// consistency across browsers.
relativeUrl = "./" + relativeUrl;
}
return relativeUrl;
}
private static string StripQuery(string path, out string query)
{
int queryIndex = path.IndexOf('?');
if (queryIndex >= 0)
{
query = path.Substring(queryIndex);
return path.Substring(0, queryIndex);
}
else
{
query = null;
return path;
}
}
}
Thêm vài phương pháp trợ giúp trong bộ điều khiển
public static string GenerateUrl(string routeName, string actionName, string controllerName, RouteCollection routeCollection, RequestContext requestContext)
{
RouteValueDictionary mergedRouteValues = MergeRouteValues(actionName, controllerName);
VirtualPathData vpd = routeCollection.GetVirtualPathForArea(requestContext, routeName, mergedRouteValues);
if (vpd == null)
{
return null;
}
string modifiedUrl = PathHelpers.GenerateClientUrl(requestContext.HttpContext, vpd.VirtualPath);
return modifiedUrl;
}
public static RouteValueDictionary MergeRouteValues(string actionName, string controllerName)
{
// Create a new dictionary containing implicit and auto-generated values
RouteValueDictionary mergedRouteValues = new RouteValueDictionary();
// Merge explicit parameters when not null
if (actionName != null)
{
mergedRouteValues["action"] = actionName;
}
if (controllerName != null)
{
mergedRouteValues["controller"] = controllerName;
}
return mergedRouteValues;
}
Bây giờ chúng ta có thể viết một số phản ánh logic để đọc bộ điều khiển, hành động và tên định tuyến.
Dictionary<string, List<string>> controllersAndActions = new Dictionary<string, List<string>>();
// Get all the controllers
var controllers = Assembly.GetExecutingAssembly().GetTypes().Where(t => typeof(Controller).IsAssignableFrom(t));
foreach (var controller in controllers)
{
List<string> actions = new List<string>();
//Get all methods without HttpPost and with return type action result
var methods = controller.GetMethods().Where(m => typeof(ActionResult).IsAssignableFrom(m.ReturnType)).Where(a=>!a.GetCustomAttributes(typeof(HttpPostAttribute),true).Any());
methods.ToList().ForEach(a => {
actions.Add(a.Name);
});
var controllerName = controller.Name;
if (controllerName.EndsWith("Controller"))
{
var nameLength = controllerName.Length - "Controller".Length;
controllerName = controllerName.Substring(0, nameLength);
}
controllersAndActions.Add(controllerName, actions);
}
List<string> allowedRoutes = new List<string>();
var routeNames = RouteTable.Routes.Where(o=>o.GetRouteData(this.HttpContext)!=null).Select(r=>r.GetRouteData(this.HttpContext).DataTokens["RouteName"].ToString());
foreach (var cName in controllersAndActions)
{
foreach (var aName in cName.Value)
{
foreach (var item in routeNames)
{
allowedRoutes.Add(GenerateUrl(item, aName, cName.Key, RouteTable.Routes, this.Request.RequestContext));
}
}
}
Điểm cần nhớ: Nếu trong tuyến đường bạn đã xác định bất kỳ thông số mặc định nào, thì url cho bộ điều khiển và hành động đó sẽ trống. ví dụ. trong ví dụ trên "/ Home/Index" sẽ được hiển thị là "/"
Tải ứng dụng mẫu Link To Download
làm bạn có nghĩa là giá trị gốc ..? – MethodMan
bạn có cây/đồ thị các loại? – Adrian
RouteTable thực sự là nơi để xem ... Điều đó nói rằng, chúng ta thực hiện theo cách khác: chúng ta sử dụng các thuộc tính để quảng cáo tuyến đường và xây dựng bảng định tuyến thông qua sự phản chiếu - và dĩ nhiên chúng ta có thể chạy phản chiếu đó danh sách các tuyến đường –