Community Server专题六:Delegates & Events

server

对于CS的分析你可以能会从页面开始,其实那并不是一个很好的方法,因为CS采用了MasterPage和内建的Theme与Skins,页面一层嵌套一层,如果你对CS页面执行机制不了解,或者你是初学者,这个时候可能就会碰壁,接着就放弃了对CS更深入的了解。我希望我的专题能从CS的运行过程开始一步一步地讲解,同时把ASP.NET的运行机理也表述出来,因此学习了解CS的过程就是对ASP.NET深入了解得过程。当然,我个人的开发经验与水平也是有限的,如果在专题中表述有问题,或者有疑问可以直接在文章的评论中直接指出,我将万分感谢你。

在分析CSHttpModule.cs的时候,你会看到这样两句代码:

CSEvents.UserKnown(csContext.User);
CSEvents.CSException(csException);

其实短短两行代码后面隐藏了Delegates与Events的大量运用,CS也通过这样的运用实现了一种模块化的处理机制,即CSModules。

打开CommunityServerWeb项目下的communityserver.config文件,这是CS的配置文件(与Web.config不同,communityserver.config主要配置的是CS内部的一些运行机制,而Web.config主要配置的是与Asp.net的交互)。找到文件中的这段:

<CSModules>
              <add name = "CSMembershipRulesModule" type = "CommunityServer.Components.CSMembershipRulesModule, CommunityServer.Components" />
              <add name = "CSCatastrophicExceptionModule" type = "CommunityServer.Components.CSCatastrophicExceptionModule, CommunityServer.Components" />
        <add name = "CSExceptionModule" type = "CommunityServer.Components.CSExceptionModule, CommunityServer.Components" />
              <add name = "IrcCommands" type = "CommunityServer.Discussions.Components.IrcCommandsModule, CommunityServer.Discussions" />
              <add name = "ForumCensorship" type = "CommunityServer.Discussions.Components.CensorshipModule, CommunityServer.Discussions" />
              <add name = "ForumEmoticon" type = "CommunityServer.Discussions.Components.EmoticonModule, CommunityServer.Discussions" />
              <add name = "ForumSourceCode" type = "CommunityServer.Discussions.Components.SourceCodeModule, CommunityServer.Discussions" />
              <add name = "ForumHtmlScrubbing" type = "CommunityServer.Discussions.Components.HtmlScrubbingModule, CommunityServer.Discussions" />
              <add name = "BBcodeToHtml" type = "CommunityServer.Discussions.Components.BBcodeToHtmlModule, CommunityServer.Discussions" />
              <add name = "ForumPlainText" type = "CommunityServer.Discussions.Components.PlainTextModule, CommunityServer.Discussions" />
              <add name = "WeblogCensorModule" type = "CommunityServer.Blogs.Components.CensorModule, CommunityServer.Blogs" />
              <add name = "WeblogPostandArticleHtmlScrubbing" type = "CommunityServer.Blogs.Components.PostandArticleHtmlScrubbing, CommunityServer.Blogs" />
              <add name = "WeblogFeedbackHtmlFormatting" type = "CommunityServer.Blogs.Components.FeedbackHtmlFormatting, CommunityServer.Blogs" />
              <add name = "TrackbackModule" type = "CommunityServer.Blogs.Components.TrackbackModule, CommunityServer.Blogs" />
              <add name = "XmlRpcPingModule" type = "CommunityServer.Blogs.Components.XmlRpcPingModule, CommunityServer.Blogs" />
              <add name = "WeblogFormattingModule" type = "CommunityServer.Blogs.Components.WeblogFormattingModule, CommunityServer.Blogs" />
              <add name = "PictureCensor" type = "CommunityServer.Galleries.Components.CensorPictureModule, CommunityServer.Galleries" />
              <add name = "PictureHtmlScrubber" type = "CommunityServer.Galleries.Components.HtmlScrubberModule, CommunityServer.Galleries" />
              <add name = "PictureComments" type = "CommunityServer.Galleries.Components.CommentModule, CommunityServer.Galleries" />
              <!-- <add name = "MaxPictureSize" type = "CommunityServer.Galleries.Components.MaxPictureSizeModule, CommunityServer.Galleries" maxWidth="1024" maxHeight="768" quality="90" /> -->
        </CSModules>

