您的位置:首页 > 编程语言 > ASP

ASP.NET AJAX(服务器控件 UpdatePanel、Timer、UpdateProgress)

2013-01-06 14:59 579 查看
ASP.NETAJAX对Web服务特性为客户端代码访问服务器提供了一个可贵的窗口。但你要做大多数的困难任务,必须精心打造Web方法、合适的时机调用它们、适当更新页面、除了JavaScript什么都不能用。对于复杂的呈现,这个过程就十分单调。

由于这个原因,ASP.NET提供了一个更高层的服务器模型,它提供可以直接在Web窗体里使用的控件和组件,你可以完全使用服务器端代码工作

ASP.NETAJAX控件会自动注入客户端脚本,在幕后使用ASP.NETAJAX脚本库。与手动编写js代码相比,潜在的缺点是降低了灵活性。

在这篇文章里,我将介绍ASP.NET框架中的3个ASP.NETAJAX控件:UpdatePanel、Timer、UpdateProgress。所有这些控件都支持局部呈现,可以不经过完整回发无缝地更新页面内容,这是Ajax的关键概念。

UpdaePanel的局部呈现

UpdaePanel能让你使用服务器端逻辑处理普通页面并以无闪动的Ajax风格刷新自己。

基本思想是把Web页面分解为一到多个独立的区域,其中每个区域都包含在一个不可见的UpdaePanel里。当UpdaePanel中发生通常会触发一次回发的事件时,UpdaePanel截取该回发事件代之以执行一次异步回调

下面是它发生过程的一个示例步骤:

用户单击UpdaePanel里的一个按钮

一些客户端js代码(由ASP.NETAJAX生成)截取到单击事件并执行一次服务器回调

在服务器端,页面周期正常执行,所有常规事件正常发生。

最终,页面被呈现为HTML返回浏览器

客户端js得到完整的HTML并更新页面上所有的UpdaePanel(如果变更的内容不在UpdaePanel里,就会被忽略)

UpdaePanel控件和ScriptManager控件一起工作。在使用UpdaePanel前,需要把ScriptManager.EnablePartialRendering属性设置为true(默认值),然后才可以向页面添加UpdaePanel控件(放在ScriptManager之后)。

把控件拖到UpdaePanel时,内容出现在<ContentTemplate>节,如下:

<asp:ScriptManagerID="ScriptManager1"runat="server"EnablePartialRendering="true">


</asp:ScriptManager>


<asp:UpdatePanelID="UpdatePanel1"runat="server">


<ContentTemplate>


<asp:LabelID="Label1"runat="server"Text="Label"></asp:Label>


<asp:ButtonID="Button1"runat="server"Text="Button"/>


</ContentTemplate>


</asp:UpdatePanel>


UpdaePanel是一个基于模板的控件。呈现自身时,它把自己的ContentTemplate节的内容复制到页面上,因此,不能通过UpdaePanel.Controls集合动态添加控件,而要通过UpdaePanel.ContentTemplateContainer.Controls集合,这点请注意

UpdaePanel并非继承自Panel,而是直接继承Controls。在其生命周期里只有一个角色:作为异步刷新内容的容器。UpdaePanel没有可视界面,不支持样式设置。如果要在UpdaePanel之外显示边框或者修改背景颜色,那么需要在UpdaePanel里放置一个普通的Panel或DIV标签

UpdaePanel把自身呈现为<div>标签。但如果设置RenderMode属性由Block改为Inline,可以配置UpdaePanel自身呈现为嵌入元素。如果要创建的UpdaePanel处于段落中或者其他块元素中,就可以进行这样的设置。

下图显示包含3个UpdaePanel控件的示例页面,每个UpdaePanel都包含相同的内容:一个Label和一个Button控件。每次页面传送到服务器时,Page.Load事件触发:

protectedvoidPage_Load(objectsender,EventArgse)


{


Label1.Text=DateTime.Now.ToLongTimeString();


Label2.Text=DateTime.Now.ToLongTimeString();


Label3.Text=DateTime.Now.ToLongTimeString();


}






这个页面显示了异步回调无闪动刷新,单击任一按钮,3个标签都会安静的更新。唯一的例外是浏览器不支持XMLHttpRequest对象时,UpdaePanel会自动降级为使用完整页面回发。

1.错误处理

UpdaePanel执行异步回调后,Web页面代码完全按页面被回发时那样运行。唯一的区别在于:

