zoukankan      html  css  js  c++  java
  • 使用EasyUI的树控件构建Web界面

     

    最近花了不少时间在重构和进一步提炼我的Web开发框架上,力求在用户体验和界面设计方面,和Winform开发框架保持一致,而在Web上,我主要采用EasyUI的前端界面处理技术,走MVC的技术路线,在重构完善过程中,很多细节花费不少时间进行研究和提炼,一步步走过来,也积累了不少经验,本系列将主要介绍我在进一步完善我的Web框架基础上积累的经验进行分享,本随笔主要介绍使用EasyUI的树控件构建Web界面的相关经验。

    在很多界面设计上,我们可能都需要引入树列表控件,这个控件可以用zTree来实现,也可以用EasyUI的内置树控件进行展示,由于历史原因,我原来倾向于使用zTree,最新把它全部修改为EasyUI的树控件,并进行了完善优化,发现代码更加简洁明快,非常不错。

    1、在界面上使用EasyUI的树控件

    一般情况下,使用EasyUI的树控件,代码很简单,脚本代码如下所示,主要就是通过调用url来获得Json数据,然后就可以显示了,通过onClick就可以响应用户单击节点的操作,每个节点有id, text, iconCls, checked,state,children等属性。

    1)树控件的Json数据绑定

                $('#treeDept').tree({
                    url: '/User/GetMyDeptTreeJson?userId=@Session["UserId"]',
                    onClick: function (node) {
                        loadData(node.id);
                    }
                });

    2)树控件的折叠和展开

    树控件的展开和折叠,可以通过定义两个通用的脚本进行处理,如下所示。

    复制代码
            function expandAll(treeName) {
                var node = $('#' + treeName).tree('getSelected');
                if (node) {
                    $('#' + treeName).tree('expandAll', node.target);
                }
                else {
                    $('#' + treeName).tree('expandAll');
                }
            }
            function collapseAll(treeName) {
                var node = $('#' + treeName).tree('getSelected');
                if (node) {
                    $('#' + treeName).tree('collapseAll', node.target);
                }
                else {
                    $('#' + treeName).tree('collapseAll');
                }
            }
    复制代码

    然后,在页面加载完毕后,绑定指定的按钮控件就可以了吗,如下代码所示。

    复制代码
            //初始化对象
            $(document).ready(function () {
                //初始化机构分类
                initOUCategorys();
    
                //机构基础信息
                initDeptTreeview();
                $("#deptExpand").bind("click", function () {
                    expandAll("treeDept");
                });
                $("#deptCollapse").bind("click", function () {
                    collapseAll("treeDept");
                });                       
    
                $("#loading").center(); //loading的图片显示居中
            });
    复制代码

    3)树控件的复选框显示

    树控件默认是没有复选框的,它可以通过属性checkbox设置让它进行展示的,如下代码是我项目里面的代码。

    其中cascadeCheck是否让树控件级联的,默认是级联,也就是只要父控件被选中,所有其子控件都会被选中,我们可以设置它为false,让它不级联,这样在很多情况下是需要的。

    复制代码
                $('#treeFunctionView').tree({
                    checkbox: true,
                    cascadeCheck: false,
                    url: '/Function/GetRoleFunctionByUser?userId=@Session["UserId"]',
                    onClick: function (node) {
                        //
                    }
                });
    复制代码

    4)树控件的全选和全不选择

    这个全部不选的特性,我找了很多文章,都没有找到,其实后来才发现,我们对树的节点理解有偏差,认识到后,实现起来也很容易。

    如取消全部节点的选中状态,代码如下所示。它的方法getChecked是返回所有的节点,而不是一个节点。它们把全部选中的节点放到一个结合里面,不像Winform里面,树节点需要递归查询,这里只需要一个for循环就可以展开了,我这里把所有勾选的节点,设置为非勾选状态就可以实现取消全部树节点勾选状态了。

    复制代码
            function unCheckTree(tree) {
                var nodes = $('#' + tree).tree('getChecked');
                if (nodes) {
                    for (var i = 0; i < nodes.length; i++) {
                        $('#' + tree).tree('uncheck', nodes[i].target);
                    }
                }
            }
    复制代码

    我们知道,很多树控件,为了方便操作,都提供了一个全选或者全部不选的操作,这个在EasyUI的树控件里面,也是很容易实现的。这里的getChildren和上面的意思类似,也是返回所有的子节点,不需要在进行递归,用一个for循环就可以遍历全部节点和其下面的多级子节点了。也就是说,它是一个二维的数据,不用递归查询。

    复制代码
            function checkAllTree(tree, checked) {
                var children = $('#' + tree).tree('getChildren');
                for (var i = 0; i < children.length; i++) {
                    if (checked) {
                        $('#' + tree).tree('check', children[i].target);
                    } else {
                        $('#' + tree).tree('uncheck', children[i].target);
                    }
                }
            }
    复制代码

    5)下拉列表的树控件初始化

    除了普通的树列表,还有一种比较特殊的树控件,就是在ComboTree,也就是在下拉列表中集成树控件,它的操作和普通的树控件差不多,很多事件属性都一样,它的使用代码如下所示。

    复制代码
            //初始化公司
            function initCompany() {
                $('#txtCompany_ID').combotree({
                    url: '/User/GetMyCompanyTreeJson?userId=@Session["UserId"]',
                    valueField: 'id',
                    textField: 'text',
                    required: true,
                    onClick: function (node) {
                        //
                    }
                });
            }
    复制代码

    2、树控件的优化

    1)普通的Json数据生成

    前面说了,我们为了方便,一般使用Json数据和javascript打交道,而EasyUI的树控件支持很好地的Json链接绑定,因此我们只需要在对应的控制器里面实现json数据的生成即可,如果是一开始想要确定的Json数据,一般也是通过手工生成的居多,如下代码所示。

    复制代码
            public ActionResult GetTreeJson()
            {
                string folder = "/Content/JqueryEasyUI/themes/icons/customed/" + "organ.png";
                string leaf = "/Content/JqueryEasyUI/themes/icons/customed/" + "organ.png";
                string json = GetTreeJson(-1, folder, leaf);
                json = json.Trim(',');
                return Content(string.Format("[{0}]", json));
            }
    
            /// <summary>
            /// 递归获取树形信息
            /// </summary>
            /// <param name="PID"></param>
            /// <returns></returns>
            private string GetTreeJson(int PID, string folderIcon, string leafIcon)
            {
                string condition = string.Format("PID={0}", PID);
                List<OUInfo> nodeList = BLLFactory<OU>.Instance.Find(condition);
                StringBuilder content = new StringBuilder();
                foreach (OUInfo model in nodeList)
                {
                    int ParentID = (model.PID == -1 ? 0 : model.PID);
                    //string tempMenu = string.Format("{{ id:{0}, pId:{1}, name:"{2}",icon:"{3}" }},", model.ID, ParentID, model.Name, imgsrc);
                    string subMenu = this.GetTreeJson(model.ID, folderIcon, leafIcon);
                    string parentMenu = string.Format("{{ "id":{0}, "pId":{1}, "name":"{2}" ", model.ID, ParentID, model.Name);
                    if (string.IsNullOrEmpty(subMenu))
                    {
                        if (!string.IsNullOrEmpty(leafIcon))
                        {
                            parentMenu += string.Format(","icon":"{0}" }},", leafIcon);
                        }
                        else
                        {
                            parentMenu += "},";
                        }
                    }
                    else
                    {
                        if (!string.IsNullOrEmpty(folderIcon))
                        {
                            parentMenu += string.Format(","icon":"{0}" }},", folderIcon);
                        }
                        else
                        {
                            parentMenu += "},";
                        }
                    }
    
                    content.AppendLine(parentMenu.Trim());
                    content.AppendLine(subMenu.Trim());
                }
    
                return content.ToString().Trim();
            } 
    复制代码

    上面的代码很好实现了根据数据库结构的关系,生成Json数据,但是感觉部分硬编码,凑出来的数据,始终感觉不太理想,如果我们要简化,该如何操作呢?

    2)简洁美观的Json数据生成

    本小节继续上面的议题,看如何简化json的生成,因为我们需要很多这样的json操作,如果采用上面的方法,我感觉很容易出错,而且也不太美观。为了解决这个问题,我们可以通过定义一个json数据的实体类,用来承载相关的信息,如下定义所示。

    复制代码
        /// <summary>
        /// 定义EasyUI树的相关数据,方便控制器生成Json数据进行传递
        /// </summary>
        [DataContract]
        [Serializable]
        public class EasyTreeData
        {
            /// <summary>
            /// ID
            /// </summary>
            [DataMember]
            public string id { get; set; }
    
            /// <summary>
            /// 节点名称
            /// </summary>
            [DataMember]
            public string text { get; set; }
            
            /// <summary>
            /// 是否展开
            /// </summary>
            [DataMember]
            public string state  { get; set; }
    
            /// <summary>
            /// 图标样式
            /// </summary>
            [DataMember]
            public string iconCls { get; set; }
    
    
            /// <summary>
            /// 子节点集合
            /// </summary>
            [DataMember]
            public List<EasyTreeData> children { get; set; }
            
            /// <summary>
            /// 默认构造函数
            /// </summary>
            public EasyTreeData() 
            {
                this.children = new List<EasyTreeData>();
                this.state = "open";
            }
    
            /// <summary>
            /// 常用构造函数
            /// </summary>
            public EasyTreeData(string id, string text, string iconCls = "", string state = "open")
                : this()
            {
                this.id = id;
                this.text = text;
                this.state = state;
                this.iconCls = iconCls;
            }
    
            /// <summary>
            /// 常用构造函数
            /// </summary>
            public EasyTreeData(int id, string text, string iconCls = "", string state = "open")
                : this()
            {
                this.id = id.ToString();
                this.text = text;
                this.state = state;
                this.iconCls = iconCls;
            }
        }
    复制代码

    然后,我们在需要生成Json数据的地方,使用这个实体类进行承载,然后把它列表生成Json就可以了,很简单了,呵呵。

    复制代码
            /// <summary>
            /// 根据用户获取对应人员层次的树Json
            /// </summary>
            /// <param name="deptId">用户所在部门</param>
            /// <returns></returns>
            public ActionResult GetUserTreeJson(int deptId)
            {
                List<EasyTreeData> treeList = new List<EasyTreeData>();
                treeList.Insert(0, new EasyTreeData(-1, "无"));
    
                List<UserInfo> list = BLLFactory<User>.Instance.FindByDept(deptId);
                foreach (UserInfo info in list)
                {
                    treeList.Add(new EasyTreeData(info.ID, info.FullName, "icon-user"));
                }
    
                string json = ToJson(treeList);
                return Content(json);
            }
    复制代码

    如果需要递归的操作,一样的方式处理就可以了。

    复制代码
            /// <summary>
            /// 获取用户的部门树结构(分级需要)
            /// </summary>
            /// <param name="userId">用户ID</param>
            /// <returns></returns>
            public ActionResult GetMyDeptTreeJson(int userId)
            {
                StringBuilder content = new StringBuilder();
                UserInfo userInfo = BLLFactory<User>.Instance.FindByID(userId);
                if (userInfo != null)
                {
                    OUInfo groupInfo = GetMyTopGroup(userInfo);
                    if (groupInfo != null)
                    {
                        List<OUNodeInfo> list = BLLFactory<OU>.Instance.GetTreeByID(groupInfo.ID);
    
                        EasyTreeData treeData = new EasyTreeData(groupInfo.ID, groupInfo.Name, GetIconcls(groupInfo.Category));
                        GetTreeDataWithOUNode(list, treeData);
    
                        content.Append(base.ToJson(treeData));
                    }
                }
                string json = string.Format("[{0}]", content.ToString().Trim(','));
                return Content(json);
            }
    复制代码

    上面使用EasyTreeData来承载数据,然后构建列表,其本身就是一个多层级的树对象,然后一个ToJson的方法就可以把列表对象完美转换为Jason数据了。

    这里的ToJson,主要就是调用JavaScriptSerializer 对象进行的操作,如下所示。

    复制代码
            /// <summary>
            /// 把对象为json字符串
            /// </summary>
            /// <param name="obj">待序列号对象</param>
            /// <returns></returns>
            protected string ToJson(object obj)
            {
                string jsonData = (new JavaScriptSerializer()).Serialize(obj);
                return jsonData;
            }
    复制代码

    3、树控件效果展示

    在介绍如何使用它之后,我们来看看我几个场景中使用树控件进行的展示效果,方便我们加深上面EasyUI树控件使用的了解。

    1)组织机构列表如下所示:

    2)角色树列表展示

    3)功能树列表展示

    4)菜单树列表展示

    5)登陆日志树列表展示

    6)下拉列表树展示

      

        

     

    主要研究技术:代码生成工具、Visio二次开发、客户关系管理软件、送水管理软件等共享软件开发
    专注于Winform开发框架Web开发框架、WCF开发框架的研究及应用。
      转载请注明出处:
    撰写人:伍华聪  http://www.iqidi.com 
        

    ASP.NET是如何在IIS下工作的

    ASP.NET与IIS是紧密联系的,由于IIS6.0与IIS7.0的工作方式的不同,导致ASP.NET的工作原理也发生了相应的变化。

    IIS6(IIS7的经典模式)与IIS7的集成模式的不同

    IIS6的运行过程:

    IIS6运行图示

    分析上图可知:

        在 User Mode 下,http.sys 接收到 http request,然后它会根据 IIS 中的 Metabase 查看基于该 Request 的 Application 属于哪个 Application Pool, 如果该 Application Pool 不存在,则创建之。否则直接将 request 发到对应 Application Pool 的 Queue中。每个 Application Pool 对应着一个 Worker Process — w3wp.exe,(运行在 User Mode 下)。

        在 IIS Metabase 中维护着 Application Pool 和 Worker Process 的Mapping。WAS(Web Administrative Service)根据这样一个 mapping,将存在于某个 Application Pool Queue 的 request 传递到对应的 Worker Process (如果没有,就创建这样一个进程)。在 Worker Process 初始化的时候,加载 ASP.NET ISAPI,ASP.NET ISAPI 进而加载 CLR。最后通过 AppManagerAppDomainFactory 的 Create 方法为 Application 创建一个 Application Domain;通过 ISAPIRuntime 的  ProcessRequest 处理 Request,进而将流程进入到 ASP.NET Http Runtime Pipeline。

       几个知识点:

    • HTTP.SYS:(Kernel)的一个组件,它负责侦听(Listen)来自于外部的HTTP请求,根据请求的URL将其转发给相应的应用程序池 (Application Pool)。当此HTTP请求处理完成时,它又负责将处理结果发送出去.为了提供更好的性能,HTTP.SYS内部建立了一个缓冲区,将最近的HTTP请求处理结果保存起来。
    • Application Pool:  IIS总会保持一个单独的工作进程:应用程序池。所有的处理都发生在这个进程里,包括ISAPI dll的执行。对于IIS6而言,应用程序池是一个重大的改进,因为它们允许以更小的粒度控制一个指定进程的执行。你可以为每一个虚拟目录或者整个Web 站点配置应用程序池,这可以使你很容易的把每一个应用程序隔离到各自的进程里,这样就可以把它与运行在同一台机器上其他程序完全隔离。从Web处理的角度看,如果一个进程死掉,至少它不会影响到其它的进程。 
      当应用程序池接收到HTTP请求后,交由在此应用程序池中运行的工作者进程Worker Process: w3wp.exe来处理此HTTP请求。
    • Worker Process: 当工作者进程接收到请求后,首先根据后缀找到并加载对应的ISAPI扩展 (如:aspx 对应的映射是aspnet_isapi.dll),工作者进程加载完aspnet_isapi.dll后,由aspnet_isapi.dll负责加载 ASP.NET应用程序的运行环境即CLR (.NET Runtime)。 
      Worker Process运行在非托管环境,而.NET中的对象则运行在托管环境之上(CLR),它们之间的桥梁就是ISAPI扩展。
    • WAS(Web Admin Service):这是一个监控程序,它一方面可以存取放在InetInfo元数据库(Metabase)中的各种信息,另一方面也负责监控应用程序池(Application Pool)中的工作者进程的工作状态况,必要时它会关闭一个老的工作者进程并创建一个新的取而代之。

    IIS7的运行过程:

         IIS7运行图示

    分析上图可知:

        1、当客户端浏览器开始 HTTP 请求一个WEB 服务器的资源时,HTTP.sys 拦截到这个请求。

        2、HTTP.sys 联系 WAS 获取配置信息。

        3、WAS 向配置存储中心(applicationHost.config)请求配置信息。

        4、WWW 服务接收到配置信息,配置信息指类似应用程序池配置信息,站点配置信息等等。

        5、WWW 服务使用配置信息去配置 HTTP.sys 处理策略。

        6、WAS为请求创建一个进程(如果不存在的话)。

        7、工作者进程处理请求并对HTTP.sys做出响应。

        8、客户端接受到处理结果信息。

    除了IIS的整体运行方式不同之外,IIS7相比IIS6最大的不同之处在于它提供了两种应用程序池管道模式:

    经典模式:是与IIS 6或者之前版本保持兼容的一种模式,一个典型问题就是,在处理ASP.NET这种动态网站的时候,它是通过一个所谓的ISAPI程序,作为插件的方式来工作的。针对不同的动态应用程序(例如ASP,PHP等),会需要不同的ISAPI(Internet Server Application Programe Interface,互联网服务器应用程序接口)。如图,在IIS中,打开“处理程序映射”,可以看到aspx类型页面的处理程序为aspnet_isapi.dll。

    经典模式处理程序映射

    下图展示了IIS7经典模式与IIS6的应用程序池管道模式运行原理,针对不同的请求,会指定不同的ISAPI(dll)进行处理:

    经典模式运行图

    集成模式:asp.net不再像IIS6一样只限定于aspnet_isapi.dll中,而是被解放出来,从IIS接收到HTTP请求开始,即进入asp.net的控制范围,asp.net可以存在于一个请求在IIS中各个处理阶段。允许我们将ASP.NET更好地与IIS集成,甚至允许我们在ASP.NET中编写一些功能(例如Module)来改变IIS的行为(扩 展)。集成的好处是,不再通过ISAPI的方式,提高了速度和稳定性。至于扩展,则可以使得我们对于IIS,以及其他类型的请求有更多的控制。(例如,我 们希望静态网页也具备一些特殊的行为)。如图

    集成模式运行图

    如下图在IIS7集成模式中,打开处理程序映射,可以看到aspx类型页面所对应的不再是一个dll,而是一个类型。

    集成模式处理程序映射

    总结与扩展:

    对于处理ASP.NET应用程序而言,IIS6及IIS7的经典模式需要aspnet_isapi.dll来处理,而IIS7集成模式不需要aspnet_isapi.dll来处理,而可以直接根据文件扩展名找到相应的处理程序接口。例如aspx的处理程序是System.Web.UI.PageHandlerFactory类型。

    介绍完IIS的工作原理,来看一下ASP.NET内部的运行机制。

    首先看一下IIS处理模型:

    image

    上面介绍IIS工作原理时,已经介绍了从发起HTTP请求,到响应请求的过程,这里主要介绍当请求到达.NET Runtime之后,.NET运行时所发生的一系列工作。

    先看如下的.NET运行时工作序列图:

    .net运行时序列图


    1.HTTP请求进入Web服务器后,首先由HTTP.SYS来判断请求的页面是否存在,如果存在的话将把请求信息转交给.NET Runtime。在这部分实际是完成两个步骤,在将请求转交给.NET Runtime的同时将请求信息封存在HTTPWorkRequest类中供其它步骤调用。HttpWorkRequest类在以后的操作中至关重要,它第一次将Http请求信息转换为类信息。 
    2.当请求到达.NET Runtime后,接下来的操作将会在托管环境中完成,这时请求就真正进入了.NET中,对请求信息的操作是由.NET的底层类库来实现。首先.NET Runtime将会针对请求信息做两个动作,一是准备HostingEnvironment;二是调用ApplicationManager类为HTTP请求动态的分配AppDomain,并把处理权交给AppDomain。 
    3.HTTP请求进入AppDomain后,将由对象ISAPIRuntime来接管,一方面经方法ProcessRequest()得到HttpWorkerRequest对象,另一方面由方法StartProcessing()生成HttpRuntime对象,接下来把处理权交给了HttpRuntime(HttpWorkerRequest对象将作为HttpRuntime方法中的参数被使用)。 
    4.HTTPRuntime接收到Http请求后,方法ProcessRequest处理请求。将对第1步中的HTTPWorkRequest类中的信息进行操作,具体的实现由ProcessRequest方法实现。内部代码如下:

     
    1. [AspNetHostingPermission(SecurityAction.Demand, Level=AspNetHostingPermissionLevel.Medium)]  
    2. public static void ProcessRequest(HttpWorkerRequest wr)  
    3. {  
    4.     if (wr == null)  
    5.     {  
    6.         throw new ArgumentNullException("wr");  
    7.     }  
    8.     if (UseIntegratedPipeline)  
    9.     {  
    10.         throw new PlatformNotSupportedException(System.Web.SR.GetString("Method_Not_Supported_By_Iis_Integrated_Mode"new object[] { "HttpRuntime.ProcessRequest" }));  
    11.     }  
    12.     ProcessRequestNoDemand(wr);  
    13. }  
    14. internal static void ProcessRequestNoDemand(HttpWorkerRequest wr)  
    15. {  
    16.     RequestQueue queue = _theRuntime._requestQueue;  
    17.     if (queue != null)  
    18.     {  
    19.         wr = queue.GetRequestToExecute(wr);  
    20.     }  
    21.     if (wr != null)  
    22.     {  
    23.         CalculateWaitTimeAndUpdatePerfCounter(wr);  
    24.         wr.ResetStartTime();  
    25.         ProcessRequestNow(wr);  
    26.     }  
    27. }  
    28. internal static void ProcessRequestNow(HttpWorkerRequest wr)  
    29. {  
    30.     _theRuntime.ProcessRequestInternal(wr);  
    31. }  

    5.在HttpRunTime中经过一系列的驱动后,将会在ProcessRequestInternal方法中为Http请求分配应用程序。在这一步中还将创建HttpContext对象。

     
    1. context = new HttpContext(wr, false); // 基于HttpWorkerRequest生成HttpContext  
    2. IHttpHandler applicationInstance = HttpApplicationFactory.GetApplicationInstance(context); // 得到HttpApplication  
    3. handler2.BeginProcessRequest(context, this._handlerCompletionCallback, context); // 由HttpApplication处理请求  

    6.经过步骤5后HTTP请求信息才由基本信息转交给了Asp.net中的各个对象。接下来的操作会触发一些列的管道事件,这时的请求才真正转到HttpModule和HttpHandler中。 
    接下来我们看看常说的管道事件的创建过程:

     
    1. internal override void BuildSteps(WaitCallback stepCallback)  
    2. {  
    3.     ArrayList steps = new ArrayList();  
    4.     HttpApplication app = base._application;  
    5.     bool flag = false;  
    6.     UrlMappingsSection urlMappings = RuntimeConfig.GetConfig().UrlMappings;  
    7.     flag = urlMappings.IsEnabled && (urlMappings.UrlMappings.Count > 0);  
    8.     steps.Add(new HttpApplication.ValidatePathExecutionStep(app));  
    9.     if (flag)  
    10.     {  
    11.         steps.Add(new HttpApplication.UrlMappingsExecutionStep(app));  
    12.     }  
    13.     app.CreateEventExecutionSteps(HttpApplication.EventBeginRequest, steps);  
    14.     app.CreateEventExecutionSteps(HttpApplication.EventAuthenticateRequest, steps);  
    15.     app.CreateEventExecutionSteps(HttpApplication.EventDefaultAuthentication, steps);  
    16.     app.CreateEventExecutionSteps(HttpApplication.EventPostAuthenticateRequest, steps);  
    17.     app.CreateEventExecutionSteps(HttpApplication.EventAuthorizeRequest, steps);  
    18.     app.CreateEventExecutionSteps(HttpApplication.EventPostAuthorizeRequest, steps);  
    19.     app.CreateEventExecutionSteps(HttpApplication.EventResolveRequestCache, steps);  
    20.     app.CreateEventExecutionSteps(HttpApplication.EventPostResolveRequestCache, steps);  
    21.     steps.Add(new HttpApplication.MapHandlerExecutionStep(app));  
    22.     app.CreateEventExecutionSteps(HttpApplication.EventPostMapRequestHandler, steps);  
    23.     app.CreateEventExecutionSteps(HttpApplication.EventAcquireRequestState, steps);  
    24.     app.CreateEventExecutionSteps(HttpApplication.EventPostAcquireRequestState, steps);  
    25.     app.CreateEventExecutionSteps(HttpApplication.EventPreRequestHandlerExecute, steps);  
    26.     steps.Add(new HttpApplication.CallHandlerExecutionStep(app));  
    27.     app.CreateEventExecutionSteps(HttpApplication.EventPostRequestHandlerExecute, steps);  
    28.     app.CreateEventExecutionSteps(HttpApplication.EventReleaseRequestState, steps);  
    29.     app.CreateEventExecutionSteps(HttpApplication.EventPostReleaseRequestState, steps);  
    30.     steps.Add(new HttpApplication.CallFilterExecutionStep(app));  
    31.     app.CreateEventExecutionSteps(HttpApplication.EventUpdateRequestCache, steps);  
    32.     app.CreateEventExecutionSteps(HttpApplication.EventPostUpdateRequestCache, steps);  
    33.     this._endRequestStepIndex = steps.Count;  
    34.     app.CreateEventExecutionSteps(HttpApplication.EventEndRequest, steps);  
    35.     steps.Add(new HttpApplication.NoopExecutionStep());  
    36.     this._execSteps = new HttpApplication.IExecutionStep[steps.Count];  
    37.     steps.CopyTo(this._execSteps);  
    38.     this._resumeStepsWaitCallback = stepCallback;  
    39. }  

    管道事件请求序列图如下:

    管道

    人生没有回头路,珍惜当下。
     
    分类: asp.net
  • 相关阅读:
    C++中析构函数的作用,
    fp = fopen(s, "at") 中at 是啥意思,a 是append 追加的意思
    C++中 :: 的意思
    sed 指令
    make -e install ,,,make命令的-e选项!
    _AR="ar" _ARFLAGS="-ruv"
    gcc的-D和-U参数:宏的设置与取消 _CCFLAGS=" -w -enable-threads=posix -DLINUX -D_REENTRANT -DWORKONGN -Dlinux -D_GN_DETAIL_SDR_"
    GCC 编译详解
    RPC 编程 使用 RPC 编程是在客户机和服务器实体之间进行可靠通信的最强大、最高效的方法之一。它为在分布式计算环境中运行的几乎所有应用程序提供基础。
    vim插件ctags的安装和使用
  • 原文地址:https://www.cnblogs.com/Leo_wl/p/3669776.html
Copyright © 2011-2022 走看看