博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
微软真强啊!这么恶心的model(转自msdn)-----front controller
阅读量:4224 次
发布时间:2019-05-26

本文共 8837 字,大约阅读时间需要 29 分钟。

实现策略

Front Controller 通常分为两个部分来实现。Handler 对象从 Web 服务器接收各个请求(HTTP Get 和 Post),并检索相关参数,然后根据参数选择适当的命令。控制器的第二个部分是 Command Processor,该部分执行特定操作或命令来满足请求。命令完成后转到视图,以便显示页面。

注意:此实现策略解决了前面的示例中出现的问题。虽然此示例可能不足以证明对 Front Controller 的更改是合理的,但它说明了为什么会使用 Front Controller ,并且该实现解决了这种复杂性高得多的问题。另外,与大多数实现一样,实现此模式的方式不止一种,这只是其中的一个选择。

处理程序

ASP.NET 提供低级请求/响应 API 来处理传入的 HTTP 请求。ASP.NET 所接收的每个传入 HTTP 请求最终由实现 IHTTPHandler 接口的类的具体实例来处理。这种低级 API 非常适用于实现 Front Controller 的处理程序部分。

注意:Microsoft? .NET Framework 为 HTTP 处理程序提供了多个实现选择。例如,在高容量环境中,您可以通过实现了 IHttpAsyncHandler 接口的异步 HTTP 处理程序来提高响应速度。为简单起见,此解决方案使用同步处理程序。有关如何实现异步 HTTP 处理程序的详细信息,请访问 Microsoft Developer Network (MSDN?) 网站 (http://msdn.microsoft.com)。

图 1 显示了控制器的处理程序部分的结构。

1 Front Controller 的处理程序部分

此解决方案完美地划分了职责。Handler 类负责处理各个 Web 请求,并将确定正确的 Command 对象这一职责委派给 CommandFactory 类。当 CommandFactory 返回 Command 对象后,Handler 将调用 Command 上的 Execute 方法来执行请求。

Handler.cs

下面的代码示例显示了如何实现 Handler 类:

using System; using System.Web; public class Handler : IHttpHandler {    public void ProcessRequest(HttpContext context)     {       Command command =           CommandFactory.Make(context.Request.Params);       command.Execute(context);    }    public bool IsReusable     {        get { return true;}     } }

Command.cs

Command 类是 Command 模式 [Gamma95] 的一个示例。Command 模式在此解决方案中非常有用,因为您不希望 Handler 类直接依赖于命令。一般来说,可以从 CommandFactory 返回命令对象。

using System; using System.Web; public interface Command {    void Execute(HttpContext context); }

CommandFactory.cs

CommandFactory 类对于实现至关重要。它根据查询字符串中的参数来判断将创建哪个命令。在此示例中,如果 site 查询参数被设置为 micro 或根本没有设置,工厂将创建 MicroSite 命令对象。如果 site 被设置为 macro,工厂将创建 MacroSite 命令对象。如果该值被设置为任何其他值,工厂将返回 UnknownCommand 对象,以便进行默认错误处理。这是 Special Case 模式 [Fowler03] 的一个示例。

using System; using System.Collections.Specialized; public class CommandFactory {    public static Command Make(NameValueCollection parms)    {       string siteName = parms["site"];       Command command = new UnknownCommand();       if(siteName == null || siteName.Equals("micro"))          command = new MicroSite();       else if(siteName.Equals("macro"))          command = new MacroSite();       return command;    } }

配置处理程序

HTTP 处理程序在 ASP.NET 配置中被声明为 web.config 文件。ASP.NET 定义了一个可以在其中添加和删除处理程序的 <httphandlers> 配置段。例如,ASP.NET 将 Page*.aspx 文件的所有请求映射到应用程序的 web.config 文件中的 Handler 类:

命令

命令代表了网站中的可变性。在此示例中,从每个站点的数据库中检索数据的功能包含在它自己的类中,并且该类是从名为 RedirectingCommand 的基类继承而来的。RedirectingCommand 类实现了 Command 接口。调用 RedirectingCommand 类的 Execute 时,它首先调用名为 OnExecute 的抽象方法,然后转到视图。该特定视图是从名为 UrlMap 的类检索而来的。UrlMap 类从应用程序的 web.config 文件中检索映射关系。图 2 显示了该解决方案的命令部分的结构。

2 front controller的命令部分

RedirectingCommand.cs

RedirectingCommand 是一个抽象基类,它调用名为 OnExecute 的抽象方法来执行特定命令,然后转到从 UrlMap 检索到的视图。

using System; using System.Web; public abstract class RedirectingCommand : Command {    private UrlMap map = UrlMap.SoleInstance;    protected abstract void OnExecute(HttpContext context);    public void Execute(HttpContext context)    {       OnExecute(context);       string url = String.Format("{0}?{1}",          map.Map[context.Request.Url.AbsolutePath],          context.Request.Url.Query);       context.Server.Transfer(url);    } }

UrlMap.cs

UrlMap 类从应用程序的 web.config 文件加载配置信息。配置信息将所请求的 URL 的绝对路径关联到该文件所指定的另一个 URL。这样,就可以更改当请求外部页面时要将用户转到哪个实际页面。这个过程为更改视图提供了很高的灵活性,因为用户永远不会引用实际页面。下面是 UrlMap 类:

using System; using System.Web; using System.Xml; using System.Configuration; using System.Collections.Specialized; public class UrlMap : IConfigurationSectionHandler  {    private readonly NameValueCollection _commands = new NameValueCollection();    public const string SECTION_NAME="controller.mapping";    public static UrlMap SoleInstance     {       get {return (UrlMap) ConfigurationSettings.GetConfig(SECTION_NAME);}    }    object IConfigurationSectionHandler.Create(object parent,object configContext, XmlNode section)     {       return (object) new UrlMap(parent,configContext, section);       }    private UrlMap() {/*no-op*/}    public UrlMap(object parent,object configContext, XmlNode section)     {       try        {          XmlElement entriesElement = section["entries"];          foreach(XmlElement element in entriesElement)           {             _commands.Add(element.Attributes["key"].Value,element.Attributes["url"].Value);          }       }        catch (Exception ex)        {          throw new ConfigurationException("Error while parsing configuration section.",ex,section);       }    }       public NameValueCollection Map    {       get { return _commands; }    } }

下面的代码是从显示配置的 web.config 文件中摘录的:

MicroSite.cs

MicroSite 类与此模式前面的 LoadMicroHeader 中的代码类似。主要区别是,无法再访问页面中包含的标签。而必须将信息添加到 HttpContext 对象。下面的示例显示了 MicroSite 代码:

using System; using System.Web; public class MicroSite : RedirectingCommand {    protected override void OnExecute(HttpContext context)    {       string name = context.User.Identity.Name;       context.Items["address"] =           WebUsersDatabase.RetrieveAddress(name);       context.Items["site"] = "Micro-Site";    } }

MacroSite.cs

MacroSite 类与 MicroSite 类似,但它使用的是不同的数据库网关类 MacroUsersDatabase。这两个类都将信息存储在传递进来的 HttpContext 中,以便让视图可以检索它。下面的示例显示了 MacroSite 代码:

using System; using System.Web; public class MacroSite : RedirectingCommand {    protected override void OnExecute(HttpContext context)    {       string name = context.User.Identity.Name;       context.Items["address"] =           MacroUsersDatabase.RetrieveAddress(name);       context.Items["site"] = "Macro-Site";    } }

WebUsersDatabase.cs

WebUsersDatabase 类负责从“webusers”数据库中检索电子邮件地址。它是 Table Data Gateway [Fowler03] 模式的一个示例。

using System; using System.Data; using System.Data.SqlClient; public class WebUsersDatabase {    public static string RetrieveAddress(string name)    {       string address = null;       String selectCmd =           String.Format("select * from webuser where (id = '{0}')",          name);       SqlConnection myConnection =           new SqlConnection("server=(local);database=webusers;Trusted_Connection=yes");       SqlDataAdapter myCommand = new SqlDataAdapter(selectCmd, myConnection);       DataSet ds = new DataSet();       myCommand.Fill(ds,"webuser");       if(ds.Tables["webuser"].Rows.Count == 1)       {          DataRow row = ds.Tables["webuser"].Rows[0];          address = row["address"].ToString();       }       return address;    } }

MacroUsersDatabase.cs

MacroUsersDatabase 类负责从“macrousers”数据库中检索电子邮件地址。它是 Table Data Gateway 模式的一个示例。

using System; using System.Data; using System.Data.SqlClient; public class MacroUsersDatabase {    public static string RetrieveAddress(string name)    {       string address = null;       String selectCmd =           String.Format("select * from customer where (id = '{0}')",          name);       SqlConnection myConnection =           new SqlConnection("server=(local);database=macrousers;Trusted_Connection=yes");       SqlDataAdapter myCommand = new SqlDataAdapter(selectCmd, myConnection);       DataSet ds = new DataSet();       myCommand.Fill(ds,"customer");       if(ds.Tables["customer"].Rows.Count == 1)       {          DataRow row = ds.Tables["customer"].Rows[0];          address = row["email"].ToString();       }       return address;    } }

视图

视图最后实现。“更改需求”中的示例视图负责根据用户访问哪个站点从数据库中检索信息,然后向用户显示所产生的页面。因为数据库访问代码已移到命令,所以视图现在从 ttpContext 对象检索数据。图 3 显示了代码隐藏类的结构。

3 视图的代码隐藏类的结构

由于仍然存在公共行为,因此仍然需要 BasePage 类以避免代码重复。

BasePage.cs

与“更改需要”中的示例相比,BasePage 类已有大幅更改。它不再负责确定要加载哪个站点头信息。它只检索由命令存储在 HttpContext 对象中的数据,并将它们分配给适当的标签:

using System; using System.Web.UI; using System.Web.UI.WebControls; public class BasePage : Page {    protected Label eMail;    protected Label siteName;    virtual protected void PageLoadEvent(object sender, System.EventArgs e)    {}    protected void Page_Load(object sender, System.EventArgs e)    {       if(!IsPostBack)       {          eMail.Text = (string)Context.Items["address"];          siteName.Text = (string)Context.Items["site"];          PageLoadEvent(sender, e);       }    }    #region Web Form Designer generated code    #endregion }

ActualPage1.aspx.cs ActualPage2.aspx

ActualPage1ActualPage2 是针对具体页面的代码隐藏类。它们都是从 BasePage 继承而来的,以确保在屏幕的顶部填入头信息:

using System; using System.Web.UI; using System.Web.UI.WebControls; public class ActualPage1 : BasePage {    protected System.Web.UI.WebControls.Label pageNumber;    protected override void PageLoadEvent(object sender, System.EventArgs e)    {       pageNumber.Text = "1";    }    #region Web Form Designer generated code    #endregion } using System; using System.Web.UI.WebControls; public class ActualPage2 : BasePage {    protected Label pageNumber;    protected override void PageLoadEvent(object sender, System.EventArgs e)    {       pageNumber.Text = "2";    }   #region Web Form Designer generated code    #endregion }

在从 Page Controller 实现转移到 Front Controller 实现时,不必更改这些页面。 

转载地址:http://zagmi.baihongyu.com/

你可能感兴趣的文章
如何使用log4j输出单个级别的log到指定文件
查看>>
表单元素与提示文字无法对齐的解决方法
查看>>
图片按钮消除边框
查看>>
增加windows下Tomcat运行时的内存
查看>>
tomcat群集中session共享的几个方案
查看>>
查找google谷歌北京IP地址的方法
查看>>
使用Beyond Compare合并代码后出现乱码问题
查看>>
dmp数据文件导入问题
查看>>
使用Beyond Compare对比文件夹
查看>>
深入理解java虚拟机 -- jVM高级特性与最佳实践
查看>>
ora-01756
查看>>
java 核心技术Ⅱ--章四:网络
查看>>
java 核心技术Ⅱ--章五:JDBC数据库编程
查看>>
java 核心技术Ⅱ--章六:时间与日期API
查看>>
链表,循环链表,双向链表,判环和入环点
查看>>
浅谈HashMap,HashTable,ConcurrentHashMap,WeakHashMap,HashMap源码分析
查看>>
云创大数据校企合作项目斩获“全国校企合作十佳案例”
查看>>
云创大数据与宽泛科技签订战略合作协议
查看>>
免费!免费!免费!全国高校大数据师资实战免费培训班
查看>>
“南京市独角兽瞪羚企业俱乐部创始人简餐会”走进云创
查看>>