通信方式:页面通过一个XMLHttpRequest异步调用获取新数据

接收到的数据的处理方式:UpdaePanel刷新自身内容,页面其余部分保持不变

同步回发中可能发生的问题也完全会在执行异步回发时发生,添加下列代码测试:

if(IsPostBack)


thrownewApplicationException("Thisoperationfailed.");


Web页面抛出一个未处理的异常时,ScriptManager捕获这个错误并回传给客户端,然后ASP.NETAJAX客户端库在页面中抛出一个JavaScript错误。下一步发生什么取决于浏览器的设置。如果启用了脚本调试,VS会在产生错误的那一行中断。如果没有使用脚本调试,浏览器可能通知也可能不通知你发生了一个问题。现在大多数浏览器都被配置为忽略JavaScript错误。对于IE,会在状态栏左下角出现“页面错误”消息。







使用客户端js处理错误可以改变这一行为。为此,你需要为System.Web.PageRequestManager类的endRequest事件注册一个回调PageRequestManager是ASP.NETAJAX应用程序模型的核心部分,它管理UpdaePanel控件的刷新过程并在页面的生命周期各个阶段触发客户端事件

下面这段客户端脚本块就是这样注册的:

定义页面第一次加载时触发的函数

不需要使用onload事件,只要有pageLoad()函数,ASP.NETAJAX就会自动调用它

不需要使用unload事件,只要有pageUnload()函数,ASP.NETAJAX也会自动调用它

除了上述2个函数,其余函数均须手工绑定

下面是pageLoad()函数,它得到PageRequestManager当前实例的引用,并向endRequest事件附加第二个函数:

functionpageLoad(){


varpageManager=Sys.WebForms.PageRequestManager.getInstance();


pageManager.add_endRequest(endRequest);


}


endRequest事件在每次异步回发结束时发生。本例中,endRequest()函数检查是否有错误发生。如果有,把错误信息显示到另一个控件里,并调用set_errorHandled()方法来消除ASP.NETAJAX标准错误处理行为(显示错误消息框)

functionendRequest(sender,args){


//Handletheerror.


if(args.get_error()!=null){


$get("lblError").innerHTML=args.get_error().message;




//Suppressthemessagebox.


args.set_errorHandled(true);


}


}


下图显示了使用错误处理后的界面效果:





ASP.NET里有2个不能在UpdatePanel中使用的控件:FileInput和HtmlInputFile控件。但它们仍可以在含有UpdatePanel控件的页面中使用

2.条件更新

如果页面上有多个UpdatePanel控件且都是完全独立的,那么可以配置UpdatePanel.UpdateMode属性由Always改为Conditional以独立更新它们。即,如果将先前示例中的3个UpdatePanel控件都设置为UpdateMode="Conditional",那么它们将各自独立工作。

从技术面而言,单击某个按钮时本例中所有的Label都会被更新,但是客户端只有部分页面会被刷新以显示相应的效果。多数情况下,这种差别并不重要。但是,它可能会导致异常,因为每个Label的值都被保存到了视图状态。这样,下一次页面被送到服务器端时,所有Label都将被置为最近的值。

3.被中断的更新

有一点需要说明,如果执行的是一个很耗时的更新,那么更新可能会被其他更新中断。ASP.NETAJAX异步回发页面,因此用户能够在回发进行过程中继续单击页面的其他按钮。ASP.NETAJAX不允许并发更新,因为它需要确保其他信息(如视图状态、会话cookie等)保持一致。当一个新的异步回发被启动后,前一个异步回发就被取消了。

大部分情况下,这正是你希望的行为。但为了防止用户打断进行中的异步回发,可以通过js代码在异步回发的过程中禁用控件。你需要为beginRequest事件附加一个事件处理程序,这和错误处理程序示例中给endRequest事件添加处理程序一样。

4.触发器

如果使用的是条件更新模式,还有其他一些办法来触发更新。其中一个办法就是使用触发器告诉UpdatePanel在页面上的某个特定控件的特定事件发生时来呈现自身。

从技术上而言,UpdatePanel总是使用触发器。UpdatePanel中所有控件自动成为UpdatePanel的触发器。在先前的示例中,当Button.Click事件发生时,就会发生一次异步回发。然而,这同时也能和所有Web控件的默认事件(控件里用DefaultEvent特性标记的事件)一起工作,只要那个事件回发了页面。例如,在UpdatePanel里放置一个TextBox,设置AutoPostBack属性为True,那么TextBox.TextChanged事件就会触发一次异步回发,同时UpdatePanel也将被更新。

