【问题标题】:Friendly URLs for ASP.NETASP.NET 的友好 URL
【发布时间】:2010-09-07 21:40:42
【问题描述】:

Python 框架始终提供处理 URL 的方法,这些 URL 以优雅的方式传达请求的数据,例如 http://somewhere.overtherainbow.com/userid/123424/

我想让你注意结束路径/userid/123424/

在 ASP.NET 中如何做到这一点?

【问题讨论】:

    标签: asp.net url rest friendly-url


    【解决方案1】:

    此示例使用 ASP.NET 路由来实现友好的 URL。

    应用程序处理的映射示例如下:

    http://samplesite/userid/1234 - http://samplesite/users.aspx?userid=1234
    http://samplesite/userid/1235 - http://samplesite/users.aspx?userid=1235

    本示例使用查询字符串并避免任何修改 aspx 页面上的代码的要求。

    第 1 步 - 将必要的条目添加到 web.config

    <system.web>
    <compilation debug="true">
            <assemblies>
                …
                <add assembly="System.Web.Routing, Version=3.5.0.0,    Culture=neutral, PublicKeyToken=31BF3856AD364E35"/>
            </assemblies>
        </compilation>
    …
        <httpModules>
        …
            <add name="UrlRoutingModule" type="System.Web.Routing.UrlRoutingModule, System.Web.Routing, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" />
            </httpModules>
    </system.web>
    <system.webServer>
        …
        <modules>
            …
            <add name="UrlRoutingModule" type="System.Web.Routing.UrlRoutingModule, System.Web.Routing, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"/>
        </modules>
        <handlers
    …   
            <add name="UrlRoutingHandler" preCondition="integratedMode" verb="*" path="UrlRouting.axd" type="System.Web.HttpForbiddenHandler,                 System.Web, Version=2.0.0.0, Culture=neutral,              PublicKeyToken=b03f5f7f11d50a3a"/>
        </handlers>
    </system.webServer>
    

    第 2 步 - 在 global.asax 中添加路由表

    定义从友好 URL 到 aspx 页面的映射,保存请求的用户 ID 以供以后使用。

    void Application_Start(object sender, EventArgs e)
    {
        RegisterRoutes(RouteTable.Routes);
    }
    
    public static void RegisterRoutes(RouteCollection routes)
    {
        routes.Add("UseridRoute", new Route
        (
           "userid/{userid}",
           new CustomRouteHandler("~/users.aspx")
        ));
    }
    

    第 3 步 - 实现路由处理程序

    在路由发生之前将查询字符串添加到当前上下文。

    using System.Web.Compilation;
    using System.Web.UI;
    using System.Web;
    using System.Web.Routing;
    
    public class CustomRouteHandler : IRouteHandler
    {
        public CustomRouteHandler(string virtualPath)
        {
            this.VirtualPath = virtualPath;
        }
    
        public string VirtualPath { get; private set; }
    
        public IHttpHandler GetHttpHandler(RequestContext
              requestContext)
        {
            // Add the querystring to the URL in the current context
            string queryString = "?userid=" + requestContext.RouteData.Values["userid"];
            HttpContext.Current.RewritePath(
              string.Concat(
              VirtualPath,
              queryString)); 
    
            var page = BuildManager.CreateInstanceFromVirtualPath
                 (VirtualPath, typeof(Page)) as IHttpHandler;
            return page;
        }
    }
    

    users.aspx 中的代码

    aspx页面上的代码供参考。

    protected void Page_Load(object sender, EventArgs e)
    {
        string id = Page.Request.QueryString["userid"];
        switch (id)
        {
            case "1234":
                lblUserId.Text = id;
                lblUserName.Text = "Bill";
                break;
            case "1235":
                lblUserId.Text = id;
                lblUserName.Text = "Claire";
                break;
            case "1236":
                lblUserId.Text = id;
                lblUserName.Text = "David";
                break;
            default:
                lblUserId.Text = "0000";
                lblUserName.Text = "Unknown";
                break;
    }
    

    【讨论】:

    • 我知道这是一个旧的,但在谷歌上得分很高。有什么理由永远不会调用 GetHttpHandler。我将运行时错误生成代码放在那里,果然除了 GetHttpHandler 之外的所有方法都在请求中被调用。
    【解决方案2】:

    这是另一个使用 ASP.NET 路由来实现友好 URL 的替代示例。

    应用程序处理的映射示例如下:

    http://samplesite/userid/1234 - http://samplesite/users.aspx?userid=1234
    http://samplesite/userid/1235 - http://samplesite/users.aspx?userid=1235

    此示例使用查询字符串,但在 aspx 页面上需要额外的代码

    第 1 步 - 将必要的条目添加到 web.config

    <system.web>
    <compilation debug="true">
            <assemblies>
                …
                <add assembly="System.Web.Routing, Version=3.5.0.0,    Culture=neutral, PublicKeyToken=31BF3856AD364E35"/>
            </assemblies>
        </compilation>
    …
        <httpModules>
        …
            <add name="UrlRoutingModule" type="System.Web.Routing.UrlRoutingModule, System.Web.Routing, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" />
            </httpModules>
    </system.web>
    <system.webServer>
        …
        <modules>
            …
            <add name="UrlRoutingModule" type="System.Web.Routing.UrlRoutingModule, System.Web.Routing, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"/>
        </modules>
        <handlers
    …   
            <add name="UrlRoutingHandler" preCondition="integratedMode" verb="*" path="UrlRouting.axd" type="System.Web.HttpForbiddenHandler,                 System.Web, Version=2.0.0.0, Culture=neutral,              PublicKeyToken=b03f5f7f11d50a3a"/>
        </handlers>
    </system.webServer>
    

    第 2 步 - 在 global.asax 中添加路由表

    定义从友好 URL 到 aspx 页面的映射,保存请求的用户 ID 以供以后使用。

    void Application_Start(object sender, EventArgs e)
    {
        RegisterRoutes(RouteTable.Routes);
    }
    
    public static void RegisterRoutes(RouteCollection routes)
    {
        routes.Add("UseridRoute", new Route
        (
           "userid/{userid}",
           new CustomRouteHandler("~/users.aspx")
        ));
    }
    

    第 3 步 - 实现路由处理程序

    将包含参数的路由上下文传递给页面。 (注意IRoutablePage的定义)

    using System.Web.Compilation;
    using System.Web.UI;
    using System.Web;
    using System.Web.Routing;
    
    public interface IRoutablePage
    {
        RequestContext RequestContext { set; }
    }
    
    public class CustomRouteHandler : IRouteHandler
    {
        public CustomRouteHandler(string virtualPath)
        {
            this.VirtualPath = virtualPath;
        }
    
        public string VirtualPath { get; private set; }
    
        public IHttpHandler GetHttpHandler(RequestContext
              requestContext)
        {
            var page = BuildManager.CreateInstanceFromVirtualPath
                 (VirtualPath, typeof(Page)) as IHttpHandler;
    
            if (page != null)
            {
                var routablePage = page as IRoutablePage;
    
                if (routablePage != null) routablePage.RequestContext = requestContext;
            }
    
            return page;
        }
    }
    

    第 4 步 - 检索目标页面上的参数

    注意 IRoutablePage 的实现。

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Web;
    using System.Web.UI;
    using System.Web.UI.WebControls;
    using System.Web.Routing;
    
    public partial class users : System.Web.UI.Page, IRoutablePage
    {
        protected RequestContext requestContext;
    
        protected object RouteValue(string key)
        {
            return requestContext.RouteData.Values[key];
        }
    
        protected void Page_Load(object sender, EventArgs e)
        {
            string id = RouteValue("userid").ToString();
            switch (id)
            {
                case "1234":
                    lblUserId.Text = id;
                    lblUserName.Text = "Bill";
                    break;
                case "1235":
                    lblUserId.Text = id;
                    lblUserName.Text = "Claire";
                    break;
                case "1236":
                    lblUserId.Text = id;
                    lblUserName.Text = "David";
                    break;
                default:
                    lblUserId.Text = "0000";
                    lblUserName.Text = "Unknown";
                    break;
            }
        }
    
        #region IRoutablePage Members
    
        public RequestContext RequestContext
        {
            set { requestContext = value; }
        }
    
        #endregion
    }
    

    【讨论】:

    • 我对这个实现的运气比另一个好。 queryString 在使用 Ajax 时出现问题。这个实现有点复杂,但值得付出努力。
    【解决方案3】:

    这是使用 ASP.NET MVC 的另一种方法

    首先,这是包含两个操作的控制器代码。 index 从模型中获取用户列表,userid 获取单个用户:

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Web;
    using System.Web.Mvc;
    using System.Web.Mvc.Ajax;
    
    namespace MvcApplication1.Controllers
    {
        public class UsersController : Controller
        {
            public ActionResult Index()
            {
                return View(Models.UserDB.GetUsers());
            }
            public ActionResult userid(int id)
            {
                return View(Models.UserDB.GetUser(id));
            }
        }
    }
    

    这是 Index.asp 视图,它使用 ActionLink 以正确的格式创建链接:

    <%@ Page Language="C#" AutoEventWireup="true" CodeBehind="Index.aspx.cs" Inherits="MvcApplication1.Views.Index" %>
    <%@ Import Namespace="MvcApplication1.Controllers" %>
    <%@ Import Namespace="MvcApplication1.Models" %>
    
    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
    
    <html xmlns="http://www.w3.org/1999/xhtml" >
    <head runat="server">
        <title></title>
    </head>
    <body>
        <div>
        <h2>Index of Users</h2>
               <ul>
                <% foreach (User user in (IEnumerable)ViewData.Model) { %>
                     <li>
                           <%= Html.ActionLink(user.name, "userid", new {id = user.id })%>
                     </li>
                <% } %>
               </ul>
        </div>
    </body>
    </html>
    

    这是显示个人详细信息的 userid.aspx 视图:

    <%@ Page Language="C#" AutoEventWireup="true" CodeBehind="userid.aspx.cs" Inherits="MvcApplication1.Views.Users.userid" %>
    <%@ Import Namespace="MvcApplication1.Controllers" %>
    <%@ Import Namespace="MvcApplication1.Models" %>
    
    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
    <html xmlns="http://www.w3.org/1999/xhtml">
    <head runat="server">
        <title></title>
    </head>
    <body>
        <div>
            <table border ="1">
                <tr>
                    <td>
                    ID
                    </td>
                    <td>
                    <%=((User)ViewData.Model).id %>
                    </td>
                </tr>
                <tr>
                    <td>
                    Name
                    </td>
                    <td>
                    <%=((User)ViewData.Model).name %>
                    </td>
                </tr>
            </table>
        </div>
    </body>
    </html>
    

    最后为了完整起见,这里是模型代码:

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Web;
    
    namespace MvcApplication1.Models
    {
        public class UserDB
        {
            private static List<User> users = new List<User>{
                new User(){id=12345, name="Bill"},
                new User(){id=12346, name="Claire"},
                new User(){id=12347, name="David"}
            };
    
            public static List<User> GetUsers()
            {
                return users;
            }
    
            public static User GetUser(int id)
            {
                return users.First(user => user.id == id);
            }
    
        }
    
        public class User
        {
            public int id { get; set; }
            public string name { get; set; }
        }
    }
    

    【讨论】:

      【解决方案4】:

      我一直在使用 Intelligencia 的 URL 重写器:

      http://urlrewriter.net/

      配置非常简单 - 可能需要一个小时才能全部启动并运行。很少有问题...

      我会推荐它,但我应该提到我没有尝试过任何其他的。

      祝你好运!

      【讨论】:

        【解决方案5】:

        另外,请查看 ASP.NET MVC,或者如果您设置在 webforms 上,请查看 ASP.NET 3.5 SP1 中的新 System.Web.Routing 命名空间

        【讨论】:

          【解决方案6】:

          我为此问题开发了一个开源 NuGet 库,它隐式地将 EveryMvc/Url 转换为 every-mvc/url。

          虚线网址对 SEO 更友好且更易于阅读。小写 URL 往往会产生较少的问题。 (More on my blog post)

          NuGet 包:https://www.nuget.org/packages/LowercaseDashedRoute/

          要安装它,只需在 Visual Studio 中打开 NuGet 窗口,方法是右键单击项目并选择 NuGet 包管理器,然后在“在线”选项卡上键入“小写虚线”,它应该会弹出。

          或者,您可以在包管理器控制台中运行此代码:

          Install-Package LowercaseDashedRoute

          之后,您应该打开 App_Start/RouteConfig.cs 并注释掉现有的 route.MapRoute(...) 调用并添加它:

          routes.Add(new LowercaseDashedRoute("{controller}/{action}/{id}",
            new RouteValueDictionary(
              new { controller = "Home", action = "Index", id = UrlParameter.Optional }),
              new DashedRouteHandler()
            )
          );
          

          就是这样。所有的 url 都是小写的、破折号的,并且无需您做任何其他操作即可隐式转换。

          开源项目网址:https://github.com/AtaS/lowercase-dashed-route

          【讨论】:

            猜你喜欢
            • 2010-12-17
            • 1970-01-01
            • 2013-02-14
            • 2020-05-01
            • 2012-09-16
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多