网络编程 | 站长之家 | 网页制作 | 图形图象 | 操作系统 | 冲浪宝典 | 软件教学 | 网络办公 | 邮件系统 | 网络安全 | 认证考试 | 系统进程
Firefox | IE | Maxthon | 迅雷 | 电驴 | BitComet | FlashGet | QQ | QQ空间 | Vista | 输入法 | Ghost | Word | Excel | wps | Powerpoint
asp | .net | php | jsp | Sql | c# | Ajax | xml | Dreamweaver | FrontPages | Javascript | css | photoshop | fireworks | Flash | Cad | Discuz!
当前位置 > 网站建设学院 > 网络编程 > ASP.NET技巧
Tag:注入,存储过程,分页,安全,优化,xmlhttp,fso,jmail,application,session,防盗链,stream,无组件,组件,md5,乱码,缓存,加密,验证码,算法,cookies,ubb,正则表达式,水印,索引,日志,压缩,base64,url重写,上传,控件,Web.config,JDBC,函数,内存,PDF,迁移,结构,破解,编译,配置,进程,分词,IIS,Apache,Tomcat,phpmyadmin,Gzip,触发器,socket
网络编程:ASP教程,ASP.NET教程,PHP教程,JSP教程,C#教程,数据库,XML教程,Ajax,Java,Perl,Shell,VB教程,Delphi,C/C++教程,软件工程,J2EE/J2ME,移动开发
本月文章推荐
.asp.net 2.0小TIPS两则.
.正确实现 IDisposable 接口.
..NET扫描远程计算机注册表.
.应用lucene.net进行搜索测试.
.Asp.net(c#)实现多线程断点续传.
.IIS7 会重用那些不该重用 HttpHa.
.有关TextBox中输入字符控制的一种.
.在Asp.net的HttpCookie中写入汉字.
.包含实时功能的ASP.NET系统结构 .
..Net 下信号量(Semaphore)的一种.
.分享个极好的无刷新二级联动下拉.
.asp.net 2.0 上传控件的使用.
.ASP.NET 2.0防止同一用户同时登陆.
.asp.net如何连接sql server2000数.
.如何实现无刷新的DropdownList联.
.实现在页面中单击按钮关闭页面.
.使用ASP.NET2.0的ReportViewer查.
.DNGuard 一款DotNet内核级加密保.
.用ASP/ASP.NET实现网络空间管理.
.ASP.NET实现下拉框二级联动组件.

UpdatePanel与UrlRewrite

发表日期:2006-12-27


  今天收到邮件,被问及为什么UpdatePanel如果结合了UrlRewrite就会出现问题。一开始我不以为然,由于我也曾经在UrlRewrite时使用过UpdatePanel,没有出现过问题。但是收到对方打包的代码后,发现这个问题的确重现了,如果直接访问目标页面就不会有任何问题。因为当时在公司,没有仔细地去研出错的原因。在回家的路上,脑子里一遍一遍地模拟着UpdatePanel的实现过程,却没有察觉到有任何不妥。最后还是忍不住,坐在公交车上的时候就打开笔记本,仔细的寻找问题所在。公交车实在晃得厉害,还好最终在我呕吐之前找到了问题,刚才的思考还是棋差一着。

 
重现问题:

  现在我将重现那个问题。在原来的代码中使用了NBear的UrlRewriteModule,为了简单起见,我使用了最普通的UrlRewrite的做法来得到相同的效果,尽量避免有些朋友(包括我)因为不熟悉NBear而妨碍文章内容的理解。

  首先,新建一个ASP.NET AJAX Enabled Web Site。创建一个文件~/SubFolder/Target.aspx,内容如下:

~/SubFolder/Target.aspx
<html xmlns="http://www.w3.org/1999/xhtml" >
<head runat="server">
    <title>Target Page</title>
</head>
<body>
    <form id="form1" runat="server">
        <asp:ScriptManager ID="ScriptManager1" runat="server">
        </asp:ScriptManager>
       
        <asp:UpdatePanel ID="UpdatePanel1" runat="server">
            <ContentTemplate>
                <%= DateTime.Now.ToString() %>
                <asp:Button ID="Button1" runat="server" Text="Refresh" />
            </ContentTemplate>
        </asp:UpdatePanel>
    </form>
</body>
</html>
 

  然后再创建一个Global.asax,提供Application_BeginRequest方法,在其中实现Url Rewrite,如下:

Global.asax中Application_BeginRequest方法
void Application_BeginRequest(object sender, EventArgs e)
{
    HttpContext context = (sender as HttpApplication).Context;
    if (context.Request.Path.Contains("Source.aspx"))
    {
        context.RewritePath("SubFolder/Target.aspx", false);
    }
}
 

  这样,当我们访问~/Source.aspx文件时,则会被Rewrite至~/SubFolder/Target.aspx,打开页面,一切正常:


  点击Refresh按钮之后,时间被更新了。然后当我们再点击按钮之后,错误发生了:“Sys.WebForms.PageRequestManagerServerErrorException: An unknown eror occurred while processing the request on the server. The status code returned from the server was: 12031”。

 

分析问题:

  发生这个问题的原因是因为Url Rewrite更新了Form提交的地址,而UpdatePanel又将这地址的改变反映到了页面上。

  在第一次打开页面时,我们可以看到页面的源文件中<form />元素的action已经不是我们访问的Source.aspx,而是Url Rewrite后的目标文件:

form元素的action为目标页面
...
<form name="form1" method="post" action="SubFolder/Target.aspx" id="form1">
...
</form>
...

  还好我们使用了Partial Rendering,只要“目标”是正确的,UpdatePanel依旧能够正确地发送和获取数据,然后更新页面。因此,在点击Refresh按钮之后,页面被正确更新了。可是,我们form元素的action也变了,使用Web Development Helper和IE Dev Toolbar便一目了然:


  由于我们在进行异步PostBack时,直接访问了~/SubFolder/Target.aspx,因此在生成的Form对象其action值为Target.aspx。于是乎,UpdatePanel兢兢业业地将客户端form元素的action也进行了修改。这样就让我们再次提交时访问了一个不存在的页面,错误就再所难免了。

 

解决问题:

  既然发现了问题所在,那么解决起来自然也会得心应手。我们只要在响应Sys.Application的load事件即可,它会在页面第一次加载时,以及每次Partial Rendering之后被触发,我们在这时候修改页面中form元素的action属性即可,如下:

相应Sys.Application的load事件
Sys.Application.add_load(function()
{
    var form = Sys.WebForms.PageRequestManager.getInstance()._form;
    form._initialAction = form.action = window.location.href;
});
 
  至于为什么应该这样获得页面中的form元素,_initialAction又是什么,以及为什么要设置它,就要牵涉到UpdatePanel的实现方式,在这里就不多作解释了。只要页面中放置了这么一小段代码,这个问题就被解决了。

 

深入问题:

  造成这个问题的原因,其实就是因为在Url Rewrite之后,form元素的action并非客户端请求的地址,而是Url Rewrite的目标地址。如果我们没有使用Partial Rendering,而是使用了最传统的PostBack,虽然不会造成页面功能的破坏,但是在PostBack之后,用户就会发现地址栏的内容变了,直接变成了目标地址。这可不是我们希望看到的结果,既然Rewrite了,就把它Rewrite到底。当然,我们依然可以使用上面提到的办法,使用JavaScript来修改form元素的action,但是这个做法实在不够“美观大方”,而且用户从HTML源文件中也可以看到我们Url Rewrite的目标地址,不是吗?

  如果我们能够在服务器端设置Form的action就好了,可惜System.Web.UI.HtmlControls.HtmlForm类不允许我们这么做。不过还好,我们用的是ASP.NET,我们用的是面向对象的编程模型。于是我们“继承”System.Web.UI.HtmlControls.HtmlForm,实现一个自己的Form控件:

继承HtmlForm类实现自己的From
namespace ActionlessForm {
    public class Form : System.Web.UI.HtmlControls.HtmlForm
    {
        protected override void RenderAttributes(HtmlTextWriter writer)
        {
            writer.WriteAttribute("name", this.Name);
            base.Attributes.Remove("name");
            writer.WriteAttribute("method", this.Method);
            base.Attributes.Remove("method");
            this.Attributes.Render(writer);
            base.Attributes.Remove("action");
            if (base.ID != null)
            writer.WriteAttribute("id", base.ClientID);
        }
    }
}
 
 

  然后我们就可以在页面中使用它了。当然,在这之前,我们需要在页面(或Web.config)里注册它:

使用我们自己实现的Form
<%@ Register TagPrefix="skm" Namespace="ActionlessForm"
    Assembly="ActionlessForm" %>
...
<skm:Form id="Form1" method="post" runat="server">
...
</skm:Form>
...
 

  至此,我们已经不需要在页面里编写一段“巧妙”的JavaScript了,Url Rewrite之后form元素的action问题被解决了。

  (“深入问题”参考了MSDN上一篇文章的部分内容:http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnaspp/html/urlrewriting.asp
http://www.cnblogs.com/JeffreyZhao/archive/2006/12/27/updatepanel_with_url_rewrite.html

上一篇:使用WebClient自动填写并提交ASP.NET页面表单 人气:4550
下一篇:ASP.NET2.0中用ICallbackEventHandler实现客户端与服务器端异步交互 人气:4066
浏览全部UrlRewrite的内容 Dreamweaver插件下载 网页广告代码 祝你圣诞节快乐 2009年新年快乐