触发器可以按两种方式改变这个行为。首先,它允许把触发器关联到Panel之外的某个控件上。例如页面其他位置有一个按钮,这个按钮本将触发一次完整的回发,但把它关联到UpdatePanel之后,它将执行一次异步回发。要实现这一设计,只需给UpdatePanel增加AsyncPostBackTrigger,指定要监听的控件的ID以及要触发刷新的事件:

<div>


<asp:ScriptManagerID="ScriptManager1"runat="server">


</asp:ScriptManager>


<br/>


<asp:UpdatePanelID="UpdatePanel1"runat="server"UpdateMode="Conditional">


<ContentTemplate>


<divstyle="background-color:#FFFFDD;padding:20px">


<asp:LabelID="Label1"runat="server"Font-Bold="True"></asp:Label>


</div>


</ContentTemplate>


<Triggers>


<asp:AsyncPostBackTriggerControlID="cmdOutsideUpdate"EventName="Click"/>


</Triggers>


</asp:UpdatePanel>


<br/>


<asp:ButtonID="cmdOutsideUpdate"runat="server"Text="Update"/>


</div>


EventName指定要监听的事件,通常不需指定,默认监听控件的默认事件,不过,显式设置是一个好的选择

现在单击按钮,单击在客户端被拦截,并且PageRequestManager执行一次异步回发,会发生如下情况:

所有UpdateMode设置为Always的UpdatePanel控件都会被刷新

所有UpdateMode设置为Conditional并且有针对cmdOutsideUpdate的AsyncPostBackTrigger的UpdatePanel控件都会被刷新

所有UpdateMode设置为Conditional但不监听按钮的UpdatePanel不会被刷新

注意:

为同一UpdatePanel添加多个触发器,其中任一事件都将触发更新

将同一触发器添加到多个UpdatePanel,此时一个事件同时更新所有UpdatePanel

在条件更新的UpdatePanel里混合匹配触发器和内嵌控件,这样内嵌控件的所有事件及触发器里的事件都将引发更新

还可以按另一种方式使用触发器。假设UpdatePanel里有一个按钮,单击将触发一次异步请求和局部更新。如果希望触发一次完整的页面回发,只要添加PostBackTrigger即可

<asp:ScriptManagerID="ScriptManager1"runat="server">


</asp:ScriptManager>


<br/>


<asp:UpdatePanelID="UpdatePanel1"runat="server"UpdateMode="Conditional">


<ContentTemplate>


<divstyle="background-color:#FFFFDD;padding:20px">


<asp:LabelID="Label1"runat="server"Font-Bold="True"></asp:Label>


<br/>


<br/>


<asp:ButtonID="cmdOutsideUpdate"runat="server"Text="Update"/>


</div>


</ContentTemplate>


<Triggers>


<asp:PostBackTriggerControlID="cmdOutsideUpdate"/>


</Triggers>


</asp:UpdatePanel>


这项技术应用不太常见。但是当UpdatePanel中的多个控件只执行很少的更新(因此使用异步回发),而有一个控件执行整个页面的大片更新(因此使用完整回发)时它就很有用了

5.优化UpdatePanel

UpdatePanel有时会因带宽因素让人有不好的印象。这是因为UpdatePanel几乎总是传输超过你所需要的信息量

假设你创建一个页面用于显示一张表。实现这个页面最有效的办法就是使用ASP.NETAJAX和Web服务。页面会调用服务器端的一个Web服务获取数据,你需要编写客户端的js代码并将它转换为HTML。

与上面的办法相比,类似的解决方案是使用一个带有富数据控件的UpdatePanel,比如GridView。这个方案让你可以避免写大部分的代码,但是,UpdatePanel需要请求更多信息来刷新自身。即Web服务器需要发送完整的GridView呈现内容,和UpdatePanel中其他控件的呈现内容以及页面的完整视图状态。这些信息远多于你采用Web服务方式所需的信息量。

为了获得最佳的UpdatePanel性能,了解它的本质是必须的。一些最佳的做法如下:

尽可能的压缩视图状态数据,使用EnableViewState属性关闭那些有变化内容但是不需要用视图状态保存的控件的视图状态。

在UpdatePanel里只放置最少的内容,如上例中,只因放GridView,而使用触发器特性将其他可能触发更新的控件放置在UpdatePanel之外。

