一步一步实战扩展 ASP.NET Route,实现小写 URL、个性化 URL

摘要:
ASP。NETRoute实现小写URL和个性化URL NETMVC有任何扩展要求吗?无论如何,我有很多。好吧,让我们停止胡说八道。今天我将演示如何扩展ASPNETRoute,希望能对您有所帮助。通常,除非在开发过程中手动将Controller和Action的名称设置为小写,或者在Action方法上标记ActionNameAttribute,否则很难实现没有扩展名的完全小写URL。

一步一步实战扩展 ASP.NET Route,实现小写 URL、个性化 URL

介绍

 

不知道大家在使用 ASP.NET MVC 时有没有一些扩展要求,反正我是有很多。在使用 MVC 这几年(PS:我是从 1.0 开始学,2.0、3.0 开发至今),我深深地觉得 MVC 的扩展性真是太好了,几乎你大部分的“合理”需求,用 MVC 都能实现。好了,废话不多说了,今天我就实战演示如何扩展 ASP.NET Route,希望能帮助到你。

 

小写 URL

 

我想很多朋友和我一样,使用 ASP.NET MVC 时都想要小写的 URL。一般除非你在开发时手动把 Controller、Action 的名字建成小写,或者在 Action 方法上标记 ActionNameAttribute,否则如果不经过扩展,很难实现完全的小写 URL。把 Controller、Action 的名字建成小写不符合 C# 编码规范,当然如果你忽略这个规范,我也没有办法。另一方面,在 Action 方法上标记 ActionNameAttribute 工作量又太大,又不利于统一维护。至于为什么要小写的 URL,我想是一种习惯吧,仔细观察各大网站,你就会发现,小写的 URL 是主流。

 


个性 URL

 

实现完小写 URL 后,我还有一个特殊的 URL 规则要求,就是生成 A 元素的 URL 时,把 Action 的名字中的下划线(_)替换成减号(-),并且服务器端 ASP.NET MVC 能处理这个请求。打一个比如:

 

复制代码
public class HomeController : Controller
{
    /// <summary>
    /// 添加产品信息,可以通过访问 URL:/home/add-product-information
    /// </summary>
    /// <returns></returns>
    public ActionResult Add_Product_Information()
    {
        return View();
    } 
}
复制代码

 

上面的例子,大家注意到了吗,我希望使用 @Url.Action("Add_Product_Information") 能生成 /home/add-Product-Information 格式的 URL,并且还能访问。很多朋友可能想到了,以为通过简单的在 Global.asax 中配置路由可以实现,经过本人的实测,是无法实现的,因为配置路由时,比如: "{controller}/{action}/{id}" 这里的 {action} 是作为一个整体,而无法再把它拆分。像这种就只能通过扩展 Route 来实现了。 作者(音乐让我说)博客地址:http://music.cnblogs.com

 

开始实战

 


1. 建立一个 LowercaseRoute,继承 System.Web.Routing.Route 类

 

在这个 LowercaseRoute 类里,我们需要做的是添加和 Route 类相似的构造函数,并且重写 GetVirtualPath 方法。关键代码如下:

 

复制代码
public override VirtualPathData GetVirtualPath(RequestContext requestContext, RouteValueDictionary values)
{
    VirtualPathData virtualPath = base.GetVirtualPath(requestContext, values); // 由 MVC 默认生成的 URL,比如:/Home/Add_Product_Information
    if (virtualPath != null)
    {
        string virtualPathValue = virtualPath.VirtualPath; // 获取比如:/Home/Add_Product_Information
        int length = virtualPathValue.LastIndexOf("?");
        if (length == 0) return virtualPath;
        if (length > 0)
        {
            string url1 = virtualPathValue.Substring(0, length).ToLowerInvariant(); // 把 controller 和 action 小写
            string url2 = virtualPathValue.Substring(length); // 保留 ? 后的参数
            virtualPath.VirtualPath = url1 + url2; // 连接,比如:/home/add-product-information
            return virtualPath;
        }
        virtualPath.VirtualPath = virtualPath.VirtualPath.ToLowerInvariant();
    }
    return virtualPath;
}
复制代码

 

以上这个类会在当你在 View、Controller 中调用 Url.Action("Add_Product_Information")、Html.ActionLink("Add_Product_Information") 时调用。

 


2. 建立一个 UnderlineRoute,继承 LowercaseRoute 类

 