我们拿出其中的一个来分析运行过程,例:

<add name = "CSExceptionModule" type = "CommunityServer.Components.CSExceptionModule, CommunityServer.Components" />

这是CS中异常处理的模块,当发生异常的时候该模块将调用一个RedirectToMessage方法,提示一个友好的错误界面,告诉请求的用户有错误发生。那么CS系统是如何在发生错误的时候自动调用RedirectToMessage方法转向另外一个页面提示友好错误的呢?先打开CommunityServerComponents项目下Components文件夹中的CSApplication.cs

using System;
using System.Collections;
using System.ComponentModel;
using System.Web.Caching;
using System.Xml;
using CommunityServer.Configuration;
namespace CommunityServer.Components
{
     Delegates#region Delegates
     //Do we want one single delegate or a custom one for each type
     //public delegate void CSEventHandler(object sender, CSEventArgs e);
     public delegate void CSUserEventHandler(User user, CSEventArgs e);
     public delegate void CSPostEventHandler(Post post, CSEventArgs e);
     public delegate void CSSectionEventHandler(Section section, CSEventArgs e);
     public delegate void CSGroupEventHandler(Group group, CSEventArgs e);
     public delegate void CSExceptionHandler(CSException csEx, CSEventArgs e);
     #endregion
     /**//// <summary>
     /// Summary description for CSApplication.
     /// </summary>
     public class CSApplication
     {
         private members#region private members
         private EventHandlerList Events = new EventHandlerList();
         private static readonly object sync = new object();
         private Hashtable modules = new Hashtable();
         #endregion
         Event Keys (static)#region Event Keys (static)
         private static object EventAuthorizePost = new object();
         private static object EventPrePostUpdate = new object();
         private static object EventPreProcessPost = new object();
         private static object EventPostPostUpdate = new object();
         private static object EventRatePost = new object();
         //private static object EventPreRenderPost = new object();
         private static object EventPreUserUpdate = new object();
         private static object EventPostUserUpdate = new object();
         private static object EventUserRemove = new object();
         private static object EventUserKnown = new object();
         private static object EventUserValidated = new object();
         private static object EventPreSectionUpdate = new object();
         private static object EventPostSectionUpdate = new object();
         private static object EventPreSectionGroupUpdate = new object();
         private static object EventPostSectionGroupUpdate = new object();
         private static object EventUnhandledException = new object();
         #endregion
         cnstr#region cnstr
         private CSApplication()
         {
         }
         internal static CSApplication Instance()
         {
              const string key = "CSApplication";
              CSApplication app = CSCache.Get(key) as CSApplication;
              if(app == null)
              {
                   lock(sync)
                   {
                       app = CSCache.Get(key) as CSApplication;
                       if(app == null)
                       {
                            CSConfiguration config = CSContext.Current.Config;
                            XmlNode node = config.GetConfigSection("CommunityServer/CSModules");
                            app = new CSApplication();
                            if(node != null)
                            {
                                 foreach(XmlNode n in node.ChildNodes)
                                 {
                                     if(n.NodeType != XmlNodeType.Comment)
                                     {
                                          switch(n.Name)
                                          {
                                               case "clear":
                                                   app.modules.Clear();
                                                   break;
                                               case "remove":
                                                   app.modules.Remove(n.Attributes["name"].Value);
                                                   break;
                                               case "add":
                                                   string name = n.Attributes["name"].Value;
                                                   string itype = n.Attributes["type"].Value;
                                                   Type type = Type.GetType(itype);
                                                   if(type == null)
                                                        throw new Exception(itype + " does not exist");
                                                   ICSModule mod = Activator.CreateInstance(type) as ICSModule;
                                                  if(mod == null)
                                                        throw new Exception(itype + " does not implement ICSModule or is not configured correctly");
                                                   mod.Init(app, n);
                                                   app.modules.Add(name,mod);
                                                   break;
                                          }
                                     }
                                 }
                            }
                            CacheDependency dep = new CacheDependency(null, new string[]{CSConfiguration.CacheKey});
                            CSCache.Max(key, app,dep);
                       }
                   }
              }
              return app;
         }
         #endregion
         Post Events#region Post Events
         Execute Events#region Execute Events
         internal void ExecuteAuthorizePost()
         {
              ExecuteUserEvent(EventAuthorizePost,CSContext.Current.User);
         }
         internal void ExecutePrePostEvents(Post post, ObjectState state, ApplicationType appType)
         {
              ExecutePostEvent(EventPreProcessPost,post,state,appType);
         }
         internal void ExecutePrePostUpdateEvents(Post post, ObjectState state, ApplicationType appType)
         {
              ExecutePostEvent(EventPrePostUpdate,post,state,appType);
         }
         internal void ExecutePostPostUpdateEvents(Post post, ObjectState state, ApplicationType appType)
         {
              ExecutePostEvent(EventPostPostUpdate,post,state,appType);
         }
         internal void ExecuteRatePostEvents(Post post, ApplicationType appType)
         {
              ExecutePostEvent(EventRatePost,post,ObjectState.None,appType);
         }
//       internal void ExecutePrePostRender(Post post, ApplicationType appType)
//       {
//            ExecutePostEvent(EventPreRenderPost,post,ObjectState.None,appType);
//       }
         protected void ExecutePostEvent(object EventKey, Post post,ObjectState state, ApplicationType appType)
         {
              CSPostEventHandler handler = Events[EventKey] as CSPostEventHandler;
              if (handler != null)
              {
                   handler(post, new CSEventArgs(state,appType));
              }
         }
         #endregion
         Events#region Events
         /**//// <summary>
         /// Event raised before a user accesses a page which can be used to create content
         /// </summary>
         public event CSUserEventHandler AuthorizePost
         {
              add{Events.AddHandler(EventAuthorizePost, value);}
              remove{Events.RemoveHandler(EventAuthorizePost, value);}
         }
         /**//// <summary>
         /// Event raised before any post processing takes place
         /// </summary>
         public event CSPostEventHandler PreProcessPost
         {
              add{Events.AddHandler(EventPreProcessPost, value);}
              remove{Events.RemoveHandler(EventPreProcessPost, value);}
         }
         /**//// <summary>
         /// Fires after PreProcessPost but before the post change is commited to the datastore
         /// </summary>
         public event CSPostEventHandler PrePostUpdate
         {
              add{Events.AddHandler(EventPrePostUpdate, value);}
              remove{Events.RemoveHandler(EventPrePostUpdate, value);}
         }
         /**//// <summary>
         /// Fires after a post change is commited to the datastore
         /// </summary>
         public event CSPostEventHandler PostPostUpdate
         {
              add{Events.AddHandler(EventPostPostUpdate, value);}
              remove{Events.RemoveHandler(EventPostPostUpdate, value);}
         }
         /**//// <summary>
         /// Fires after a Post or Thread is rated
         /// </summary>
         public event CSPostEventHandler RatePost
         {
              add{Events.AddHandler(EventRatePost, value);}
              remove{Events.RemoveHandler(EventRatePost, value);}
         }
//       /// <summary>
//       /// Event raised before an individual post is rendered
//       /// </summary>
//       public event CSPostEventHandler PreRenderPost
//       {
//            add{Events.AddHandler(EventPreRenderPost, value);}
//            remove{Events.RemoveHandler(EventPreRenderPost, value);}
//       }
         #endregion
         #endregion
         User Events#region User Events
         Execute Events#region Execute Events
         internal void ExecuteUserValidated(User user)
         {
              ExecuteUserEvent(EventUserValidated,user);
         }
         internal void ExecuteUserKnown(User user)
         {
              ExecuteUserEvent(EventUserKnown,user);
         }
         internal void ExecutePreUserUpdate(User user, ObjectState state)
         {
              ExecuteUserEvent(EventPreUserUpdate,user,state,ApplicationType.Unknown);
         }
         internal void ExecutePostUserUpdate(User user, ObjectState state)
         {
              ExecuteUserEvent(EventPostUserUpdate,user,state,ApplicationType.Unknown);
         }
         internal void ExecuteUserRemove(User user)
         {
              ExecuteUserEvent(EventUserRemove,user,ObjectState.Delete,ApplicationType.Unknown);
         }
         protected void ExecuteUserEvent(object EventKey, User user)
         {
              ExecuteUserEvent(EventKey,user,ObjectState.None,ApplicationType.Unknown);
         }
         protected void ExecuteUserEvent(object EventKey, User user,ObjectState state, ApplicationType appType)
         {
              CSUserEventHandler handler = Events[EventKey] as CSUserEventHandler;
              if (handler != null)
              {
                   handler(user, new CSEventArgs(state,appType));
              }
         }
         #endregion
         Events#region Events
         /**//// <summary>
         /// Fires after a user's credentials have been validated.
         /// </summary>
         public event CSUserEventHandler UserValidated
         {
              add{Events.AddHandler(EventUserValidated, value);}
              remove{Events.RemoveHandler(EventUserValidated, value);}
         }
         /**//// <summary>
         /// Fires once the current user has been identified. This user may still be anonymous.
         /// </summary>
         public event CSUserEventHandler UserKnown
         {
              add{Events.AddHandler(EventUserKnown, value);}
              remove{Events.RemoveHandler(EventUserKnown, value);}
         }
         /**//// <summary>
         /// Fires before a User is saved/updated to the datastore
         /// </summary>
         public event CSUserEventHandler PreUserUpdate
         {
              add{Events.AddHandler(EventPreUserUpdate, value);}
              remove{Events.RemoveHandler(EventPreUserUpdate, value);}
         }
         /**//// <summary>
         /// Fires after a User is saved/updated to the datastore
         /// </summary>
         public event CSUserEventHandler PostUserUpdate
         {
              add{Events.AddHandler(EventPostUserUpdate, value);}
              remove{Events.RemoveHandler(EventPostUserUpdate, value);}
         }
         /**//// <summary>
         /// Fires before a User is removed from the datastore.
         /// </summary>
         public event CSUserEventHandler UserRemove
         {
              add{Events.AddHandler(EventUserRemove, value);}
              remove{Events.RemoveHandler(EventUserRemove, value);}
         }
         #endregion
         #endregion
         Section Events#region Section Events
         internal void ExecutePreSectionUpdate(Section section, ObjectState state, ApplicationType appType)
         {
              CSSectionEventHandler handler = Events[EventPreSectionUpdate] as CSSectionEventHandler;
              if (handler != null)
              {
                   handler(section, new CSEventArgs(state,appType));
              }
         }
         internal void ExecutePostSectionUpdate(Section section, ObjectState state, ApplicationType appType)
         {
              CSSectionEventHandler handler = Events[EventPostSectionUpdate] as CSSectionEventHandler;
              if (handler != null)
              {
                   handler(section, new CSEventArgs(state,appType));
              }
         }
         /**//// <summary>
         /// Event raised before a section change is committed to the datastore (create/update)
         /// </summary>
         public event CSSectionEventHandler PreSectionUpdate
         {
              add{Events.AddHandler(EventPreSectionUpdate, value);}
              remove{Events.RemoveHandler(EventPreSectionUpdate, value);}
         }
         /**//// <summary>
         /// Event raised after a section chage is committed to the data store
         /// </summary>
         public event CSSectionEventHandler PostSectionUpdate
         {
              add{Events.AddHandler(EventPostSectionUpdate, value);}
              remove{Events.RemoveHandler(EventPostSectionUpdate, value);}
         }
         #endregion
         Group Events#region Group Events
         internal void ExecutePreSectionGroupUpdate(Group group, ObjectState state, ApplicationType appType)
         {
              CSGroupEventHandler handler = Events[EventPreSectionGroupUpdate] as CSGroupEventHandler;
              if (handler != null)
              {
                   handler(group, new CSEventArgs(state,appType));
              }
         }
         internal void ExecutePostSectionGroupUpdate(Group group, ObjectState state, ApplicationType appType)
         {
              CSGroupEventHandler handler = Events[EventPostSectionGroupUpdate] as CSGroupEventHandler;
              if (handler != null)
              {
                   handler(group, new CSEventArgs(state,appType));
              }
         }
         /**//// <summary>
         /// Event raised before a group chage is committed to the datastore (create/update)
         /// </summary>
         public event CSGroupEventHandler PreSectionGroupUpdate
         {
              add{Events.AddHandler(EventPreSectionGroupUpdate, value);}
              remove{Events.RemoveHandler(EventPreSectionGroupUpdate, value);}
         }
         /**//// <summary>
         /// Event raised after a group chage is committed to the data store
         /// </summary>
         public event CSGroupEventHandler PostSectionGroupUpdate
         {
              add{Events.AddHandler(EventPostSectionGroupUpdate, value);}
              remove{Events.RemoveHandler(EventPostSectionGroupUpdate, value);}
         }
         #endregion
         Exceptions#region Exceptions
         /**//// <summary>
         /// Event raised before a group chage is committed to the datastore (create/update)
         /// </summary>
         public event CSExceptionHandler CSException
         {
              add{Events.AddHandler(EventUnhandledException, value);}
              remove{Events.RemoveHandler(EventUnhandledException, value);}
         }
         internal void ExecuteCSExcetion(CSException csEx)
         {
              CSExceptionHandler handler = Events[EventUnhandledException] as CSExceptionHandler;
              if (handler != null)
              {
                   handler(csEx,new CSEventArgs());
              }
         }
         #endregion
     }
}