如果页面中有多个可更新区域,应放置在独立的UpdatePanel中,并设置Conditional模式。Web服务器应答一个回调时,将呈现的标记发送至UpdatePanel和页面中所有非Conditional的UpdatePanel。如果你仅仅需要为其中一个面板获取新内容,那就不需要为其他的面板获取内容。

在使用了多个更新面板的复杂页面中,考虑用手动的方式刷新它们。要做到这一点,将面板设置为Conditional并将ChildrenAdTriggers属性设置为false。现在唯一能引发刷新动作的就是在一个回调请求期间在一个或更多UpdatePanel控件上显式调用Update()方法。

UpdatePanel方式永远不会比页面回发的方式差,因为页面回发方式总是将整个页面进行回发。UpdatePanel方式仅仅在与手工进行ASP.NETAJAX编程相比时显得不够好

使用Timer定时刷新

有时候可能希望用户没有动作的情况下强制完成一次完整或部分页面的刷新。例如一个股价的页面,你会希望定期刷新股价区域。ASP.NETAJAX的Timer控件可以实现这种设计。

Timer控件的使用非常简单,只要把它的Interval属性设置为页面更新间隔的最大毫秒数即可。不过要知道,Timer控件可能会大大增加Web应用程序的负载并降低它的可扩展性。

Timer控件会引发服务器端Tick事件,可以在该事件中更新页面。但此事件的使用也不是强制的,因为定时器触发时会执行完整的页面生命周期,也可以响应页面和其他控件事件,比如Page.Load。

要在部分呈现中使用Timer控件,可把页面的可更新部分包装到UpdatePanel控件并设置UpdateMode为Conditional,定时器触发时会强制更新:

<asp:UpdatePanelID="UpdatePanel1"runat="server"UpdateMode="Conditional">


<ContentTemplate>


...


</ContentTemplate>


<Triggers>


<asp:AsyncPostBackTriggerControlID="cmdOutsideUpdate"EventName="Tick"/>


</Triggers>


</asp:UpdatePanel>


<asp:TimerID="Timer1"runat="server"Interval="60000"ontick="Unnamed1_Tick"></asp:Timer>


页面的其他部分保持不变,或者如果要响应其他动作而更新它们,可以把它们包装到具有不同触发器的条件更新的UpdatePanel控件里。

如果要停止一个定时器,只要在服务器端代码里设置Enabled属性为false即可。例如下面的代码在10次更新后禁用定时器:

protectedvoidUnnamed1_Tick(objectsender,EventArgse)


{


inttickCount=0;


if(ViewState["TickCount"]!=null)


{


tickCount=(int)ViewState["TickCount"];


}


tickCount++;


if(tickCount>10)


{


Timer1.Enabled=false;


}


}


使用UpdateProgress的耗时更新

ASP.NETAJAX还包括UpdateProgress控件,它和UpdatePanel的部分呈现一起工作。UpdateProgress控件的名称不太准确。它并不指示进度,而是提供一条等待信息让用户知道页面还在工作,最后的请求还在继续处理中。

添加UpdateProgress控件后,就能够指定异步请求开始后显示某些内容,而这些内容在异步请求结束时又将自动消失。这些内容可以包括固定的消息或图片。通常,会用一个动画GIF来模拟进度条。

下面是一个使用了UpdateProgress控件的页面在其生命周期3个不同阶段的画面:









页面标记中定义了一个UpdatePanel,随后跟着一个UpdateProgress。UpdateProgress控件包含一个取消按钮,稍后会详细介绍它:

<asp:UpdatePanelID="UpdatePanel1"runat="server">


<ContentTemplate>


<divstyle="background-color:#FFFFE0;padding:20px">


<asp:LabelID="lblTime"runat="server"Font-Bold="True"></asp:Label>


<br/>


<br/>


<asp:ButtonID="cmdRefreshTime"runat="server"Text="StarttheRefreshProcess"


OnClick="cmdRefreshTime_Click"/>


</div>


</ContentTemplate>


</asp:UpdatePanel>


<br/>




<asp:UpdateProgressrunat="server"ID="updateProgress1">


<ProgressTemplate>


<divstyle="font-size:xx-small">


ContactingServer...<imgsrc="wait.gif"alt="Wait"/>


<inputid="Button1"onclick="AbortPostBack()"type="button"value="Cancel"


style="font-size:xx-small;"/>


</div>


</ProgressTemplate>


