源码网商城,靠谱的源码在线交易网站 我的订单 购物车 帮助

源码网商城

Community Server专题三:HttpModule

  • 时间:2021-07-04 00:26 编辑: 来源: 阅读:
  • 扫一扫,手机访问
摘要:Community Server专题三:HttpModule
从专题三开始分析Community Server的一些具体的技术实现,根据IIS对请求的处理流程,从HttpModule&  HttpHandler切入话题,同时你也可以通过一系列的专题了解CS的运行过程,不只如此,所有的.Net 1.1 构架的Web App都是以同样的顺序执行的。 先了解一下IIS系统。它是一个程序,负责对网站的内容进行管理并且处理对客户的请求做出反应。当用户对一个页面提出请求时,IIS做如下反应(不考虑权限问题): 1.把对方请求的虚拟路径转换成物理路径 2.根据物理路径搜索请求的文件 3.找到文件后,获取文件的内容 4.生成Http头信息。 5.向客户端发送所有的文件内容:首先是头信息,然后是Html内容,最后是其它文件的内容。 6.客户端IE浏览器获得信息后,解析文件内容,找出其中的引用文件,如.js .css .gif等,向IIS请求这些文件。 7.IIS获取请求后,发送文件内容。 8.当浏览器获取所有内容后,生成内容界面,客户就看到图像/文本/其它内容了。 但是IIS本身是不支持动态页面的,也就是说它仅仅支持静态html页面的内容,对于如.asp,.aspx,.cgi,.php等,IIS并不会处理这些标记,它就会把它当作文本,丝毫不做处理发送到客户端。为了解决这个问题。IIS有一种机制,叫做ISAPI的筛选器,这个东西是一个标准组件(COM组件),当在在访问IIS所不能处理的文件时,如asp.net 1.1 中的IIS附加ISAPI筛选器如图: Asp.net 服务在注册到IIS的时候,会把每个扩展可以处理的文件扩展名注册到IIS里面(如:*.ascx、*.aspx等)。扩展启动后,就根据定义好的方式来处理IIS所不能处理的文件,然后把控制权跳转到专门处理代码的进程中。让这个进程开始处理代码,生成标准的HTML代码,生成后把这些代码加入到原有的 Html中,最后把完整的Html返回给IIS,IIS再把内容发送到客户端。     有上面对ISAPI的简单描述,我们把HttpModule& HttpHandler分开讨论,并且结合CS进行具体的实现分析。 HttpModule: HttpModule实现了ISAPI Filter的功能,是通过对IhttpModule接口的继承来处理。下面打开CS中的CommunityServerComponents项目下的CSHttpModule.cs文件(放在HttpModule目录) //------------------------------------------------------------------------------ // <copyright company="Telligent Systems"> //     Copyright (c) Telligent Systems Corporation.  All rights reserved. // </copyright>  //------------------------------------------------------------------------------ using System; using System.IO; using System.Web; using CommunityServer.Components; using CommunityServer.Configuration; namespace CommunityServer  {     // *********************************************************************     //  CSHttpModule     //     /**//// <summary>     /// This HttpModule encapsulates all the forums related events that occur      /// during ASP.NET application start-up, errors, and end request.     /// </summary>     // ***********************************************************************/     public class CSHttpModule : IHttpModule      {         Member variables and inherited properties / methods#region Member variables and inherited properties / methods         public String ModuleName          {              get { return "CSHttpModule"; }          }             // *********************************************************************         //  ForumsHttpModule         //         /**//// <summary>         /// Initializes the HttpModule and performs the wireup of all application         /// events.         /// </summary>         /// <param name="application">Application the module is being run for</param>         public void Init(HttpApplication application)          {              // Wire-up application events             //             application.BeginRequest += new EventHandler(this.Application_BeginRequest);             application.AuthenticateRequest += new EventHandler(Application_AuthenticateRequest);             application.Error += new EventHandler(this.Application_OnError);             application.AuthorizeRequest += new EventHandler(this.Application_AuthorizeRequest);             //settingsID = SiteSettingsManager.GetSiteSettings(application.Context).SettingsID;             Jobs.Instance().Start();             //CSException ex = new CSException(CSExceptionType.ApplicationStart, "Appication Started " +  AppDomain.CurrentDomain.FriendlyName);             //ex.Log();         }         //int settingsID;         public void Dispose()          {             //CSException ex = new CSException(CSExceptionType.ApplicationStop, "Application Stopping " +  AppDomain.CurrentDomain.FriendlyName);             //ex.Log(settingsID);             Jobs.Instance().Stop();         }         Installer#region Installer         #endregion         #endregion         Application OnError#region Application OnError         private void Application_OnError (Object source, EventArgs e)          {             HttpApplication application = (HttpApplication)source;             HttpContext context = application.Context;             CSException csException = context.Server.GetLastError() as CSException;             if(csException == null)                 csException = context.Server.GetLastError().GetBaseException() as CSException;             try             {                 if (csException != null)                 {                     switch (csException.ExceptionType)                      {                         case CSExceptionType.UserInvalidCredentials:                         case CSExceptionType.AccessDenied:                         case CSExceptionType.AdministrationAccessDenied:                         case CSExceptionType.ModerateAccessDenied:                         case CSExceptionType.PostDeleteAccessDenied:                         case CSExceptionType.PostProblem:                         case CSExceptionType.UserAccountBanned:                         case CSExceptionType.ResourceNotFound:                         case CSExceptionType.UserUnknownLoginError:                         case CSExceptionType.SectionNotFound:                             csException.Log();                             break;                     }                 }                  else                  {                     Exception ex = context.Server.GetLastError();                     if(ex.InnerException != null)                         ex = ex.InnerException;                     csException = new CSException(CSExceptionType.UnknownError, ex.Message, context.Server.GetLastError());                     System.Data.SqlClient.SqlException sqlEx = ex as System.Data.SqlClient.SqlException;                     if(sqlEx == null || sqlEx.Number != -2) //don't log time outs                         csException.Log();                 }             }             catch{} //not much to do here, but we want to prevent infinite looping with our error handles             CSEvents.CSException(csException);         }         #endregion         Application AuthenticateRequest#region Application AuthenticateRequest         private void Application_AuthenticateRequest(Object source, EventArgs e)          {             HttpContext context = HttpContext.Current;             Provider p = null;             ExtensionModule module = null;             // If the installer is making the request terminate early             if (CSConfiguration.GetConfig().AppLocation.CurrentApplicationType == ApplicationType.Installer) {                 return;             }             // Only continue if we have a valid context             //             if ((context == null) || (context.User == null))                 return;             try              {                 // Logic to handle various authentication types                 //                 switch(context.User.Identity.GetType().Name.ToLower())                 {                         // Microsoft passport                     case "passportidentity":                         p = (Provider) CSConfiguration.GetConfig().Extensions["PassportAuthentication"];                         module = ExtensionModule.Instance(p);                         if(module != null)                             module.ProcessRequest();                         else                             goto default;                         break;                         // Windows                     case "windowsidentity":                         p = (Provider) CSConfiguration.GetConfig().Extensions["WindowsAuthentication"];                         module = ExtensionModule.Instance(p);                         if(module != null)                             module.ProcessRequest();                         else                             goto default;                         break;                         // Forms                     case "formsidentity":                         p = (Provider) CSConfiguration.GetConfig().Extensions["FormsAuthentication"];                         module = ExtensionModule.Instance(p);                         if(module != null)                             module.ProcessRequest();                         else                             goto default;                         break;                         // Custom                     case "customidentity":                         p = (Provider) CSConfiguration.GetConfig().Extensions["CustomAuthentication"];                         module = ExtensionModule.Instance(p);                         if(module != null)                             module.ProcessRequest();                         else                             goto default;                         break;                     default:                         CSContext.Current.UserName = context.User.Identity.Name;                         break;                 }             }              catch( Exception ex )              {                 CSException forumEx = new CSException( CSExceptionType.UnknownError, "Error in AuthenticateRequest", ex );                 forumEx.Log();                 throw forumEx;             }             //            // Get the roles the user belongs to             //            //             //            Roles roles = new Roles();             //            roles.GetUserRoles();         }         #endregion         Application AuthorizeRequest#region Application AuthorizeRequest         private void Application_AuthorizeRequest (Object source, EventArgs e) {             if (CSConfiguration.GetConfig().AppLocation.CurrentApplicationType == ApplicationType.Installer)             {                 //CSContext.Create(context);                 return;             }             HttpApplication application = (HttpApplication)source;             HttpContext context = application.Context;             CSContext csContext = CSContext.Current;             //bool enableBannedUsersToLogin = CSContext.Current.SiteSettings.EnableBannedUsersToLogin; //            // If the installer is making the request terminate early //            if (csContext.ApplicationType == ApplicationType.Installer) { //                return; //            }             //csContext.User = CSContext.Current.User;             CSEvents.UserKnown(csContext.User);             ValidateApplicationStatus(csContext);             // Track anonymous users             //             Users.TrackAnonymousUsers(context);             // Do we need to force the user to login?             //             if (context.Request.IsAuthenticated)              {                 string username = context.User.Identity.Name;                 if (username != null)                  {                     string[] roles = CommunityServer.Components.Roles.GetUserRoleNames(username);                     if (roles != null && roles.Length > 0)                      {                         csContext.RolesCacheKey = string.Join(",",roles);                     }                 }             }         }         #endregion         Application BeginRequest#region Application BeginRequest         private void Application_BeginRequest(Object source, EventArgs e)          {             HttpApplication application = (HttpApplication)source;             HttpContext context = application.Context;                          CSConfiguration config = CSConfiguration.GetConfig();             // If the installer is making the request terminate early             if (config.AppLocation.CurrentApplicationType == ApplicationType.Installer)             {                 //CSContext.Create(context);                 return;             }             CheckWWWStatus(config,context);                          CSContext.Create(context, ReWriteUrl(context));                                              }         private void CheckWWWStatus(CSConfiguration config, HttpContext context)         {             if(config.WWWStatus == WWWStatus.Ignore)                 return;             const string withWWW = "[url=http://www.%22;/]http://www.";[/url]             const string noWWW = "[url=http://%22;/]http://";[/url]             string rawUrl = context.Request.Url.ToString().ToLower();             bool isWWW = rawUrl.StartsWith(withWWW);                          if(config.WWWStatus == WWWStatus.Remove && isWWW)             {                 context.Response.Redirect(rawUrl.Replace(withWWW, noWWW));             }             else if(config.WWWStatus == WWWStatus.Require && !isWWW)             {                 context.Response.Redirect(rawUrl.Replace(noWWW, withWWW));             }                  }         ReWriteUrl#region ReWriteUrl         private bool ReWriteUrl(HttpContext context)         {             // we're now allowing each individual application to be turned on and off individually. So before we allow             // a request to go through we need to check if this product is disabled and the path is for the disabled product,             // if so we display the disabled product page.             //             // I'm also allowing the page request to go through if the page request is for an admin page. In the past if you              // disabled the forums you were locked out, now with this check, even if you're not on the same machine but you're accessing             // an admin path the request will be allowed to proceed, where the rest of the checks will ensure that the user has the             // permission to access the specific url.             // Url Rewriting             //             //RewriteUrl(context);             string newPath = null;             string path = context.Request.Path;             bool isReWritten = SiteUrls.RewriteUrl(path,context.Request.Url.Query,out newPath);             //very wachky. The first call into ReWritePath always fails with a 404.             //calling ReWritePath twice actually fixes the probelm as well. Instead,              //we use the second ReWritePath overload and it seems to work 100%              //of the time.             if(isReWritten && newPath != null)             {                 string qs = null;                 int index = newPath.IndexOf('?');                 if (index >= 0)                 {                     qs = (index < (newPath.Length - 1)) ? newPath.Substring(index + 1) : string.Empty;                     newPath = newPath.Substring(0, index);                 }                 context.RewritePath(newPath,null,qs);             }             return isReWritten;         }         #endregion         private void ValidateApplicationStatus(CSContext cntx)         {             if(!cntx.User.IsAdministrator)             {                 string disablePath = null;                 switch(cntx.Config.AppLocation.CurrentApplicationType)                 {                     case ApplicationType.Forum:                         if(cntx.SiteSettings.ForumsDisabled)                             disablePath = "ForumsDisabled.htm";                         break;                     case ApplicationType.Weblog:                         if(cntx.SiteSettings.BlogsDisabled)                             disablePath = "BlogsDisabled.htm";                         break;                     case ApplicationType.Gallery:                         if(cntx.SiteSettings.GalleriesDisabled)                             disablePath = "GalleriesDisabled.htm";                         break;                     case ApplicationType.GuestBook:                         if(cntx.SiteSettings.GuestBookDisabled)                             disablePath = "GuestBookDisabled.htm";                         break;                     case ApplicationType.Document:                   //新增 ugoer                         if(cntx.SiteSettings.DocumentDisabled)                             disablePath = "DocumentsDisabled.htm";                         break;                 }                 if(disablePath != null)                 {                     string errorpath = cntx.Context.Server.MapPath(string.Format("~/Languages/{0}/errors/{1}",cntx.Config.DefaultLanguage,disablePath));                     using(StreamReader reader = new StreamReader(errorpath))                     {                         string html = reader.ReadToEnd();                         reader.Close();                         cntx.Context.Response.Write(html);                         cntx.Context.Response.End();                     }                 }             }         }         #endregion     } } 在Web.Config中的配置:         <httpModules>             <add name="CommunityServer" type="CommunityServer.CSHttpModule, CommunityServer.Components" />             <add name="Profile" type="Microsoft.ScalableHosting.Profile.ProfileModule, MemberRole, Version=1.0.0.0, Culture=neutral, PublicKeyToken=b7c773fb104e7562"/>             <add name="RoleManager" type="Microsoft.ScalableHosting.Security.RoleManagerModule, MemberRole, Version=1.0.0.0, Culture=neutral, PublicKeyToken=b7c773fb104e7562" />         </httpModules> CSHttpModule.cs   UML: 要实现HttpModule功能需要如下步骤: 1.编写一个类,实现IhttpModule接口  2.实现Init 方法,并且注册需要的方法  3.实现注册的方法  4.实现Dispose方法,如果需要手工为类做一些清除工作,可以添加Dispose方法的实现,但这不是必需的,通常可以不为Dispose方法添加任何代码。  5.在Web.config文件中,注册您编写的类 到这里我们还需要了解一个Asp.Net的运行过程: 在图中第二步可以看到当请求开始的时候,马上就进入了HttpModule,在CS中由于实现了HttpModule的扩展CSHttpModule.cs 类,因此当一个web请求发出的时候(如:一个用户访问他的blog),CS系统首先调用CSHttpModule.cs类,并且进入 public void Init(HttpApplication application) 该方法进行初始化事件: application.BeginRequest += new EventHandler(this.Application_BeginRequest); application.AuthenticateRequest += new EventHandler(Application_AuthenticateRequest); application.Error += new EventHandler(this.Application_OnError); application.AuthorizeRequest += new EventHandler(this.Application_AuthorizeRequest);   有事件就要有对应的处理方法: private void Application_BeginRequest(Object source, EventArgs e) private void Application_AuthenticateRequest(Object source, EventArgs e) private void Application_OnError (Object source, EventArgs e) private void Application_AuthorizeRequest (Object source, EventArgs e)   事件被初始化后就等待系统的触发,请求进入下一步此时系统触发Application_BeginRequest事件,事件处理内容如下: private void Application_BeginRequest(Object source, EventArgs e)          {             HttpApplication application = (HttpApplication)source;             HttpContext context = application.Context;                          CSConfiguration config = CSConfiguration.GetConfig();             // If the installer is making the request terminate early             if (config.AppLocation.CurrentApplicationType == ApplicationType.Installer)             {                 //CSContext.Create(context);                 return;             }             CheckWWWStatus(config,context);                          CSContext.Create(context, ReWriteUrl(context));                                              }         private void CheckWWWStatus(CSConfiguration config, HttpContext context)         {             if(config.WWWStatus == WWWStatus.Ignore)                 return;             const string withWWW = "[url=http://www.%22;/]http://www.";[/url]             const string noWWW = "[url=http://%22;/]http://";[/url]             string rawUrl = context.Request.Url.ToString().ToLower();             bool isWWW = rawUrl.StartsWith(withWWW);                          if(config.WWWStatus == WWWStatus.Remove && isWWW)             {                 context.Response.Redirect(rawUrl.Replace(withWWW, noWWW));             }             else if(config.WWWStatus == WWWStatus.Require && !isWWW)             {                 context.Response.Redirect(rawUrl.Replace(noWWW, withWWW));             }                  }         ReWriteUrl#region ReWriteUrl         private bool ReWriteUrl(HttpContext context)         {             // we're now allowing each individual application to be turned on and off individually. So before we allow             // a request to go through we need to check if this product is disabled and the path is for the disabled product,             // if so we display the disabled product page.             //             // I'm also allowing the page request to go through if the page request is for an admin page. In the past if you              // disabled the forums you were locked out, now with this check, even if you're not on the same machine but you're accessing             // an admin path the request will be allowed to proceed, where the rest of the checks will ensure that the user has the             // permission to access the specific url.             // Url Rewriting             //             //RewriteUrl(context);             string newPath = null;             string path = context.Request.Path;             bool isReWritten = SiteUrls.RewriteUrl(path,context.Request.Url.Query,out newPath);             //very wachky. The first call into ReWritePath always fails with a 404.             //calling ReWritePath twice actually fixes the probelm as well. Instead,              //we use the second ReWritePath overload and it seems to work 100%              //of the time.             if(isReWritten && newPath != null)             {                 string qs = null;                 int index = newPath.IndexOf('?');                 if (index >= 0)                 {                     qs = (index < (newPath.Length - 1)) ? newPath.Substring(index + 1) : string.Empty;                     newPath = newPath.Substring(0, index);                 }                 context.RewritePath(newPath,null,qs);             }             return isReWritten;         }         #endregion 这个事件主要做两个事情 a:为发出请求的用户初始化一个Context,初始化Context用到了线程中本地数据槽(LocalDataStoreSlot),把当前用户请求的上下文(contextb)保存在为此请求开辟的内存中。 b:判断是否需要重写 URL(检查是否需要重写的过程是对SiteUrls.config文件中正则表达式和对应Url处理的过程),如果需要重写URL,就执行asp.net级别上的RewritePath方法获得新的路径,新的路径才是真正的请求信息所在的路径。这个专题不是讲URL Rewrite,所以只要明白URL在这里就进行Rewrite就可以了,具体的后面专题会叙述。 处理完 Application_BeginRequest 后进程继向下执行,随后触发了Application_AuthenticateRequest(如果有朋友不明白这个执行过程,可以通过调试中设置多个断点捕获事件执行的顺序。如果你还不会调试,可以留言偷偷的告诉我,嘿嘿。), Application_AuthenticateRequest事件初始化一个context的Identity,其实CS提供了很多的 Identity支持,包括Microsoft passport,但是目前的版本中使用的是默认值 System.Web.Security.FormsIdentity。具体代码如下: private void Application_AuthenticateRequest(Object source, EventArgs e)          {             HttpContext context = HttpContext.Current;             Provider p = null;             ExtensionModule module = null;             // If the installer is making the request terminate early             if (CSConfiguration.GetConfig().AppLocation.CurrentApplicationType == ApplicationType.Installer) {                 return;             }             // Only continue if we have a valid context             //             if ((context == null) || (context.User == null))                 return;             try              {                 // Logic to handle various authentication types                 //                 switch(context.User.Identity.GetType().Name.ToLower())                 {                         // Microsoft passport                     case "passportidentity":                         p = (Provider) CSConfiguration.GetConfig().Extensions["PassportAuthentication"];                         module = ExtensionModule.Instance(p);                         if(module != null)                             module.ProcessRequest();                         else                             goto default;                         break;                         // Windows                     case "windowsidentity":                         p = (Provider) CSConfiguration.GetConfig().Extensions["WindowsAuthentication"];                         module = ExtensionModule.Instance(p);                         if(module != null)                             module.ProcessRequest();                         else                             goto default;                         break;                         // Forms                     case "formsidentity":                         p = (Provider) CSConfiguration.GetConfig().Extensions["FormsAuthentication"];                         module = ExtensionModule.Instance(p);                         if(module != null)                             module.ProcessRequest();                         else   &nbs
  • 全部评论(0)
联系客服
客服电话:
400-000-3129
微信版

扫一扫进微信版
返回顶部