有几种方法可以做到这一点:
以您希望它们在 url 中显示的样式命名所有视图
这非常简单,您只需将ActionName
属性添加到所有操作并以您希望 url 的样式指定它们,然后将 CamelCase.cshtml 文件重命名为 camel-case.cshtml 文件。
使用属性路由
与上述相同,nuget 上有一个插件可以启用属性路由,它允许您将每个操作的完整 url 指定为操作的属性。它具有约定属性来帮助您使用控制器名称等。我通常更喜欢这种方法,因为我喜欢非常明确地使用我的应用程序中的路由。
一种更加框架化的方法
通过扩展 MVC 框架可能会做一些基于约定的事情,但这将是大量的工作。为了在控制器上选择正确的操作,您需要在框架使用它来定位控制器上的操作之前,将进入 MVC 的操作名称映射到其 CamelCase 等效项。最容易做到这一点的地方是在 Route 中,这是 MVC 框架接管请求之前发生的最后一件事。您还需要在输出时转换另一种方式,以便生成的 url 看起来像您想要的那样。
由于您真的不想更改现有方法来注册路由,因此最好在 application init 中编写一个函数,该函数在注册后遍历所有路由并用您的新功能包装它们。
这是一个示例路由和对应用程序启动的修改,以实现您想要做的事情。但是,我仍然会使用路由属性方法。
public class MvcApplication : System.Web.HttpApplication
{
protected void Application_Start()
{
AreaRegistration.RegisterAllAreas();
WebApiConfig.Register(GlobalConfiguration.Configuration);
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
RouteConfig.RegisterRoutes(RouteTable.Routes);
WrapRoutesWithNamingConvention(RouteTable.Routes);
BundleConfig.RegisterBundles(BundleTable.Bundles);
AuthConfig.RegisterAuth();
}
private void WrapRoutesWithNamingConvention(RouteCollection routes)
{
var wrappedRoutes = routes.Select(m => new ConventionRoute(m)).ToList();
routes.Clear();
wrappedRoutes.ForEach(routes.Add);
}
private class ConventionRoute : Route
{
private readonly RouteBase baseRoute;
public ConventionRoute(RouteBase baseRoute)
: base(null, null)
{
this.baseRoute = baseRoute;
}
public override RouteData GetRouteData(HttpContextBase httpContext)
{
var baseRouteData = baseRoute.GetRouteData(httpContext);
if (baseRouteData == null) return null;
var actionName = baseRouteData.Values["action"] as string;
var convertedActionName = ConvertHyphensToPascalCase(actionName);
baseRouteData.Values["action"] = convertedActionName;
return baseRouteData;
}
private string ConvertHyphensToPascalCase(string hyphens)
{
var capitalParts = hyphens.Split('-').Select(m => m.Substring(0, 1).ToUpper() + m.Substring(1));
var pascalCase = String.Join("", capitalParts);
return pascalCase;
}
public override VirtualPathData GetVirtualPath(RequestContext requestContext, RouteValueDictionary values)
{
var valuesClone = new RouteValueDictionary(values);
var pascalAction = valuesClone["action"] as string;
var hyphens = ConvertPascalCaseToHyphens(pascalAction);
valuesClone["action"] = hyphens;
var baseRouteVirtualPath = baseRoute.GetVirtualPath(requestContext, valuesClone);
return baseRouteVirtualPath;
}
private string ConvertPascalCaseToHyphens(string pascal)
{
var pascalParts = new List<string>();
var currentPart = new StringBuilder();
foreach (var character in pascal)
{
if (char.IsUpper(character) && currentPart.Length > 0)
{
pascalParts.Add(currentPart.ToString());
currentPart.Clear();
}
currentPart.Append(character);
}
if (currentPart.Length > 0)
{
pascalParts.Add(currentPart.ToString());
}
var lowers = pascalParts.Select(m => m.ToLower());
var hyphens = String.Join("-", lowers);
return hyphens;
}
}
}