</asp:UpdateProgress>


为了模拟一个较慢的过程,可添加一行延时10秒的代码:

protectedvoidcmdRefreshTime_Click(objectsender,EventArgse)


{


System.Threading.Thread.Sleep(TimeSpan.FromSeconds(10));


lblTime.Text=DateTime.Now.ToLongTimeString();


}


不需要把UpdateProgress控件显式关联到UpdatePanel控件。无论哪一个UpdatePanel开始回调,UpdateProgress都会自动显示它的ProgressTemplate。不过,如果页面很复杂且具有多个UpdatePanel,可以选择让UpdateProgress只关注其中某一个。要这么做的话,只要把UpdateProgress.AssociatedUpdatePanelID的属性设为相应的UpdatePanel的ID即可。甚至可以为同一页面添加多个UpdateProgress控件,然后分别关联到不同的UpdatePanel。

取消

UpdateProgress控件还支持另一个细节,取消按钮。用户单击取消时,异步回调就会立即被取消,UpdateProgress的内容将消失,页面重新回到它的原始状态。

添加取消按钮是一个两步过程。首先,要添加一段执行取消的js代码。下面的代码执行这一工作(必须放在ScriptManager控件之后):

varprm=Sys.WebForms.PageRequestManager.getInstance();


prm.add_initializeRequest(InitializeRequest);




functionInitializeRequest(sender,args){


if(prm.get_isInAsyncPostBack()){


args.set_cancel(true);


}


}




functionAbortPostBack(){


if(prm.get_isInAsyncPostBack()){


prm.abortPostBack();


}


}


添加这段代码后,就可以随时通过JavaScript代码调用AbortPostBack()函数取消回调:

<inputid="Button1"onclick="AbortPostBack()"type="button"value="Cancel"/>


典型情况下,会把这个按钮(或者类似的元素)放到UpdateProgress控件的ProgressTemplate里,因为它只在回调进行时才被应用。

对那些能够被安全取消的任务提供取消按钮是有意义的,因为它们不影响外部的状态。例如,用户应该能够取消耗时的查询。但是,为更新操作提供取消则不是什么好主意,因为服务器会持续执行直到它结束更新,即使客户端已经停止监听响应时也是如此。

管理浏览器历史

每次页面执行一次全面回发,Web浏览器就会将其作为一个页面导航来处理,并在历史列表中加入一个新项。然而,当你使用UpdatePanel来执行异步回发的操作时,历史列表不会被更新。这一缺点在ASP.NETAJAX页面执行一个复杂的多步骤操作的时候变得尤为明显。如果用户稍不注意单击了“后退”按钮回退到前一步的话,浏览器会跳回到前一个页面,并且刚才用户所做的所有工作都会丢失。

如果已经安装了ASP.NET4,那么有一个合适的解决方法。通过使用ScriptManager,你可以控制浏览器的历史列表。你可以在需要的时候新增浏览器列表项,并在用户单击“后退”或“前进”时作出响应,确保页面状态是被正确恢复的。

事实上,与普通Web表单的导航相比,这个处理过程工作的相当好,因为不会提示用户重新填写之前页面上的信息。如同大多数ASP.NETAJAX特性一样,历史列表支持特性给了你一个很好的方式来获得这些功能,而无需你自己来编写恼人的复杂代码并且无需考虑浏览器的兼容性。

为了看到ScriptManager的浏览器历史特性是如何工作的,可以使用Wizard控件来创建一个简单的例子。下面是一个分为3步向导的简化例子,Wizard控件包含在UpdatePanel中:

<asp:UpdatePanelID="UpdatePanel1"runat="server">


<ContentTemplate>


<asp:WizardID="Wizard1"runat="server"...>


<WizardSteps>


<asp:WizardSteprunat="server"Title="Step1">


ThisisStep1.


</asp:WizardStep>


<asp:WizardSteprunat="server"Title="Step2">


ThisisStep2.


</asp:WizardStep>


<asp:WizardSteprunat="server"Title="Step3">


ThisisStep3.


</asp:WizardStep>


</WizardSteps>


...


</asp:Wizard>


</ContentTemplate>


</asp:UpdatePanel>


这个页面充分利用了ASP.NETAJAX的优势。现在单击向导中的链接进行导航,页面不会出现山东。然而,历史列表也不会有任何变化。

1.新增历史点

首先,将ScriptManager.EnableHistory属性设为true,这将允许使用ScriptManager来新增历史点并对历史导航作出响应。