文件太长,我们抓出关键的部分来分析:

public delegate void CSExceptionHandler(CSException csEx, CSEventArgs e);

这里先申明一个委托,相当于一个函数指针。在通俗一点理解它就是一个跑腿的,专管传递对象与对象间的调用信息。

接下来:

internal static CSApplication Instance()
         {
              const string key = "CSApplication";
              CSApplication app = CSCache.Get(key) as CSApplication;
              if(app == null)
              {
                   lock(sync)
                   {
                       app = CSCache.Get(key) as CSApplication;
                       if(app == null)
                       {
                            CSConfiguration config = CSContext.Current.Config;
                            XmlNode node = config.GetConfigSection("CommunityServer/CSModules");
                            app = new CSApplication();
                            if(node != null)
                            {
                                 foreach(XmlNode n in node.ChildNodes)
                                 {
                                     if(n.NodeType != XmlNodeType.Comment)
                                     {
                                          switch(n.Name)
                                          {
                                               case "clear":
                                                   app.modules.Clear();
                                                   break;
                                               case "remove":
                                                   app.modules.Remove(n.Attributes["name"].Value);
                                                   break;
                                               case "add":
                                                   string name = n.Attributes["name"].Value;
                                                   string itype = n.Attributes["type"].Value;
                                                   Type type = Type.GetType(itype);
                                                   if(type == null)
                                                        throw new Exception(itype + " does not exist");
                                                   ICSModule mod = Activator.CreateInstance(type) as ICSModule;
                                                   if(mod == null)
                                                        throw new Exception(itype + " does not implement ICSModule or is not configured correctly");
                                                   mod.Init(app, n);
                                                   app.modules.Add(name,mod);
                                                   break;

                                          }

                                     }

                                 }

                            }
                            CacheDependency dep = new CacheDependency(null, new string[]{CSConfiguration.CacheKey});
                           CSCache.Max(key, app,dep);
                       }
                   }
              }
             return app;
         }