上面那个 LowercaseRoute 类仅仅是实现 URL 小写的需求,而现在这个 UnderlineRoute 才是在小写 URL 的基础上再实现个性化的 URL 需求(PS:就是本文开头介绍的,要把 Action 的名称中带有下划线的替换成减号)。作者(音乐让我说)博客地址:http://music.cnblogs.com

 

首先,依旧添加和 LowercaseRoute 类相似的构造函数,然后重写 GetVirtualPath 方法。完成代码如下:

 

复制代码
public class UnderlineRoute : LowercaseRoute
{
    public const string UNDERLINE_STRING = "_";
    public const string SUBTRACTION_SIGN = "-";

    public UnderlineRoute(string url, IRouteHandler routeHandler)
        : base(url, routeHandler)
    {
    }

    public UnderlineRoute(string url, RouteValueDictionary defaults, IRouteHandler routeHandler)
        : base(url, defaults, routeHandler)
    {
    }

    public UnderlineRoute(string url, RouteValueDictionary defaults, RouteValueDictionary constraints, IRouteHandler routeHandler)
        : base(url, defaults, constraints, routeHandler)
    {
    }

    public UnderlineRoute(string url, RouteValueDictionary defaults, RouteValueDictionary constraints, RouteValueDictionary dataTokens, IRouteHandler routeHandler)
        : base(url, defaults, constraints, dataTokens, routeHandler)
    {
    }

    public override VirtualPathData GetVirtualPath(RequestContext requestContext, RouteValueDictionary values)
    {
        string action = (string)values["action"];
        if(action != null)
        {
            if (action.Contains(UNDERLINE_STRING))
            {
                values["action"] = action.Replace(UNDERLINE_STRING, SUBTRACTION_SIGN);
            }
        }
        // 以上的这小块代码就是生成 URL 时,把 RequestContext 中的 RouteData 中的 action 参数给替换,
        // 把 action 的名字中带有下划线(_)的替换成减号(-)
        return base.GetVirtualPath(requestContext, values);
    }

    /// <summary>
    /// 替换成下划线
    /// </summary>
    /// <param name="requestContext"></param>
    public static void ReplaceUnderlineToSubtractionSignInRouteData(RequestContext requestContext)
    {
        if (requestContext == null)
        {
            throw new ArgumentNullException("requestContext");
        }
        // 以上的这小块代码就是当处理请求时,把 RequestContext 中的 RouteData 中的 action 参数给替换回来。
        // 把请求的路由中的 action 参数給替换回来,把 action 的名字中带有减号(-)的替换成下划线(_)
        string actionName = (string)requestContext.RouteData.Values["action"];
        if (actionName != null)
        {
            if (actionName.Contains(UnderlineRoute.SUBTRACTION_SIGN))
            {
                requestContext.RouteData.Values["action"] = actionName.Replace(UnderlineRoute.SUBTRACTION_SIGN, UnderlineRoute.UNDERLINE_STRING);
            }
        }
    }
} 
复制代码

 

3. 建立相应的 RouteHandler。

 

如果您建立的项目是 MVC,则建立 UnderlineMvcRouteHandler 类,继承 MvcRouteHandler 类。(PS:WebForms 可以忽略)

 

如果您建立的项目是传统的 WebForm,则建立 UnderlinePageRouteHandler 类,继承 PageRouteHandler 类。(PS:MVC 可以忽略)

 

代码如下:

 

复制代码
public class UnderlineMvcRouteHandler : MvcRouteHandler
{
    public UnderlineMvcRouteHandler() :base()
    {
    }

    public UnderlineMvcRouteHandler(IControllerFactory controllerFactory): base(controllerFactory)
    {
    }

    protected override IHttpHandler GetHttpHandler(RequestContext requestContext)
    {
        UnderlineRoute.ReplaceUnderlineToSubtractionSignInRouteData(requestContext); // 调用 UnderlineRoute 类处理
        return base.GetHttpHandler(requestContext);
    }
}



public class UnderlinePageRouteHandler : PageRouteHandler
{
    public UnderlinePageRouteHandler(string virtualPath) : base(virtualPath)
    {
    }

    public UnderlinePageRouteHandler(string virtualPath, bool checkPhysicalUrlAccess) : base(virtualPath, checkPhysicalUrlAccess)
    {
    }

