在ASP.NET 4.0 Web form上使用Routing优化URL

大家都知道MVC里利用Routing的特性将地址映射到Controller和Action上,其实因为本身Routing是.Net
4.0内置的特性了,所以Web form上其实也可以适用的,今天我们就来看看如何做一下URL地址的优化,目的是将http://localhost/Customer.aspx?Id = 1优化成http://localhost/Custome/1的形式。

正文

首先,建立一个空的ASP.NET 4.0 Web form项目,建立Global.asax文件,在Glolal类里,我们添加如下代码:

namespace EasyURL
{
    public class Global : System.Web.HttpApplication
    {
        protected void Application_Start(object sender, EventArgs e)
        {
            RegisterRoutes(RouteTable.Routes);
        }

        public static void RegisterRoutes(RouteCollection routeCollection)
        {
            //routeCollection.MapPageRoute("RouteForCustomer", "Customer/{Id}", "~/Customer.aspx")

            // 可以使用上面的,但是最好使用下面的,这样可以限制Id为数字
            routeCollection.MapPageRoute("RouteForCustomer", "Customer/{Id}", "~/Customer.aspx", true, null, new RouteValueDictionary(new { Id = "\\d+" }));
        }
    }
}

然后添加一个Customer.aspx文件,代码非常简单,如下:

public partial class Customer : Page
{
    protected void Page_Load(object sender, EventArgs e)
    {
        string id = Page.RouteData.Values["Id"].ToString();
        Response.Write("<h1>Customer详细页</h1>");
        Response.Write(string.Format("CustomerID : {0}", id));
    }
}

注意我们是用Page.RouteData.Values["Id"]来取的值。

这样,当我们在访问http://localhost/customer/1的时候,就显示了我们预想的页面:

Customer详细页

CustomerID : 1

延伸一

其实上面的效果已经很简单的实现了,但是我们发现我们必须要用Page.RouteData.Values["Id"]这种形式来取值,而不是我们平时所用的Page.QueryString["Id"]来取,那我们能否做到这一点呢?

我们知道,在PageLoad之前Request的值都有初始化好的,所以如果我们要使用这种方式的时候,必须在这个周期之前将RouteData.Values的值都加到QueryString里,好,我们来试试,先建立一个PageBase基类(后面所有的页面都要继承此类),代码如下:

public abstract class PageBase : System.Web.UI.Page
{
    protected override void OnInitComplete(EventArgs e)
    {
        base.OnInitComplete(e);

        Page.RouteData.Values.Keys.ToList().ForEach(key =>
        {
            Request.QueryString.Add(key, Page.RouteData.Values[key].ToString());
        });
    }
}

运行之后,我们发现出了黄页:

Exception Details: System.NotSupportedException: Collection is read-only.

Source Error:

Line 20:             Page.RouteData.Values.Keys.ToList().ForEach(key =>
Line 21:             {
Line 22:                 Request.QueryString.Add(key, Page.RouteData.Values[key].ToString());
Line 23:             });
Line 24:         }

原来是QueryString这个集合是只读的,通过老赵的文章一个较完整的关键字过滤解决方案我们来改写一下代码:

public static class GlobalValues
{
    public static PropertyInfo NameObjectCollectionBaseIsReadOnly;

    static GlobalValues()
    {
        Type type = typeof(NameObjectCollectionBase);
        NameObjectCollectionBaseIsReadOnly = type.GetProperty(
            "IsReadOnly",
            BindingFlags.Instance | BindingFlags.NonPublic);
    }
}

public abstract class PageBase : System.Web.UI.Page
{
    protected override void OnInitComplete(EventArgs e)
    {
        base.OnInitComplete(e);

        // 将集合改成可写的
        GlobalValues.NameObjectCollectionBaseIsReadOnly.SetValue(Request.QueryString, false, null);

        Page.RouteData.Values.Keys.ToList().ForEach(key =>
        {
            // 添加RouteData.Values的name/value对添加到QueryString集合里
            Request.QueryString.Add(key, Page.RouteData.Values[key].ToString());
        });
    }
}

