【问题标题】:ASP.NET MVC to ignore ".html" at the end of all urlASP.NET MVC 忽略所有 url 末尾的“.html”
【发布时间】:2023-03-29 19:51:01
【问题描述】:

我是 asp.net mvc 的新手,现在正在为 url 路由而苦苦挣扎。我正在使用 asp.net mvc 3 RC2。

如何创建一个 IGNORES url 中最末端扩展的 url 路由。扩展名可以是:.html.aspx.php.anything

例如,这些网址:

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

应该去Home控制器吗?

再举一个例子:

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

应该转到Home 控制器和About 操作。

谢谢你:)

【问题讨论】:

    标签: asp.net-mvc url-routing


    【解决方案1】:

    我不确定您是否使用 IIS7,但如果是这样,那么我会推荐一个重写规则,该规则检查以 .xyz 结尾的 url,然后在没有 .xyz 的情况下对其进行重写。

    类似这样的:

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

    这将处理您建议的用例。任何以扩展名和某些字符结尾的内容都将被重写为没有扩展名的 url。这样做的好处是您只需要一个路由,因为没有一个路由就可以进入您的应用程序。

    【讨论】:

      【解决方案2】:

      你只需要调整 Global.asax.cs 中的默认路由,试试这个:

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

      来自 url 的 {extension} 值将包含在路由数据中,但如果您不需要它,您可以放心地忽略它

      【讨论】:

      • 这意味着我必须为“{controller}.{extension}/{action}/{id}”和“{controller}/{action}/{id}.{extension”再次创建}”。你有什么更好的主意吗,因为我不想调整我所有的路线:(
      • 嗯,这些是不同的路线,所以他们需要这样设置,我没有更好的建议。您是使用默认路由还是有大量自定义路由?
      • 目前,只有来自模板的默认路由。但稍后会添加更多路线并将此规则应用于它们
      【解决方案3】:

      要么创建你自己的路由类,要么使用这个正则表达式路由实现:http://blog.sb2.fr/post/2009/01/03/Regular-Expression-MapRoute-With-ASPNET-MVC.aspx

      【讨论】:

        【解决方案4】:

        可以在 IIS 中处理此问题,而不是使用 IIS Url 重写的 ASP.NET MVC。例如:http://learn.iis.net/page.aspx/496/iis-url-rewriting-and-aspnet-routing/

        【讨论】:

          【解决方案5】:

          我作为周末作业开始研究这个问题:D
          下面的代码将按要求工作。请参考以下参考资料

          1] MyUrlRoute 类: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;
              }
          }
          

          }

          在 global.asax.cs 中添加以下代码

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

          按预期工作。

          也许你可以改进 if/elseif 代码。

          【讨论】:

          • 这看起来令人难以置信且不必要的hacky。
          • url 路由按要求工作,所以这是一个很好的技巧!我需要做更多的阅读,但我认为框架必须做一些类似的事情......
          【解决方案6】:

          使用Application_BeginRequest,将允许您拦截所有传入请求,并允许您修剪扩展。确保忽略对您的内容的请求,例如 .css、.js、.jpg 等。否则这些请求的扩展名也会被修剪。

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

          【讨论】:

            【解决方案7】:

            如果您使用的是 IIS 7,则应查看 Dan Atkinson's answer

            我使用的是 IIS 6,因此,就我而言,我可以选择安装 isapi rewrite for IIS 6 或创建自定义路由。我更喜欢创建简单的自定义路由类

            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;
                }
            }
            
            Global.asax 中的

            RegisterRoutes 方法

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

            【讨论】:

            • 当然不是我。如果您对任何 IIS 版本有更好的解决方案,这个赏金将一直开放到明天:D
            • 好的。没有真正想到任何其他解决方案。只有下面提到的解决方案覆盖“RouteData as GetRouteData(HttpContextBase httpContext)”,它适用于任何 IIS 版本:)
            猜你喜欢
            • 2021-04-08
            • 1970-01-01
            • 2014-01-03
            • 2011-01-05
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2023-01-18
            相关资源
            最近更新 更多