用winform的方式操纵webform--浅谈IHttpHandler
好久以前看过一篇有关自定义IHttpHandler的文章,当时就想写点自己的体会,一直没空。今天就说说这个吧。首先谈谈asp.net的一些参数传递和页面定向的方式
第一,asp.net是用Page.Navigate()调用新页面的URL。Page.Navigate()向浏览器返回了一个http状态码302,使得浏览器向server请求那个新的URL。这种导航方法导致每次客户请求都需两次在client和server之间往返。第二,任何要传递到新页面的信息都需作为URL的参数或存储在Session中或存储在数据库中以便新页面得到这些信息。传统的asp开发人员很习惯这种做法,但其他的web编程人员则有一些更高级的方法。但是很明显的这两个页面是有依赖性的,而依赖性是编译器捕捉不到的也是不容易在设计阶段建模的。所以在debug时,参数是否被正确的传递就只有我们自己检查了。再有传统的数据传递方式有可能会暴露一些关键的数据。更为关键的是这使得面向对象的设计变得很复杂。当然我并没有否定传统的方式,我这是在强调asp.net缺乏对服务器端的多页面之间的通信的支持。
但是我们可以自定义httphandler来扩充这种支持。
开始之前,我们先来看一下asp.net怎样处理页面请求,asp.net是通过System.Web.UI.PageHandlerFactory类的实例来处理。PageHandlerFactory依赖于另一个类PageParser。一个页面在第一次请求时PageParser把它编译成一个真正的.Net的类并cache已编译的实例
HttpApplication
|
|1.GetHandler()
|
PageHandlerFactory
|
|2.GetCompiledPageInstance()
|
PageParser
我们要做的第一步是override由asp.net提供的页面生成过程。所以我们必须创建一个类实现IHttpHandlerFactory接口,我们需要实现的只有两个方法,一个是GetHandler(),它是在一个HTTP Request开始时被调用;另一个是ReleaseHandler(),调用可以让IHttpHandlerfactory进行清理工作。
例子:
using System;
using System.Web;
using System.Web.UI;
namespace Michael.Web.HttpHandler
{
/// <summary>
/// 一个简单的HttpHandler
/// </summary>
public class Factory:System.Web.IHttpHandlerFactory
{
public IHttpHandler GetHandler(HttpContext context, string url, string path, string objectName)
{
return Controller.getViewObject(path, objectName, context);
}
public void ReleaseHandler(IHttpHandler Handler)
{
}
}
}
注意:GetHandler()必须返回一个实现IHttpHandler接口的对象,Controller是另一个我们自定义的类
接下来我们要修改web.config
<configuration>
<httphandlers>
<add verb="*" path="*.aspx" type="Michael.Web.HttpHandler.Factory,Michael.Web.HttpHandler" />
</httphandlers>
</configuration>
我们这里还是采用.aspx作为后缀名,其实你可以自定义这个后缀名
例子:Controller.cs
namespace Michael.Web.HttpHandler
{
using System;
using System.Web;
using System.Web.UI;
using System.Collections.Specialized;
/// <summary>
/// Controller继承了System.Web.UI.Page作为ASP.NET页面的handler
/// </summary>
public class Controller : System.Web.UI.Page
{
public Controller()
{
this.Init += new System.EventHandler( Base_Init );
}
protected void Page_Load( object sender, EventArgs e )
{
//将提交页面的对象名存储在hidden里
string a_ObjectName = this.GetType().Name;
a_ObjectName = a_ObjectName.Substring ( 0, a_ObjectName.Length - 5 );
this.RegisterHiddenField( LAST_VIEW_OBJECT, a_ObjectName );
}
protected void Page_Init( object sender, EventArgs e )
{
this.Load += new System.EventHandler ( this.Base_Load );
}
//////////////////
///创建页面实例,允许服务器端通讯
//////////////////
protected IHttpHandler createInstanceOf( string ObjectName )
{
string a_Path = Request.ApplicationPath + "/" + ObjectName;
return Controller.getPage( a_Path, this.Context.Request.MapPath(ObjectName) , Context );
}
protected virtual IHttpHandler getNextPage() { return null; }
protected override void Render( HtmlTextWriter writer )
{
IHttpHandler aHandler = this.getNextPage();
if( aHandler == null )
{
base.Render ( writer );
}
else
{
if( aHandler is Controller )
{
( ( Controller )aHandler ).overrideLoadState = true;
}
aHandler.ProcessRequest ( this.Context );
}
}
/////////////////
///先检查hidden看是否有提交页面名称,如没有则返回浏览器请求的URL
/////////////////
public static IHttpHandler getViewObject( string Path, string ObjectName , HttpContext Context )
{
string a_CurrentView = Context.Request.Form[LAST_VIEW_OBJECT];
string a_Path;
if( a_CurrentView == null || a_CurrentView.Length == 0 )
{
a_CurrentView = ObjectName;
a_Path = Path;
}
else
{
a_CurrentView += ".aspx";
a_Path = Context.Request.ApplicationPath + "/" + a_CurrentView;
a_CurrentView = Context.Server.MapPath( a_CurrentView );
}
return Controller.getPage( a_Path, a_CurrentView, Context );
}
private static IHttpHandler getPage( string Path, string ObjectName , HttpContext Context )
{
IHttpHandler a_Page = null;
try
{
a_Page = PageParser.GetCompiledPageInstance( Path , ObjectName , Context );
}
catch(Exception e)
{
// 返回错误页面
}
return a_Page;
}
protected override object LoadPageStateFromPersistenceMedium()
{
if( overrideLoadState )
{
ViewState.Clear();
return null;
}
return base.LoadPageStateFromPersistenceMedium();
}
protected override NameValueCollection DeterminePostBackMode()
{
if(overrideLoadState)
{
return null;
}
else
{
return base.DeterminePostBackMode();
}
}
protected bool overrideLoadState = false;
protected const string LAST_VIEW_OBJECT = "ControllerLASTVIEWOBJECT";
}
}
这样我们就建立了一个自定义的httphandler,在你的webform中继承Controller并重载getNextPage方法
看一看我们可以怎样操纵页面呢
protected override IHttpHandler getNextPage()
{
if(this.IsValid && this.IsPostBack)
{
Second SecondPage = this.createInstanceOf("second.aspx") as Second;//是不是很象winform呀
Infomation FirstPage = new Infomation();
FirstPage.EmailAddress = txtEmail.Text;
FirstPage.FirstName = txtFirstName.Text;
FirstPage.LastName = txtLastName.Text;
SecondPage.Infomation = FirstPage;
return SecondPage;
}
else
{
return null;
}
}
第一,asp.net是用Page.Navigate()调用新页面的URL。Page.Navigate()向浏览器返回了一个http状态码302,使得浏览器向server请求那个新的URL。这种导航方法导致每次客户请求都需两次在client和server之间往返。第二,任何要传递到新页面的信息都需作为URL的参数或存储在Session中或存储在数据库中以便新页面得到这些信息。传统的asp开发人员很习惯这种做法,但其他的web编程人员则有一些更高级的方法。但是很明显的这两个页面是有依赖性的,而依赖性是编译器捕捉不到的也是不容易在设计阶段建模的。所以在debug时,参数是否被正确的传递就只有我们自己检查了。再有传统的数据传递方式有可能会暴露一些关键的数据。更为关键的是这使得面向对象的设计变得很复杂。当然我并没有否定传统的方式,我这是在强调asp.net缺乏对服务器端的多页面之间的通信的支持。
但是我们可以自定义httphandler来扩充这种支持。
开始之前,我们先来看一下asp.net怎样处理页面请求,asp.net是通过System.Web.UI.PageHandlerFactory类的实例来处理。PageHandlerFactory依赖于另一个类PageParser。一个页面在第一次请求时PageParser把它编译成一个真正的.Net的类并cache已编译的实例
HttpApplication
|
|1.GetHandler()
|
PageHandlerFactory
|
|2.GetCompiledPageInstance()
|
PageParser
我们要做的第一步是override由asp.net提供的页面生成过程。所以我们必须创建一个类实现IHttpHandlerFactory接口,我们需要实现的只有两个方法,一个是GetHandler(),它是在一个HTTP Request开始时被调用;另一个是ReleaseHandler(),调用可以让IHttpHandlerfactory进行清理工作。
例子:
using System;
using System.Web;
using System.Web.UI;
namespace Michael.Web.HttpHandler
{
/// <summary>
/// 一个简单的HttpHandler
/// </summary>
public class Factory:System.Web.IHttpHandlerFactory
{
public IHttpHandler GetHandler(HttpContext context, string url, string path, string objectName)
{
return Controller.getViewObject(path, objectName, context);
}
public void ReleaseHandler(IHttpHandler Handler)
{
}
}
}
注意:GetHandler()必须返回一个实现IHttpHandler接口的对象,Controller是另一个我们自定义的类
接下来我们要修改web.config
<configuration>
<httphandlers>
<add verb="*" path="*.aspx" type="Michael.Web.HttpHandler.Factory,Michael.Web.HttpHandler" />
</httphandlers>
</configuration>
我们这里还是采用.aspx作为后缀名,其实你可以自定义这个后缀名
例子:Controller.cs
namespace Michael.Web.HttpHandler
{
using System;
using System.Web;
using System.Web.UI;
using System.Collections.Specialized;
/// <summary>
/// Controller继承了System.Web.UI.Page作为ASP.NET页面的handler
/// </summary>
public class Controller : System.Web.UI.Page
{
public Controller()
{
this.Init += new System.EventHandler( Base_Init );
}
protected void Page_Load( object sender, EventArgs e )
{
//将提交页面的对象名存储在hidden里
string a_ObjectName = this.GetType().Name;
a_ObjectName = a_ObjectName.Substring ( 0, a_ObjectName.Length - 5 );
this.RegisterHiddenField( LAST_VIEW_OBJECT, a_ObjectName );
}
protected void Page_Init( object sender, EventArgs e )
{
this.Load += new System.EventHandler ( this.Base_Load );
}
//////////////////
///创建页面实例,允许服务器端通讯
//////////////////
protected IHttpHandler createInstanceOf( string ObjectName )
{
string a_Path = Request.ApplicationPath + "/" + ObjectName;
return Controller.getPage( a_Path, this.Context.Request.MapPath(ObjectName) , Context );
}
protected virtual IHttpHandler getNextPage() { return null; }
protected override void Render( HtmlTextWriter writer )
{
IHttpHandler aHandler = this.getNextPage();
if( aHandler == null )
{
base.Render ( writer );
}
else
{
if( aHandler is Controller )
{
( ( Controller )aHandler ).overrideLoadState = true;
}
aHandler.ProcessRequest ( this.Context );
}
}
/////////////////
///先检查hidden看是否有提交页面名称,如没有则返回浏览器请求的URL
/////////////////
public static IHttpHandler getViewObject( string Path, string ObjectName , HttpContext Context )
{
string a_CurrentView = Context.Request.Form[LAST_VIEW_OBJECT];
string a_Path;
if( a_CurrentView == null || a_CurrentView.Length == 0 )
{
a_CurrentView = ObjectName;
a_Path = Path;
}
else
{
a_CurrentView += ".aspx";
a_Path = Context.Request.ApplicationPath + "/" + a_CurrentView;
a_CurrentView = Context.Server.MapPath( a_CurrentView );
}
return Controller.getPage( a_Path, a_CurrentView, Context );
}
private static IHttpHandler getPage( string Path, string ObjectName , HttpContext Context )
{
IHttpHandler a_Page = null;
try
{
a_Page = PageParser.GetCompiledPageInstance( Path , ObjectName , Context );
}
catch(Exception e)
{
// 返回错误页面
}
return a_Page;
}
protected override object LoadPageStateFromPersistenceMedium()
{
if( overrideLoadState )
{
ViewState.Clear();
return null;
}
return base.LoadPageStateFromPersistenceMedium();
}
protected override NameValueCollection DeterminePostBackMode()
{
if(overrideLoadState)
{
return null;
}
else
{
return base.DeterminePostBackMode();
}
}
protected bool overrideLoadState = false;
protected const string LAST_VIEW_OBJECT = "ControllerLASTVIEWOBJECT";
}
}
这样我们就建立了一个自定义的httphandler,在你的webform中继承Controller并重载getNextPage方法
看一看我们可以怎样操纵页面呢
protected override IHttpHandler getNextPage()
{
if(this.IsValid && this.IsPostBack)
{
Second SecondPage = this.createInstanceOf("second.aspx") as Second;//是不是很象winform呀
Infomation FirstPage = new Infomation();
FirstPage.EmailAddress = txtEmail.Text;
FirstPage.FirstName = txtFirstName.Text;
FirstPage.LastName = txtLastName.Text;
SecondPage.Infomation = FirstPage;
return SecondPage;
}
else
{
return null;
}
}