    public override IHttpHandler GetHttpHandler(RequestContext requestContext)
    {
        UnderlineRoute.ReplaceUnderlineToSubtractionSignInRouteData(requestContext); // 调用 UnderlineRoute 类处理
        return base.GetHttpHandler(requestContext);
    }
}
复制代码

 

4. 扩展 RouteCollection 类的 MapRoute 方法。

 

在配置路由时,默认是调用 MapRoute 方法,而这个方法默认是由 MvcRouteHandler(PS: WebForm 默认是 PageRouteHandler),所以为了让我们配置的路由默认由 UnderlineMvcRouteHandler 
(WebForm 默认是 UnderlinePageRouteHandler)来处理,我们再添加几个和 MapRoute 相似的方法。

 

对于 MVC 项目,我们添加几个名叫 MapRouteUnderline 的重载。

 

复制代码
public static Route MapRouteUnderline(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");
    }
    // 注意:
    //       1. 这里使用的 Route 是 UnderlineRoute
    //       2. 这里使用的 RouteHandler 是 UnderlineMvcRouteHandler
    UnderlineRoute item = new UnderlineRoute(url, new UnderlineMvcRouteHandler())
    {
        Defaults = new RouteValueDictionary(defaults),
        Constraints = new RouteValueDictionary(constraints),
        DataTokens = new RouteValueDictionary(namespaces)
    };
    if (namespaces != null && namespaces.Length > 0)
    {
        item.DataTokens["Namespaces"] = namespaces;
    }
    routes.Add(name, item);
    return item;
}
复制代码

 

对于 WebForms 项目,我们添加几个名叫 MapRouteUnderline 的重载。  

 

复制代码
public static Route MapPageRouteUnderline(this RouteCollection routes, 
    string routeName, 
    string routeUrl, 
    string physicalFile, 
    bool checkPhysicalUrlAccess, 
    RouteValueDictionary defaults, 
    RouteValueDictionary constraints, 
    RouteValueDictionary dataTokens)
{
    if (routes == null)
    {
        throw new ArgumentNullException("routes");
    }
    if (routeUrl == null)
    {
        throw new ArgumentNullException("routeUrl");
    }
    // 注意:
    //       1. 这里使用的 Route 是 UnderlineRoute
    //       2. 这里使用的 RouteHandler 是 UnderlinePageRouteHandler
    UnderlineRoute item = new UnderlineRoute(routeUrl, 
        defaults, 
        constraints, 
        dataTokens, 
        new UnderlinePageRouteHandler(physicalFile, checkPhysicalUrlAccess)
    );
    routes.Add(routeName, item);
    return item;
}
复制代码

 

5. 在 Global.asax 中配置路由

 

这一步是关键,要让我们上面自定义的 Route 和 RouteHandler 生效,就必须在配置路由时,调用我们自定义的 MapRouteUnderline 和 MapPageRouteUnderline 方法。

 

复制代码
//作者(音乐让我说)博客地址:http://music.cnblogs.com
public static void RegisterRoutes(RouteCollection routes)
{
    routes.IgnoreRoute("{resource}.axd/{*pathInfo}");

    // 请注意:这里调用的是 MapPageRouteUnderline 扩展方法
    routes.MapPageRouteUnderline("adminDefault",
        "{controller}/{action}",
        "~/admin/{action}.aspx",
        true, null, new RouteValueDictionary(new { controller = "admin" }));

    // 请注意:这里调用的是 MapRouteUnderline 扩展方法
    routes.MapRouteUnderline(
        "Default", // 路由名称
        "{controller}/{action}/{id}", // 带有参数的 URL
        new { controller = "Home", action = "Index", id = UrlParameter.Optional } // 参数默认值
    );
}
复制代码

 

截止到这里,关键代码都已经给出了,接下来就是检验我们的代码。

 

6. 建立测试用的 Action

 

在 HomeController 中建立一个名叫 Add_Product_Information 的 Action 方法。并建立 cshtml 视图,视图里面随便敲几句话就可以了。

 

复制代码
//作者(音乐让我说)博客地址:http://music.cnblogs.com
public class HomeController : Controller
{
    /// <summary>
    /// 添加产品信息,可以通过访问 URL:/home/add-product-information
    /// </summary>
    /// <returns></returns>
    public ActionResult Add_Product_Information()
    {
        return View();
    } 
}
复制代码

 

7. 在项目的根目录建立一个名叫 admin 的文件夹。

 


