开发者

ASP.NET MVC to ignore ".html" at the end of all url

I am new to asp.net mvc and now struggling with url routing. I'm using asp.net mvc 3 RC2.

How can I create a url routing that IGNORES the very end extension in url. the extension can be: .html, .aspx, .php, .anything.

For example, these urls:

/Home.html
/Home.en
/Home.fr
/Home

should go to Home controller?

one more example:

/Home/About.html
/Home/About.en
/Home开发者_JAVA技巧/About.fr
/Home/About

should go to Home controller and About action.

thank you :)


I'm not sure if you're using IIS7, but if so, then I would recommend a rewrite rule which checks for urls ending in .xyz and then doing a rewrites for them without the .xyz.

Something like this:

<rewrite>
  <rules>
    <rule name="HtmlRewrite">
      <match url="(.*)(\.\w+)$" />
      <action type="Rewrite" url="{R:1}" />
    </rule>
  </rules>
</rewrite>

This will handle the use cases you suggested. Anything that ends with an extension and some characters will be rewritten to a url without the extension. The benefit of this is that you will only need one route because everything goes into your application without one.


You just need to tweak the default route in Global.asax.cs, try this:

routes.MapRoute(
  "Default", // Route name
  "{controller}/{action}.{extension}/{id}", // URL with parameters
  new { controller = "Home", action = "Index", id = UrlParameter.Optional });

The {extension} value from the url will be included in the route data, but you can just safely ignore it if you don't need it


Either create your own route class, or use this regex route implementation: http://blog.sb2.fr/post/2009/01/03/Regular-Expression-MapRoute-With-ASPNET-MVC.aspx


You could handle this in IIS instead of ASP.NET MVC using IIS Url rewriting. See for example: http://learn.iis.net/page.aspx/496/iis-url-rewriting-and-aspnet-routing/


I started to work on this question as a weekend assignment :D
below code will work as requested in question. please refer below references

1] MyUrlRoute Class : RouteBase

using System; 
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using System.Web.Routing;

namespace MvcIgnoreUrl
{
    #region //References    
    // SO question /http://stackoverflow.com/questions/4449449/asp-net-mvc-to-ignore-html-at-the-end-of-all-url       
    // Implementing Custom Base entry - Pro Asp.Net MVc Framework       
    //- http://books.google.com/books?id=tD3FfFcnJxYC&amp;pg=PA251&amp;lpg=PA251&amp;dq=.net+RouteBase&amp;source=bl&amp;ots=IQhFwmGOVw&amp;sig=0TgcFFgWyFRVpXgfGY1dIUc0VX4&amp;hl=en&amp;ei=z61UTMKwF4aWsgPHs7XbAg&amp;sa=X&amp;oi=book_result&amp;ct=result&amp;resnum=6&amp;ved=0CC4Q6AEwBQ#v=onepage&amp;q=.net%20RouteBase&amp;f=false       
    // SO previous Question on ihttphandler - http://stackoverflow.com/questions/3359816/can-asp-net-routing-be-used-to-create-clean-urls-for-ashx-ihttphander-handle    
    // phil haack's Route Debugger http://haacked.com/archive/2008/03/13/url-routing-debugger.aspx    

    #endregion


public class MyUrlRoute : RouteBase
{

    public override RouteData GetRouteData(HttpContextBase httpContext)
    {
        //~/Account/LogOn 
        //~/Home.aspx - Works fine
        //~/home/index.aspx  -Works Fine
        //http://localhost:57282/home/index/1/2/3 - Works fine
        //http://localhost:57282/Account/Register  http://localhost:57282/Account/LogOn - Works Fine

        string url = httpContext.Request.AppRelativeCurrentExecutionFilePath;

        //check null for URL
        const string defaultcontrollername  = "Home";
        string[] spliturl = url.Split("//".ToCharArray());
        string controllername = String.Empty;
        string actionname = "Index";



        if (spliturl.Length == 2) //for ~/home.aspx and ~/ 
        {
            if (String.IsNullOrEmpty(spliturl[1])) //TODO:  http://localhost:57282/ not working - to make it working
            {
                controllername = defaultcontrollername;
            }
            else
            {
                controllername = spliturl[1];
                if (controllername.Contains("."))
                {
                    controllername = controllername.Substring(0, controllername.LastIndexOf("."));
                }
            }
        }
        else if (spliturl.Length == 3) // For #/home/index.aspx and /home/about
        {
            controllername = spliturl[1];
            actionname = spliturl[2];
            if (actionname.Contains("."))
            {
                actionname = actionname.Substring(0, actionname.LastIndexOf("."));
            }
        }
        else //final block in final case sned it to Home Controller
        {
            controllername = defaultcontrollername;
        }


        RouteData rd = new RouteData(this, new MvcRouteHandler());
        rd.Values.Add("controller", controllername);
        rd.Values.Add("action", actionname);
        rd.Values.Add("url", url);
        return rd;
    }