然后使用我们平时用的代码:

protected void Page_Load(object sender, EventArgs e)
{
    //string id = Page.RouteData.Values["Id"].ToString();
    string id = Request.QueryString["Id"];
    Response.Write("<h1>Customer详细页</h1>");
    Response.Write(string.Format("CustomerID : {0}", id));
}

运行一下,完美,啊哈!OK,在aspx里添加一个form表单,点击一个button几次试试,完蛋了,浏览器地址栏的地址变成了:

http://localhost/Customer/1?Id=1&Id=1&Id=1

原来是,由于我们每次都往QueryString里添加Id这个key,结果每次回发的时候就附加到URL上了,得想办法在页面结束以后从QueryString里删除这个key,由于在OnUnload周期Request/Response已经被清空了,所以我们要在之前的周期内处理,代码如下:

protected override void OnPreRenderComplete(EventArgs e)
{
    Page.RouteData.Values.Keys.ToList().ForEach(key =>
    {
        Request.QueryString.Remove(key);
    });

    base.OnPreRenderComplete(e);
}

照例运行,OK,完美,再试几下其它的case,也没什么问题。

注:由于好久不用web form做项目了,所以不太确信上述代码用的OnInitComplete/OnPreRenderComplete周期是否是合理的周期,目前运行起来是没有问题的,有时间再详细研究一下。

延伸二

延伸一的代码,颇为复杂,而且也不知道有没有副作用,其实实际项目中,一般我们都封装自己的GetParameter方法,所以其实我们可以这样用,相对就简单多了:

namespace EasyURL
{
    public abstract class PageBase : System.Web.UI.Page
    {
        public string GetQueryString(string key, string defaultValue = "")
        {
            if (Page.RouteData.Values.Keys.Contains(key))
                return Page.RouteData.Values[key].ToString();
            else if (string.IsNullOrWhiteSpace(Request.QueryString[key]))
                return Request.QueryString[key];
            else
                return defaultValue;
        }
    }

    public partial class Customer : PageBase
    {
        protected void Page_Load(object sender, EventArgs e)
        {
            string id = this.GetQueryString("id");
            Response.Write("<h1>Customer详细页</h1>");
            Response.Write(string.Format("CustomerID : {0}", id));
        }
    }
}

运行,没问题,而且也不存在在URL上再次附加?Id=1的问题了。

版权声明:本文为博主http://www.zuiniusn.com 原创文章,未经博主允许不得转载。

时间: 2024-08-13 14:35:14

在ASP.NET 4.0 Web form上使用Routing优化URL的相关文章

asp.net mvc vs web form

译者介绍 小小.NET学童,滴答…滴答…的雨…… 正文如下======================================================= 原文示例(VS2012): 1.  Download Simple WebForm demo - 6.7 KB 2.  Download Simple MVC Demo demo - 1.5 MB 介绍 我做为一名ASP.NET开发人员已经有很长时间了,并且我非常乐意使用ASP.NET Web Forms开发web应用程序. 在

(转载)Win7的IIS配置asp.net出现“由于 Web 服务器上的“ISAPI 和 CGI 限制”列表设置,无法提供您请求的页面。

点击,[应用程序池]上面的IIS根目录,然后选择右边的[ISAPI 和 CGI 限制设置],最后,所有选项都设置成启动就行了!

ASP.NET 4.0尚未在 Web 服务器上注册 解决方法

ASP.NET 4.0尚未在 Web 服务器上注册 解决方法 使用VS2010创建web应用程序时出现如下提示ASP.NET 4.0尚未在 Web 服务器上注册.为了使网站正确运行,可能需要手动将 Web 服务器配置为使用 ASP.NET 4.0,按 F1 可了解更多详细信息 解决方法: 首先设置IIS应用程序池 net framework版本为4.0 然后  开始->所有程序->附件->鼠标右键点击“命令提示符”->以管理员身份运行->%windir%\Microsoft.