这段很重要,通过读取communityserver.config文件的<CSModules>,初始化每个CSModule,注意,初始化后并且调用了这些CSModule中的Init方法。具体看看这些Module中的Init都做了什么,打开CommunityServerComponents项目下的Components文件夹中的CSExceptionModule.cs:

using System;
using System.Web;
namespace CommunityServer.Components
{
     /**//// <summary>
     /// Summary description for CSExceptionModule.
     /// </summary>
     public class CSExceptionModule : ICSModule
     {
         public CSExceptionModule()
         {
              //
              // TODO: Add constructor logic here
              //
         }
          ICSModule Members#region ICSModule Members
         public void Init(CSApplication csa, System.Xml.XmlNode node)
         {
              csa.CSException +=new CSExceptionHandler(csa_CSException);
         }
         #endregion

         private void csa_CSException(CSException csEx, CSEventArgs e)
         {
              CSContext csContext = CSContext.Current;
              if (csEx.ExceptionType != CSExceptionType.UnknownError && csContext.IsWebRequest)
              {
                   RedirectToMessage(csContext.Context, csEx);
              }
         }
         private static void RedirectToMessage (HttpContext context, CSException exception)
         {
              if ((exception.InnerException != null) && ( exception.InnerException is CSException))
              {
                   CSException inner = (CSException) exception.InnerException;
              }
              context.Response.Redirect(Globals.GetSiteUrls().Message( exception.ExceptionType ), true);
         }
     }
}

