如何构建积木式Web应用
上下文
问题
环境
预备知识
最好具备以下知识
解决方案
public class MyPlaceHolder : PlaceHolder { private string userControl; // 要载入的UserControl目录下的.ascx private string pageControl; // 要载入的Page目录下的.ascx public MyPlaceHolder() { userControl = ""; pageControl = ""; } public string UserControl { get { return userControl; } set { userControl = value; } } public string PageControl { get { return pageControl; } set { pageControl = value; } } // 当需要载入多个UserControl时,可以直接调用LoadUserControl // 当只需要载入一个UserControl时,可以调用Clear清除载入过的内容 public void Clear() { this.Controls.Clear(); } // 载入UserControl目录下的.ascx // 以及导入对应的css文件 public void LoadUserControl(string UserControl) { this.userControl = UserControl; BasePage page = (BasePage)this.Page; // 请参考后面的BasePage的代码 Control control = this.Page.LoadControl( page.Scheme + "usercontrol/" + userControl + ".ascx"); string css = "css/" + userControl + ".css"; // 对应的css文件 if(File.Exists(this.Page.MapPath(page.Scheme+css))) { page.AddCss(page.Scheme + css); } this.Controls.Add(control); } // 载入Page目录下的.ascx // LoadPage与LoadUserControl的区别是两者载入的.ascx所在的目录不同 // Page目录下的.ascx可以看成是一些搭建主体结构的.ascx,其使用MyPlaceHolder // 来包含最基础的积木块.ascx(在UserControl目录下) public void LoadPage(string PageControl) { this.PageControl = PageControl; BasePage page = (BasePage)this.Page; Control control = this.Page.LoadControl( page.Scheme + "page/" + pageControl + ".ascx"); string css = "css/" + pageControl + ".css"; if(File.Exists(this.Page.MapPath(page.Scheme+css))) { page.AddCss(page.Scheme + css); } this.Controls.Add(control); } protected override void OnLoad(EventArgs e) { base.OnLoad(e); if(!userControl.Equals(string.Empty)) { LoadUserControl(userControl); } } } public class MyPlaceHolder : PlaceHolder { private string userControl; // 要载入的UserControl目录下的.ascx private string pageControl; // 要载入的Page目录下的.ascx public MyPlaceHolder() { userControl = ""; pageControl = ""; } public string UserControl { get { return userControl; } set { userControl = value; } } public string PageControl { get { return pageControl; } set { pageControl = value; } } // 当需要载入多个UserControl时,可以直接调用LoadUserControl // 当只需要载入一个UserControl时,可以调用Clear清除载入过的内容 public void Clear() { this.Controls.Clear(); } // 载入UserControl目录下的.ascx // 以及导入对应的css文件 public void LoadUserControl(string UserControl) { this.userControl = UserControl; BasePage page = (BasePage)this.Page; // 请参考后面的BasePage的代码 Control control = this.Page.LoadControl( page.Scheme + "usercontrol/" + userControl + ".ascx"); string css = "css/" + userControl + ".css"; // 对应的css文件 if(File.Exists(this.Page.MapPath(page.Scheme+css))) { page.AddCss(page.Scheme + css); } this.Controls.Add(control); } // 载入Page目录下的.ascx // LoadPage与LoadUserControl的区别是两者载入的.ascx所在的目录不同 // Page目录下的.ascx可以看成是一些搭建主体结构的.ascx,其使用MyPlaceHolder // 来包含最基础的积木块.ascx(在UserControl目录下) public void LoadPage(string PageControl) { this.PageControl = PageControl; BasePage page = (BasePage)this.Page; Control control = this.Page.LoadControl( page.Scheme + "page/" + pageControl + ".ascx"); string css = "css/" + pageControl + ".css"; if(File.Exists(this.Page.MapPath(page.Scheme+css))) { page.AddCss(page.Scheme + css); } this.Controls.Add(control); } protected override void OnLoad(EventArgs e) { base.OnLoad(e); if(!userControl.Equals(string.Empty)) { LoadUserControl(userControl); } } }
使用方法: <HomeOffice:MyPlaceHolder id="Myplaceholder1" runat="server" UserControl="Header"> </HomeOffice:MyPlaceHolder> // 这里的Header是位于UserControl目录下的Header.ascx
<%@ Register TagPrefix="HomeOffice" Namespace="HomeOffice.Web.UI.WebControl" Assembly = "HomeOffice.Web.UI" %> <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" > <HTML> <HEAD> <title>构建积木式应用程序</title> <asp:Literal ID="CssHolder" runat="server"></asp:Literal> <asp:Literal ID="ScriptHolder" Runat="server"></asp:Literal> <style> BODY { margin-left : 0px; margin-right : 0px; } </style> </HEAD> <body bgcolor="#e6e6e6"> <form id="Form1" method="post" runat="server" enctype="multipart/form-data"> <table width="100%" cellpadding="0" cellspacing="0"> <tr> <td> </td> <td width="800"> <table width="100%" cellpadding="0" cellspacing="0"> <tr> <td> <HomeOffice:MyPlaceHolder id="PlaceHolder1" runat="server" UserControl="Header"> </HomeOffice:MyPlaceHolder> </td> </tr> <tr> <td> <HomeOffice:MyPlaceHolder id="Myplaceholder1" runat="server" UserControl="MainMenu"> </HomeOffice:MyPlaceHolder> </td> </tr> <tr> <td style="height:6px;background:#f6f6f6;font-size:1px; border-top:1px solid white;"> </td> </tr> <tr> <td style="height:4px;background:#e1e1e1;font-size:1px; border-top:1px solid #e6e6e6; "> </td> </tr> <tr> <td style="background:white;border-bottom:1px solid #bbbbbb"> <HomeOffice:MyPlaceHolder id="PageBody" runat="server"> </HomeOffice:MyPlaceHolder> </td> </tr> <tr> <td style="padding-top:20px"> <HomeOffice:MyPlaceHolder id="Myplaceholder2" runat="server" UserControl="Footer"> </HomeOffice:MyPlaceHolder> </td> </tr> </table> </td> <td> </td> </tr> </table> </form> </body> </HTML>
public class BasePage : Page { public string Scheme = "/Scheme/blue/"; // 所采用的主题 public AppSetting Setting; // 环境配置,在Init中分析,其内容包括解析http请求到正确的Page目录下的 // 文件,建立当前登陆用户的信息 public Control focusControl; // 当页面载入后,首先获得焦点的控件 private Literal CssHolder; // 要导入的css private Literal ScriptHolder; // 要导入的script文件 public BasePage() { focusControl = null; } // 导入css文件引用 public void AddScript(string script) { // 进行IsPostBack判断的原因是 // 防止重复导入 if(!this.IsPostBack) { ScriptHolder.Text += string.Format("<script src=\"{0}\" type=\"text/javascript\"></script>\n", script); } } // 导入script文件引用 public void AddCss(string css) { if(!this.IsPostBack) { CssHolder.Text += "<link rel=\"stylesheet\" type=\"text/css\" href=\"" + css + "\">\n"; } } // 载入http请求分析后的Page目录下的所请求的文件 public void LoadPageTemplate() { Control control = (Control)this.LoadControl (this.Scheme+"PageTemplate.ascx"); CssHolder = (Literal)control.FindControl("CssHolder"); ScriptHolder = (Literal)control.FindControl("ScriptHolder"); this.Controls.Add(control); MyPlaceHolder body = (MyPlaceHolder) control.FindControl("PageBody"); body.LoadPage(this.Setting.TargetPage); // 调用MyPlaceHolder的LoadPage方法 // TargetPage记录了请求的页面 } protected override void OnInit(EventArgs e) { base.OnInit(e); // 分析http请求 Setting = new AppSetting(this.Request.Path); // 设置用户信息 if(this.Request.IsAuthenticated) { Setting.SetUser(User.Identity.Name); } } protected override void OnLoad(EventArgs e) { base.OnLoad(e); this.LoadPageTemplate(); } // 当页面显示后,初始获得焦点的控件 protected void SetFocusControl() { if(this.focusControl==null) return; string template = @"<script language='jscript'> document.all.{0}.focus();</script>"; string script = string.Format(template, this.focusControl.ClientID); this.RegisterStartupScript("FocusControl", script); } protected override void OnPreRender(EventArgs e) { base.OnPreRender(e); SetFocusControl(); } // 修复了asp.net 1.1的一个bug // 没有这段代码,LinkButton等某些服务器将无法使用 protected override void Render(HtmlTextWriter writer) { StringBuilder stringBuilder = new StringBuilder(); StringWriter stringWriter = new StringWriter(stringBuilder); HtmlTextWriter htmlWriter = new HtmlTextWriter(stringWriter); base.Render(htmlWriter); string html = stringBuilder.ToString(); int start = html.IndexOf("<form name=\"") + 12; int end = html.IndexOf("\"", start); string formID = html.Substring(start, end - start); string replace = formID.Replace(":", "_"); html = html.Replace("document."+formID,"document."+replace); writer.Write(html); } }
在web.config中进行如下配置,让httphandler生效: <httpHandlers> <add verb="*" path="*.aspx" type="HomeOffice.Web.UI.HttpHandler.MyPageHandlerFactory, HomeOffice.Web.UI"/> </httpHandlers>
public class MyPageHandlerFactory : IHttpHandlerFactory { public virtual IHttpHandler GetHandler(HttpContext context, String requestType, String url, String pathTranslated) { return new BasePage(); } public virtual void ReleaseHandler(IHttpHandler handler) { } }
public class AppSetting { public string Url; // request url public string Site; // request site public string User; // login name public string UserName; // display name public string TargetPage; // target page public string[] Roles; // user roles in the site private Hashtable parameter = new Hashtable(); public AppSetting() { Site = "default"; User = "*"; UserName = ""; Roles = null; } public AppSetting(string url) : this() { this.Url = url.ToLower(); AnalysisUrl(this.Url); } public object this[string key] { get { return parameter[key]; } set { parameter.Add(key, value); } } // 分析用户所请求的页面和参数 protected void AnalysisPage(string url) { PageInfo[] pages = XmlHomeOffice.Pages(); foreach(PageInfo page in pages) { if(Regex.IsMatch(url,page.pattern,RegexOptions.IgnoreCase)) { this.TargetPage = string.Format(page.target_page, url.Replace(".aspx","").Split('/')); if(!page.parameter.Equals(string.Empty)) { string p = string.Format(page.parameter, url.Replace(".aspx", "").Split('/')); string[] ps = p.Split(','); foreach(string str in ps) { string[] item = str.Split('='); this[item[0]] = item[1]; } } return; } } // No one matched, a Exception occur this.TargetPage = "error"; } // 分析出站点,类似于blog中的每个站点 protected string AnalysisSite(string url) { if(url[0]=='/') { url = url.Remove(0, 1); } string[] items = url.Split('/'); if(items.Length<1) { return Site + "/default.aspx"; } if(items[0].EndsWith(".aspx")) { return Site + "/" + url; } string[] reserved_words = XmlHomeOffice.ReservedWords(); foreach(string str in reserved_words) { if(items[0].Equals(str.ToLower())) { return Site + "/" + url; } } Site = items[0]; return url; } public void AnalysisUrl(string url) { Url = AnalysisSite(url); AnalysisPage(Url); } public void SetUser(string user) { User = user; UserName = XmlUsers.GetDisplayName(user); XmlSiteProfile profile = new XmlSiteProfile(Site); Roles = profile.SiteUserRole(user); } public bool HasRole(string role) { if(Roles==null) return false; foreach(string str in Roles) { if(str.Equals(role)) return true; } return false; } }
<pages> <page pattern="^(\/testboth.aspx)$" parameter="" target-page="testboth" /> <page pattern="^(\/\w+.aspx)$" parameter="" target-page="{1}" /> </pages>
<%@ Control Language="c#" AutoEventWireup="false" Inherits="HomeOffice.UserControl.PageTemplate" %>
流程说明
具体应用
优点讨论
下载
建立如下的数据库,表,存储过程: 数据库:test 访问账号:sa,sa(可以在web.config中修改) 表:test 字段 test_id(自增),string(nvarchar(50)),number(int) 存储过程: testaddnew:(没有参数) insert into test(string, number) values(‘’, 0); testget: (没有参数) select * from test testdelete:(输入参数:@test_id int) delete from test where test_id = @teat_id testupate:(参数:@test_id, @string, @number) update test set string=@string, number=@number where test_id=@test_id
http://localhost/testtextbox.aspx
http://localhost/testdatagrid.aspx
http://www.smartyouth.net/scheme.rar
相关知识
http://www.microsoft.com/china/msdn/architecture/patterns/Esp/http://scottwater.com/DotText/default.aspx