    public override VirtualPathData GetVirtualPath(RequestContext requestContext, RouteValueDictionary values)
    {
        return null;
    }
}

}

in global.asax.cs add below code

    public static void RegisterRoutes(RouteCollection routes)
    {
        routes.IgnoreRoute("{resource}.axd/{*pathInfo}");

        routes.Add(new MyUrlRoute()); // Add before your default Routes

        routes.MapRoute(
            "Default", // Route name
            "{controller}/{action}/{id}", // URL with parameters
            new { controller = "Home", action = "Index", id = UrlParameter.Optional } // Parameter defaults
        );

    }

working as expected.

possibly you can improve if/elseif code.


Using the Application_BeginRequest, will allow you to intercept all incoming requests, and allow you to trim the extension. Make sure to ignore requests for your content, such as .css, .js, .jpg, etc. Otherwise those requests will have their extensions trimmed as well.

protected void Application_BeginRequest(object sender, EventArgs e)
        {
            String originalPath = HttpContext.Current.Request.Url.AbsolutePath;

            //Ignore content files (e.g. .css, .js, .jpg, .png, etc.)
            if (!Regex.Match(originalPath, "^/[cC]ontent").Success)
            {
                //Search for a file extension (1 - 5 charaters long)
                Match match = Regex.Match(originalPath, "\\.[a-zA-Z0-9]{1,5}$");

                if (match.Success)
                {
                    String modifiedPath = String.Format("~{0}", originalPath.Replace(match.Value, String.Empty));
                    HttpContext.Current.RewritePath(modifiedPath);
                }
            }
        }


If you are using IIS 7, you should look at Dan Atkinson's answer.

I'm using IIS 6, so, in my case, I have the option to install isapi rewrite for IIS 6 or create custom route. I prefer to create my simple custom route class

AndraRoute.cs

// extend Route class,
// so that we can manipulate original RouteData
// by overriding method GetRouteDate 
public class AndraRoute : Route
{
    // constructor
    public AndraRoute(
        string url, 
        RouteValueDictionary defaults, 
        RouteValueDictionary constraints, 
        IRouteHandler routeHandler)
        : base(url, defaults, constraints, routeHandler)
    {
    }

    // get original RouteData
    // check if any route data value has extension '.html' or '.anything'
    // remove the extension
    public override RouteData GetRouteData(HttpContextBase httpContext)
    {
        var data = base.GetRouteData(httpContext);
        if (data == null) return null;

        // from original route data, check 
        foreach (var pair in data.Values)
        {
            if (pair.Value.ToString().Contains('.'))
            {
                var splits = pair.Value.ToString().Split('.');

                if (splits[1] == "html" || splits[1] == "anything")
                {
                    data.Values[pair.Key] = splits[0];
                }
                break;
            }
        }

        return data;
    }

}

RouteCollectionExtensionHelper.cs

public static class RouteCollectionExtensionHelper
{
    public static Route MapAndraRoute(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");
        }

        var route = new AndraRoute(url, 
                            new RouteValueDictionary(defaults),
                            new RouteValueDictionary(constraints), 
                            new MvcRouteHandler());

        if ((namespaces != null) && (namespaces.Length > 0))
        {
            route.DataTokens = new RouteValueDictionary();
            route.DataTokens["Namespaces"] = namespaces;
        }
        routes.Add(name, route);
        return route;
    }
}

RegisterRoutes method in Global.asax

public static void RegisterRoutes(RouteCollection routes)
{
    routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
    routes.IgnoreRoute("Content/{*pathInfo}");

    routes.MapAndraRoute(
        "Product",
        "product/{id}/{slug}",
        new { controller = "product", action = "detail" },
        null, null
    );

    routes.MapAndraRoute(
        "Default",
        "{controller}/{action}/{id}",
        new { controller = "home", action = "index", id = UrlParameter.Optional },
        null, null
    );

}
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