接下来,需要在服务器端代码中调用ScriptManager.AddHistoryPoint()方法将条目加入到历史列表中。并需要提供下面3个参数

State:状态值是一个字符串,用来存储与历史点相关的信息。当用户返回到这个历史点时,可以获取到相关的状态。比如在这个例子中,它会存储向导的当前步骤索引。

Key:键值是一个唯一的字符串名字,用来存储状态信息。允许页面存储多个不冲突的状态值。这对于拥有多个使用历史列表的控件的情况很有用。比如,你有两个Wizard控件在同一页面中,只要每一个Wizard都使用了一个不同的键值,就可以同时存储各自当前步骤的索引。

Title:页面标题显示在浏览器窗口顶部并被记录在历史列表中。你也可以省略标题参数,此时历史点将会使用当前的页面标题。

本例中,在控件更改到一个新步骤时新增一个历史点是比较合适的。在向导的ActiveStepChanged事件中来做这个动作:

protectedvoidWizard1_ActiveStepChanged(objectsender,EventArgse)


{


if((ScriptManager1.IsInAsyncPostBack)&&(!ScriptManager1.IsNavigating))


{


stringcurrentStep=Wizard1.ActiveStepIndex.ToString();


ScriptManager1.AddHistoryPoint("Wizard1",currentStep,"Step"+(Wizard1.ActiveStepIndex+1).ToString());


}


}


在新增历史点之前,代码要检测两个细节。首先检测是不是作为一个异步回调操作的一部分进行变更的。

这可以确保不会在下列情况下新增历史点:

页面首次被创建且属性ActiveStepIndex第一次被赋值

使用“前进”或“后退”按钮时,IsNavigating属性为true

上述情况发生的时候,不需要存储状态,相反,需要通过处理ScriptManager.Navigate事件来还原它(后面会介绍)。

当新增历史点时,代码使用索引名字Wizard1(匹配控件的名称)存储当前步骤的索引并将页面标题设置为一个说明性字符串,比如“Step1”。如果现在运行页面会看到历史表中出现新的项,然而单击一个历史项则什么也不会发生,这是因为还没有编写代码来还原页面状态。

2.还原页面状态

当用户在历史列表中前后移动时,ScriptManager执行一个异步回调来刷新页面。这时可以处理ScriptManager.Navigate事件。当处理Navigate事件时,由你决定使用HistoryEventArgs.State集合来获取需要的状态以及当你首次新增历史点的时候所使用的状态值,表明用户可能返回到了页面的第一个书签,这意味着你应当返回到向导控件的初始状态:

protectedvoidScriptManager1_Navigate(objectsender,HistoryEventArgse)


{


if(e.State["Wizard1"]==null)


{


//Restoredefaultstateofpage(forexmaple,forfirstpage).


Wizard1.ActiveStepIndex=0;


}


else


{


Wizard1.ActiveStepIndex=Int32.Parse(e.State["Wizard1"]);


}


Page.Title="Step"+(Wizard1.ActiveStepIndex+1).ToString();


}


这段代码同时更新了页面标题以与历史记录相匹配,因为ScriptManager不会自己执行这个操作。

现在向导控件已经能够很好的工作了:





3.状态是如何在URL中存储的

事实上,ScriptManager将状态值放在了页面的URL里。它使用Base64编码来混淆这些值并在最后使用散列码来做校验。下面是向导例子中的URL:


http://localhost:41265/WebSite1/BrowserHistory.aspx#&&/wEXAQUHV2l6YXJkMQUBMqLoS2mYPwglQKajqSotKCxCQwjHojLXz4FLVZhH3Q3q


状态信息被放置在URL符号#之后。因此不会打乱任何正在使用的查询字符串参数,这些参数出现在#号前。

历史状态使用与视图状态同样的编码机制。这意味着用户能毫不费力的获取到你的状态值,但是用户并不能篡改这些值,因为他们不能在没有Web服务器私钥的情况下产生一个正确的散列码。

和视图状态不一样的地方是,你不能加密状态值。然而,如果你想更清晰的查看URL,可以移除这些编码和散列码。只需设置ScriptManager.EnableSecureHistoryState为false即可。然后URL看起来就像下面这样:


http://localhost:41265/WebSite1/BrowserHistory.aspx#&&Wizard1=2


当然,这就完全使得用户可以通过修改URL来更改一个状态值。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐
章节导航