ASP.NET MVC to ignore “.html” at the end of all ur

2019-02-12 10:40发布

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/About.fr
/Home/About

should go to Home controller and About action.

thank you :)

7条回答
Summer. ? 凉城
2楼-- · 2019-02-12 10:58

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
    );

}
查看更多
迷人小祖宗
3楼-- · 2019-02-12 11:05

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/

查看更多
仙女界的扛把子
4楼-- · 2019-02-12 11:05

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);
                }
            }
        }
查看更多
孤傲高冷的网名
5楼-- · 2019-02-12 11:13

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&pg=PA251&lpg=PA251&dq=.net+RouteBase&source=bl&ots=IQhFwmGOVw&sig=0TgcFFgWyFRVpXgfGY1dIUc0VX4&hl=en&ei=z61UTMKwF4aWsgPHs7XbAg&sa=X&oi=book_result&ct=result&resnum=6&ved=0CC4Q6AEwBQ#v=onepage&q=.net%20RouteBase&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.

查看更多
爱情/是我丢掉的垃圾
6楼-- · 2019-02-12 11:15

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.

查看更多
够拽才男人
7楼-- · 2019-02-12 11:19

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

查看更多
登录 后发表回答