哈哈,原来在Init方法里把一个CSExceptionHandler委托添加到CSException事件上,这个委托指向csa_CSException方法,还是通俗点说:如果CSException这个事件发生了,CSExceptionHandler这个跑腿的委托就会马上告诉csa_CSException方法要他执行,如果事件没有被激发就什么也不做。

名词: event 关键字使您得以指定当代码中的某些“事件”发生时调用的委托。此委托可以有一个或多个关联的方法,当代码指示该事件已发生时将调用关联的方法。

那么这个CSException又是怎么回事?在哪里定义的?我们回到CSApplication.cs文件中,看样几行:

         public event CSExceptionHandler CSException
         {
              add{Events.AddHandler(EventUnhandledException, value);}
              remove{Events.RemoveHandler(EventUnhandledException, value);}
     }

这里定义了一个CSException事件,而事件发生的时候只能用CSExceptionHandler这个委托来做跑腿的。其实CS中是把委托都存放在了一个EventHandlerList中,因此此处你可以看到add与remove, 这是访问器的声明,用于添加或移除客户代码中的事件处理程序,这样做的好处是公开大量的事件但不为每个事件分配字段,而是使用EventHandlerList存储这些事件实例。为了理解事件的调用执行过程,我们还必须看几个文件:CSEvents.cs、CSEventArgs.cs:

