making URL lowercase. Any easy or builtin way?
Is there any easy/builtin way to make URL in lowercase for MVC3.
I have code that could do it but looking something simple to implement.
routes.MapRouteLowercase(
"Default", // Route name
"{controller}/{action}/{id}", // URL with parameters
new { controller = "Home", action = "index", id = UrlParameter.Optional } // Parameter defaults
);
public class LowercaseRoute : Route
{
public LowercaseRoute(string url, IRouteHandler routeHandler)
: base(url, routeHandler)
{
}
public LowercaseRoute(string url, RouteValueDictionary defaults, IRouteHandler routeHandler)
: base(url, defaults, routeHandler)
{
}
public LowercaseRoute(string url, RouteValueDictionary defaults, RouteValueDictionary constraints, IRouteHandler routeHandler)
: base(url, defaults, constraints, routeHandler)
{
}
public LowercaseRoute(string url, RouteValueDictionary defaults, RouteValueDictionary constraints, RouteValueDictionary dataTokens, IRouteHandler routeHandler)
: base(url, defaults, constraints, dataTokens, routeHandler)
{
}
public override VirtualPathData GetVirtualPath(RequestContext requestContext, RouteValueDictionary values)
{
VirtualPathData path = base.GetVirtualPath(requestContext, values);
if (path != null)
{
path.VirtualPath = path.VirtualPath.ToLowerInvariant();
}
return path;
}
}
public static class RouteCollectionExtensions
{
public static Route MapRouteLowercase(this RouteCollection routes, string name, string url)
{
return routes.MapRouteLowercase(name, url, null /* defaults */, (object)null /* constraints */);
}
public static Route MapRouteLowercase(this RouteCollection routes, string name, string url, object defaults)
{
return routes.MapRouteLowercase(name, url, defaults, (object)null /* constraints */);
}
public static Route MapRouteLowercase(this RouteCollection routes, string name, string url, object defaults, object constraints)
{
return routes.MapRouteLowercase(name, url, defaults, constraints, null /* namespaces */);
}
public static Route MapRouteLowercase(this RouteCollection routes, string name, string url, string[] namespaces)
{
return routes.MapRouteLowercase(name, url, null /* defaults */, null /* constraints */, namespaces);
}
public static Route MapRouteLowercase(this RouteCollection routes, string name, string url, object defaults, string[] namespaces)
{
return routes.MapRouteLowercase(name, url, defaults, null /* constraints */, namespaces);
}
public static Route MapRouteLowercase(this RouteCollection routes, string name, string url, object defaults, object constraints, string[] namespaces)
{
if (routes == null)
{
throw new ArgumentNullException("routes");
}
if (url == null)
{
throw new ArgumentNullException("url");
}
Route route = new LowercaseRoute(url, new MvcRouteHandler())
{
Defaults = new RouteValueDictionary(defaults),
Constraints = new RouteValueDictionary(constraints),
DataTokens = new RouteValueDictionary()
};
if ((namespaces != null) && (namespaces.Length > 0))
{
route.DataTokens["Namespaces"] = namespaces;
}
routes.Add(name, route);
return route;
}
public static Route MapRouteLowercase(this AreaRegistrationContext context, string name, string url)
{
return context.MapRouteLowercase(name, url, (object)null /* defaults */);
}
public开发者_开发百科 static Route MapRouteLowercase(this AreaRegistrationContext context, string name, string url, object defaults)
{
return context.MapRouteLowercase(name, url, defaults, (object)null /* constraints */);
}
public static Route MapRouteLowercase(this AreaRegistrationContext context, string name, string url, object defaults, object constraints)
{
return context.MapRouteLowercase(name, url, defaults, constraints, null /* namespaces */);
}
public static Route MapRouteLowercase(this AreaRegistrationContext context, string name, string url, string[] namespaces)
{
return context.MapRouteLowercase(name, url, (object)null /* defaults */, namespaces);
}
public static Route MapRouteLowercase(this AreaRegistrationContext context, string name, string url, object defaults, string[] namespaces)
{
return context.MapRouteLowercase(name, url, defaults, null /* constraints */, namespaces);
}
public static Route MapRouteLowercase(this AreaRegistrationContext context, string name, string url, object defaults, object constraints, string[] namespaces)
{
if (namespaces == null && context.Namespaces != null)
{
namespaces = context.Namespaces.ToArray();
}
Route route = context.Routes.MapRouteLowercase(name, url, defaults, constraints, namespaces);
route.DataTokens["area"] = context.AreaName;
// disabling the namespace lookup fallback mechanism keeps this areas from accidentally picking up
// controllers belonging to other areas
bool useNamespaceFallback = (namespaces == null || namespaces.Length == 0);
route.DataTokens["UseNamespaceFallback"] = useNamespaceFallback;
return route;
}
}
I've just noticed that there is a new property in .NET Framework 4.5. Works great! RouteCollection.LowercaseUrls
Set LowercaseUrls to true
public static void RegisterRoutes(RouteCollection routes)
{
routes.LowercaseUrls = true;
...
}
Create a link
@Html.ActionLink("Log in", "Login", "Account")
That will create awesome, lowercase url :)
<a href="/account/login">Log in</a>
There is a NuGet package for this : LowerCaseRoutesMVC (Project website)
If your reasons for enforcing lowercase is purely SEO, then the best solution that I have found is to use the IIS 7 URL Rewrite Module
Not only do you have the ability to force all url's to lowercase but you also have access to rules that allow you to remove/add trailing slashes, enforce canonical domains etc.
RuslanY's Blog has a good set to start from. For example, I use the following on all of my sites:
<!-- http://ruslany.net/2009/04/10-url-rewriting-tips-and-tricks/ -->
<rule name="Convert to lower case" stopProcessing="true">
<match url=".*[A-Z].*" ignoreCase="false" />
<conditions>
<add input="{REQUEST_METHOD}" matchType="Pattern" pattern="GET" ignoreCase="false" />
</conditions>
<action type="Redirect" url="{ToLower:{R:0}}" redirectType="Permanent" />
</rule>
You simply add the above lines to the section of your web.config.
Yes, I have had to implement something similar to the above. It appears to be the only smooth way to accomplish this.
I would like to add that in addition, we added 301 redirects so that any traffic coming from /Upper-Case-Url will be 301 redirected to /upper-case-url.
Not sure what's wrong with your code (mine's a little different, but essentially the same concept). It's super easy to implement, and it's fully reusable.
LowerCaseRouteHelper.cs
using System.Web.Routing;
using System.Web.Mvc;
namespace Utilities.Helpers
{
public class LowercaseRouteHelper : System.Web.Routing.Route
{
public LowercaseRouteHelper(string url, IRouteHandler routeHandler) : base(url, routeHandler)
{
}
public LowercaseRouteHelper(string url, RouteValueDictionary defaults, IRouteHandler routeHandler) : base(url, defaults, routeHandler)
{
}
public LowercaseRouteHelper(string url, RouteValueDictionary defaults, RouteValueDictionary constraints, IRouteHandler routeHandler) : base(url, defaults, constraints, routeHandler)
{
}
public LowercaseRouteHelper(string url, RouteValueDictionary defaults, RouteValueDictionary constraints, RouteValueDictionary dataTokens, IRouteHandler routeHandler) : base(url, defaults, constraints, dataTokens, routeHandler)
{
}
public override VirtualPathData GetVirtualPath(RequestContext requestContext, RouteValueDictionary values)
{
VirtualPathData path = base.GetVirtualPath(requestContext, values);
if (path != null) {
path.VirtualPath = path.VirtualPath.ToLowerInvariant();
}
return path;
}
}
public static class RouteCollectionExtensions
{
[System.Runtime.CompilerServices.Extension()]
public static void MapRouteLowercase(RouteCollection routes, string name, string url, object defaults)
{
routes.MapRouteLowercase(name, url, defaults, null);
}
[System.Runtime.CompilerServices.Extension()]
public static void MapRouteLowercase(RouteCollection routes, string name, string url, object defaults, object constraints)
{
if (routes == null) {
throw new ArgumentNullException("routes");
}
if (url == null) {
throw new ArgumentNullException("url");
}
object route = new LowercaseRouteHelper(url, new MvcRouteHandler()) {
Defaults = new RouteValueDictionary(defaults),
Constraints = new RouteValueDictionary(constraints)
};
if (String.IsNullOrEmpty(name)) {
routes.Add(route);
} else {
routes.Add(name, route);
}
}
}
}
global
routes.MapRouteLowercase("Start", "", new {
controller = "Home",
action = "Index"
})
I love this, and the great thing (as the comments say) is that it really helps improve SEO.
Lol you guys are making this way too hard on yourselves. Just add this to your global.asax application_beginrequest ...
protected void Application_BeginRequest(Object sender, EventArgs e) {
string url = (Request.Url.Scheme + "://" + HttpContext.Current.Request.Url.Authority + HttpContext.Current.Request.Url.AbsolutePath);
if (Regex.IsMatch(url, @"[A-Z]")) {
PermanentRedirect(url.ToLower() + HttpContext.Current.Request.Url.Query);
}
private void PermanentRedirect(string url) {
Response.Clear();
Response.Status = "301 Moved Permanently";
Response.AddHeader("Location", url);
Response.End();
}
精彩评论