再在 admin 文件夹下建立 hello.aspx、add_product_information.aspx 至于里面的内容,随便敲几句话就可以了。

 


8. 在视图中测试,生成 URL

 

复制代码
<ul id="menu">
    <li>@Html.ActionLink("主页", "Index", "Home")</li>
    <li>@Html.ActionLink("关于", "About", "Home")</li>
    <li>@Html.ActionLink("添加产品信息", "Add_Product_Information", "Home")</li>
    <li>
        @Html.ActionLink("后台 - 欢迎页", "Hello", "Admin")
    </li>
    <li>
        @Html.ActionLink("后台 - 添加产品信息", "Add_Product_Information", "Admin")
    </li>
</ul>
复制代码

 

9. 运行

 

解决方案截图如下:

 

一步一步实战扩展 ASP.NET Route,实现小写 URL、个性化 URL第19张

 

一步一步实战扩展 ASP.NET Route,实现小写 URL、个性化 URL第20张

 

一步一步实战扩展 ASP.NET Route,实现小写 URL、个性化 URL第21张

 

一步一步实战扩展 ASP.NET Route,实现小写 URL、个性化 URL第22张

 

一步一步实战扩展 ASP.NET Route,实现小写 URL、个性化 URL第23张

 

以上 MVC 生成的链接都小写了,并且把下划线(_)也替换成了减号(-)。运行时,也正常的呈现出来!

 


本文只是起一个穿针引线的作用,无法要求读者也有这样的要求,仅仅为了演示,希望和大家一起进步,如有不妥,请多多包涵,并欢迎指出!

 

作者(音乐让我说)博客地址:http://music.cnblogs.com  

 

示例代码下载:点我下载

 

如果您觉得本文不错,麻烦点一下“推荐”,谢谢!

免责声明:文章转载自《一步一步实战扩展 ASP.NET Route,实现小写 URL、个性化 URL》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇SSM-CRUDvc6开发ActiveX并发布全攻略(一)(转)下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

熟悉Hbase常用命令及操作

(一) 编程实现以下指定功能,并用Hadoop提供的HBase Shell命令完成相同任务: 列出HBase所有的表的相关信息,例如表名; 在终端打印出指定的表的所有记录数据; 向已经创建好的表添加和删除指定的列族或列; 清空指定的表的所有记录数据; 统计表的行数。 (二)HBase数据库操作 1.现有以下关系型数据库中的表和数据,要求将其转换为适合于HB...

iOS Document Interaction(预览和打开文档) 编程指南

原文:http://developer.apple.com/library/ios/#documentation/FileManagement/Conceptual/DocumentInteraction_TopicsForIOS/Introduction/Introduction.html   关于 DocumentInteraction   iOS支持...

[C#]通过调用Word模板(Doc、dot)直接打印

通过替换模板中的指定 书签 来进行内容的替换、整合,然后直接发送到打印打印,也可以导出。即把打印出的语句换成保存函数。 public static classmyPrintByOffice { public static voidbyDoc(Stringtime,Stringuid) { Microsoft.Office.Interop.Word.Appl...

java生成解析xml的另外两种方法Xstream

Xstream生成和解析xm和JAXB生成和解析xml的方法。 一,Xstream Xstream非jdk自带的,需要到入Xstream-1.4.3.jar和xpp3_min-1.1.4.jar 1.Xstream简介;  使用限制: JDK版本不能<1.5. 虽然预处理注解是安全的,但自动侦查注解可能发生竞争条件. 特点: 简化的API; 无映射文...

Springboot项目集成JPush极光推送(Java SDK)

1.由于项目的需求,需要在Android APP上实现消息推送功能,所以引用了极光推送(官网:https://www.jiguang.cn/,  文档:http://docs.jiguang.cn/) 2.极光推送是经过考验的大规模app推送平台,极光推送目前每天推送消息数超过20亿条。 开发者集成SDK后,可以通过调用API推送消息。同时,极光推送提供可...

浅谈JEECG多数据源的使用

首先,简单的介绍下什么是JEECG。JEECG(J2EECode Generation)是一款基于代码生成器的免费开源的快速开发平台,使用JEECG可以简单快速地开发出企业级的Web应用系统。JEECG提倡简单功能由代码生成器直接生成,复杂业务采用表单自定义,业务流程使用工作流来实现、扩展出任务接口,由开发者编写特殊业务逻辑。 下面我们重点讲解下JEECG...