CSEventArgs.cs存储事件的数据,这个很好理解,它继承自EventArgs。当事件发生时CSEventArgs用来传递事件的信息,这里传递两个值:ObjectState与ApplicationType(可以在Enumerations文件夹下找到这两个枚举的内容)

CSEvents.cs这是对事件调用的一个包装器,看异常处理的包装:

         public static void CSException(CSException csEx)
         {
              CSApplication.Instance().ExecuteCSExcetion(csEx);
          }

这里先调用CSApplication.Instance()方法,实例化一个CSApplication对象,如果你是第一次调用Instance()方法,就实例化所有在<CSModules>中配置的类,并且调用他们的Init方法(在CSModules中配置的这些类,都实现了ICSModule接口,而这个接口要求继承他的类都具备Init方法),执行Init方法的目的就是把委托添加到事件上,使委托指向的方法可以在事件触发的时候被调用。实例化后再调用ExecuteCSExcetion方法并且传递CSException的实例,ExecuteCSExcetion方法如下:

         internal void ExecuteCSExcetion(CSException csEx)
         {
              CSExceptionHandler handler = Events[EventUnhandledException] as CSExceptionHandler;
              if (handler != null)
              {
                   handler(csEx,new CSEventArgs());
              }
         }

先通过对EventHandlerList索引访问,即Events[EventUnhandledException],从列表中找到这个CSExceptionHandler事件,如果不为null就执行它。EventUnhandledException又是什么,其实这只是一个Key,用来标示存储的事件。