尚未在 Web 服务器上注册 ASP.NET 4.0” 的解决办法

http://www.sowsoy.com/topics-537.html win7,vs2010创建.NetFramework 4框架下的Asp.Net空网站.系统提示 “尚未在 Web 服务器上注册ASP.NET 4.0.为了使网站正确运行,可能需要手动将 Web 服务器配置为使用 ASP.NET4.0,按 F1 可了解更多详细信息.” 出现这个错误是因为IIS 7 采用了更安全的Web.Config管理机制,默认情况下会锁住配置项不允许更改. 修改方法: 1.win+r 运行 C:\WIN

Win10 兼容性 Visual studio web应用程序 ASP.NET 4.0 尚未在 Web 服务器上注册

我原先的win8系统,vs2012打开解决方案还不会报asp.net4.0未在web服务器上注册这个错误,更新win10后,vs2012总是报这个问题 后来在网上找到了答案,分享给需要的朋友,原因是win10跟vs2012不兼容,解决方法一:下载补丁KB3002339或者方法二:直接用vs2015. 这个是在这个博客看到的,http://blog.csdn.net/luozhuang/article/details/47810703 补丁下载官方地址是:http://www.microsoft.

解决Win10 中打开VS2012 出现“ASP.NET 4.0 尚未在 Web 服务器上注册”

系统升级为win10后,在使用vs2012打开原来的项目时,会出现"ASP.NET 4.0 尚未在 Web 服务器上注册"的问题,如图: 想到在win8.1系统下,也出现过同样的问题,就直接使用命令提示符工具注册ASP.NET4.0,以管理员身份运行命令提示符工具并执行以下代码 C:\WINDOWS\Microsoft.NET\Framework64\v4.0.30319\aspnet_regiis.exe -i 执行后,发下这种方式不管用了,头疼 按照提示在Windows功能中安装I

尚未在 Web 服务器上注册 ASP.NET 2.0。为了使网站正确运行,可能需要手动将 Web 服务器配置为使用 ASP.NET 2.0,按 F1 可了解更多详细信息。

装了win7操作系统后,vs2010运行项目后出现“尚未在 Web 服务器上注册 ASP.NET 2.0.为了使网站正确运行,可能需要手动将 Web 服务器配置为使用 ASP.NET 2.0,按 F1 可了解更多详细信息.”的提示,点击确定后项目可以编译成功,但是在浏览器上运行时却提示“HTTP 错误 500.19 - Internal Server Error 无法访问请求的页面,因为该页的相关配置数据无效.” 错误代码 0x80070021 这个错误是因为IIS 7 采用了更安全的Web.C

在IIS7.5上添加.NET4.0程序的虚拟目录时提示ASP.NET 4.0尚未在 Web 服务器上注册

使用VS2010创建web应用程序时出现如下提示: ASP.NET 4.0尚未在 Web 服务器上注册. 解决方法: 首先IIS应用程序池添加 net framework4.0版本. 接着找到C:\Windows\Microsoft.NET\Framework\v4.0.30319 这个目录 然后  开始->所有程序->附件->鼠标右键点击“命令提示符”CMD->以管理员身份运行- >CD\ >CD C:\Windows\Microsoft.NET\Framework\

ASP.NET 4.0尚未在Web服务器上注册。您需要手动将Web服务器配置为使用ASP.NET,这样您的网站才能正确运行。

问题:之前IIS是安装好的,ASP.NET 4.0是注册好的(不是以管理员的身份注册),搞项目一直没有问题.现在,换了项目,项目一打开一直报这个问题,有几个Web层,就报几次,而且项目没有办法正常的运行.各种鼓捣,cmd 重新注册ASP.NET 4.0,不管用,后卸掉IIS重装,重新注册ASP.NET 4.0还是不行,请了各种大神也解决不了,无奈最后重装了系统,先安装IIS,后以管理员的身份运行cmd注册ASP.NET 4.0,问题解决了. 解决方案:以管理员的身份运行cmd,注册ASP.NET