有必要总结一下,不然你会被这种调用来调用去的关系搞得一头雾水,

以异常处理为例:

1:在错误发生后,调用Application_OnError方法;

2:在方法的最后调用CSEvents.CSException(csException);

3:进入CSEvents包装器,调用CSApplication.Instance().ExecuteCSExcetion(csEx);

4:执行CSApplication.Instance()方法,如果是第一次执行就根据communityserver.config文件中的配置,把所有的CSModules实例化,并且调用ICSModule接口类中的Init方法,然后缓存这些实例化的类(如果是第二次访问就从缓存中读取)。

5:在实现ICSModule接口的类中,如CSExceptionModule.cs,Init方法是给事件添加委托的过程,这个过程中实现了委托指向的一个或者多个方法与事件进行关联,异常处理的方法csa_CSException(CSException csEx, CSEventArgs e)就是在这里被关联到异常事件上的。

6:经过上面几步后,CS系统接着调用ExecuteCSExcetion方法,在ExecuteCSExcetion方触发了CSException事件

7:CSException事件被触发后,就执行事件中委托所指向的函数,这里是CSExceptionModule.cs文件中的private void csa_CSException(CSException csEx, CSEventArgs e)。

CS如此大量的使用Delegates与Events带来了什么,也许你会认为它这样是把问题复杂化,而且觉得这非常没有必要,完全可以在异常处理的最后调用处理方法即可,何必通过事件来回周转!最后说明一下这样做的重要性:

1:通过事件使调用方法者与方法本身隔离,如在CSHttpModule.cs文件中的Application_OnError方法触发CSEvents.CSException事件,而事件要做些什么处理,需要调用什么方法Application_OnError根本不知道。如果你要改变CSEvents.CSException事件处理方法的结构,甚至十处理方法的名称,Application_OnError也不需要改动,因为他根本不关心具体的实现,它的任务只是触发这个事件。

2:如果你想一个方法调用多个方法,普通的做法就是在方法中一次调用或者在方法中嵌套调用。这样做并不是一个好的设计模式,而事件可以通过委托调用多个委托指向的方法(在异常处理中只指向了一个方法,当然你可以指向任意N个方法),而这种调用也是相互隔离的,被调用的方法并不致到谁调用它,而调用者也不关心它调用谁。

3:模块化,你?

时间: 2024-10-04 09:33:22

Community Server专题六:Delegates & Events的相关文章

Community Server专题八:MemberRole之Membership深入篇

server 专题八的上篇大致讨论了MemberRole中的Membership实现,对于运用Membership进行web开发足够,但是对于想更深入了解Membership实现机理的朋友那是远远不够的,这个专题我们更深入一下了解Membership. 其实MemberRole是一个非常好的资源包,借住Reflector这个优秀的工具,你可以对其进行代码分析.它无论是在组建的构架.代码的设计.数据库表的建立.存储过程的使用等都是非常优秀的,你是程序员也好构架师也罢,其中可以学习的真的很多很多,我

Swift语法专题六——流程控制

Swift讲解专题六--流程控制 一.引言         一种编程语言的强大与否,很大程度上取决于其提供的程序流程控制方案,就如使用汇编语言实现复杂的程序流程是一件痛苦的事情.Swift中提供了许多强大的流程控制语句,例如快速遍历for-in,while循环,repeat-while循环,switch选择等,需要注意的是,在Swift2.2中,for(a;b;c)循环已经被弃用掉,并且Swift中的Switch语句也更加强大,可以处理任意数据类型. 二.for-in循环         配合范

RDS SQL Server - 专题分享 - 巧用执行计划缓存之索引缺失

title: RDS SQL Server - 专题分享 - 巧用执行计划缓存之索引缺失 author: 风移 摘要 执行计划缓存是MSSQL Server内存管理十分重要的部分,同样如何巧用执行计划缓存来解决我们平时遇到的一系列问题也是一个值得深入研究的专题.这篇文章是如何巧用执行计划缓存的开篇,分享如何使用执行计划缓存来分析索引缺失(Missing Indexes). 问题引入 缺失索引是SQL Server CPU使用率居高不下的第一大杀手,也是SQL Server数据库非常大的潜在风险点

Community Server专题一:概述Community Server_实用技巧

Community Server专题一:概述Community Server Community Server(CS)是一个非常优秀的Asp.net开源软件,目前官方发布的系统中包括三个部分:Asp.net Forums.DotText.Gallery.如果你是某个以CS构架网站的会员,你可以很容易的就拥有一个Blog.一个相册.还能在论坛上与他人一起进行讨论,这样就形成一个以User为中心的社区,这也就是起名为 Community Server的意义所在了. CS的构架很巧妙,三套原本不同的开

Community Server专题二:体系结构_实用技巧

Community Server专题二:体系结构 在进行CS细节分析的之前,有必要先了解CS工程(解决方案)的组成,以及组成CS工程中项目的结构,本文分为三个部分:1.工程结构 2.三层构架 3.数据库构架. 1:工程结构 =538) {this.width=538;}" border=0> CS工程主要分为4个部分 a:系统底层构架项目CommunityServerComponents.CommunityServerControls,提供给其他项目父类.接口.全局变量.CS系统设置.公用

Community Server专题三:HttpModule

server 从专题三开始分析Community Server的一些具体的技术实现,根据IIS对请求的处理流程,从HttpModule& HttpHandler切入话题,同时你也可以通过一系列的专题了解CS的运行过程,不只如此,所有的.Net 1.1 构架的Web App都是以同样的顺序执行的. 先了解一下IIS系统.它是一个程序,负责对网站的内容进行管理并且处理对客户的请求做出反应.当用户对一个页面提出请求时,IIS做如下反应(不考虑权限问题): 1.把对方请求的虚拟路径转换成物理路径 2.根

Community Server专题七: Job &amp; Timer

server 在CSHttpModule.cs文件中的Init方法下有这样一行: 接着在Dispose方法中还有这么一行: Job?什么是Job,在CS运行过程中有什么用途,又是如何运行的?这篇专题将叙述Job的工作流程. 你可以这里理解CS中的Job:"干一些零碎事情的钟点工". 讲解之前要先了解一个接口:IDisposable,MSDN是这样定义的:定义一种释放分配的非托管资源的方法.当托管对象不再使用时,垃圾回收器会自动释放分配给该对象的内存,不过,进行垃圾回收的时间不可预知.另

Community Server专题八:MemberRole之Membership

server MemberRole是一个在asp.net 1.1下实现用户管理.角色管理.用户特性信息存储(profile)等的一个组件,该组件被ASP.NET 2.0 Beta 2所采用,也就是ASP.NET 2.0 Beta 2中所说的Membership and Roles.如果你在asp.net 1.1下采用了MemberRole,那么你的web程序将会很容易的过渡到asp.net 2.0,另外多个采取MemberRole进行用户管理的web程序需要整合时也非常容易.我将分4个专题来分析

Community Server专题四:HttpHandler

server HttpHandler实现了ISAPI Extention的功能,他处理请求(Request)的信息和发送响应(Response).HttpHandler功能的实现通过实现IHttpHandler接口来达到. 看图先: 在ASP.NET 管道处理的末端是HTTP Hander,其实每个Asp.net的Page都实现了IHttpHander,在VS.net中的对象察看器中你可以证实这一点 具体的类是这样定义的:public class Page : TemplateControl,