詳細なHttpModuleをとのHttpHandler

要求処理を処理するために、ASP.NET:
* .aspxのファイルを要求すると、それはファイルの接尾辞(ASPX)を判断した後、要求は、Inetinfo.exeのプロセスによってインターセプトされますが、要求はASPNET_ISAPI.DLL、ASPNET_ISAPIに転送されます。 HTTPのdllは、導管(HTTPパイプライン)のhttpRuntimeによって、要求を処理するためにAspnet_wp.exeプロセスでは、aspnet_wp.exeプロセスに要求を送信し渡します、処理結果をクライアントに返します。
    Inetinfo.exeのプロセス:プロセスのWWWサービス、IISサービスとASPNET_ISAPI.DLLこのプロセスで登録されています。
    ASPNET_ISAPI.DLL:Win32のは、コンポーネントのプロセス.aspxファイルです。IISサーバーはIISサーバーはIISサーバーに対処するためにASPNET_ISAPI.DLLに引き渡される、要求されたファイルが.aspxのファイルで見つかったときのみの.htmlファイルを認識し、実際にあります。
    aspnet_wp.exeプロセス: ASP.NETフレームワークプロセスは、このプロセスでCLRをホストしている.NET環境で実行.NET、(共通言語ランタイム)をホスティング提供しています。

HTTPリクエストのプロセスを処理するASP.NETフレームワーク:
    HttpRequestの- >のInetinfo.exe - > ASPNET_ISAPI.DLL - > aspnet_wp.exeを- >のhttpRuntime - >ファクトリーさんのHttpApplication - >のHttpApplication - > HttpModuleを- >工場ののHttpHandler - >のHttpHandler - > HttpHandler.ProcessRequest()

ASP.NET要求処理パイプライン処理は、モデルに基づいて、モデルはパイプの複数から構成されてHttpModuleをとのHttpHandler組成、ASP.NETのHTTPリクエストが順次それぞれの導管に伝達されます。 HttpModuleを」のHttpHandler最終的に処理するために、処理が完了すると、再びHTTPパイプラインモジュールを介して、結果がクライアントに返されます。私たちは、各HttpModuleをに介入するための要求を処理することができます。


注意:HTTPリクエストを処理中にのみのHttpHandlerと呼ばれることができますが、複数のHttpModuleを呼び出すことができます。 
リクエストがHttpModuleをし到着すると、システムは本当にこの要求に対処していないが、我々はいくつかの他の情報を付加する前処理センター(のHttpHandler)に渡すか、この要求をインターセプトし、この要求にいくつかの余分な作業を行うことができ、またはも終了しますリクエストなど HttpHandler要求が処理された後、次に我々 HttpModuleをすることができます再びクライアントプロセスへの要求のそれぞれの処理結果インチ

HttpModuleを「
    HTTPモジュールは、インタフェースクラスSystem.Web.IhttpModuleの実装です。
    ステートメントのIHttpModuleインターフェイス:
        パブリックインターフェイスのIHttpModule
        {
            初期化(のHttpApplicationコンテキスト)を無効、
            廃棄を無効();
        }
        Initメソッド:システムの初期化時に自動的にこのメソッドを呼び出すHTTPモジュールのHttpApplicationオブジェクトのイベントに独自のイベントハンドラを登録することを可能にします。
        メソッドを処分:このメソッドは、オブジェクトがガベージコレクトされる前にクリーンアップするHTTPモジュールを実行する機会を与えてくれます。この方法は、コードを記述することなく、一般的です。
    
    HTTPモジュールはSystem.Web.HttpApplication対象に次の一連のイベントを登録することができます
        したAcquireRequestStateは、  このイベントをトリガしたときにASP.NETランタイムの現在のステータスダイアログHTTPリクエストを受信する準備ができて。 
        たAuthenticateRequest  時にASP.NETランタイム時にこのイベントをトリガしたユーザーを認証する準備ができて。 
        AuthorizeRequest  時にASP.NETランタイム時にこのイベントをトリガしたリソースへのアクセスから許可されたユーザへの準備ができて。 
        BeginRequestイベントの  受信時に、新たなHTTPリクエストがこのイベントをトリガしたASP.NETランタイム。 
        配置されました プロセスがASP.NET HTTPリクエストを完了したときに、このイベントが発生します。 
        EndRequestの  このイベントをトリガするために、クライアントを送信する前に、応答の内容を。 
        エラー  未処理の例外がHTTPリクエストの処理中に発生し、このイベントをトリガしました。 
        PostRequestHandlerExecuteは、  このイベントが発生したときにHTTPハンドラの実装の終わり。 
        PreRequestHandlerExecute  このイベントは、ASP.NET HTTPリクエスト処理プログラムの実行を開始する前に発生します。このイベントの後、ASP.NETには、適切なHTTPハンドラに要求を転送します。 
        PreSendRequestContent  クライアントに応答を送信する前にASP.NETコンテンツでは、このイベントをトリガします。このイベントは、コンテンツがクライアントに到達する前に、私たちは応答内容を変更することができます。我々は、すべてのページの内容のためのページ出力に追加するには、このイベントを使用することができます。例えば、一般的なメニュー、ヘッダー情報や足。 
        PreSendRequestHeadersは、  ASP.NETでクライアントにHTTPレスポンスヘッダ情報を送信する前にこのイベントをトリガーします。ヘッダ情報がクライアントに到達する前に、このイベントは、私たちはその内容を変更することができます。当社は、クッキーとヘッダ情報にカスタムデータを追加するには、このイベントを使用することができます。 
        たReleaseRequestState  このイベントをトリガしたときに、検索の最後に、いくつかのASP.NETリクエストハンドラが実行されたとき。 
        たResolveRequestCache  我々はあなたが要求の最後に出力バッファから返されたコンテンツを使用できるかどうかを判断するために、このイベントを発生させました。Webアプリケーションの出力バッファに応じた時間を設定する方法。 
        たUpdateRequestCache 現在のASP.NETのHTTP要求処理、及び出力コンテンツが終了したら、このイベントをトリガし、出力バッファに追加する準備ができたら。Webアプリケーションの出力バッファが設定されている方法に応じて。

    上記のイベントのように多くの、我々は多少めまい見えるかもしれませんが、それは問題ではない、ステップで次のステップを見てください。
    ライフサイクルのHttpModuleを図


    以下は、一連のイベントをトリガーされます。


    BeginRequest和PreRequestHandlerExecute之间的事件是在服务器执行HttpHandler处理之前触发。
    PostRequestHandlerExecute和PreSendRequestContent之间的事件是在服务器执行Handler处理之后触发。
    
    下面我们看一下如何使用HttpModule来实现我们日常的应用:
        HttpModule通过在某些事件中注册,把自己插入ASP.NET请求处理管道。当这些事件发生的时候,ASP.NET调用对相应的HTTP模块,这样该模块就能处理请求了。
       1、向每个页面动态添加一些备注或说明性的文字:
            有的网站每一个页面都会弹出一个广告或在每个页面都以注释形式(<!-- -->)加入网站的版权信息。如果在每个页面教编写这样的JS代码的话,对于大一点的网站,这种JS代码的编写与维护可是一个很繁琐枯燥的工作。
            有了HttpModule我们就可以很简单地解决这个问题了。HttpModule是客户端发出请求到客户端接收到服务器响应之间的一段必经之路。我们完全可以在服务器处理完请求之后,并在向客户端发送响应文本之前这段时机,把这段注释文字添加到页面文本之后。这样,每一个页面请求都会被附加上这段注释文字。
            这段代码究竟该在哪个事件里实现呢? PostRequestHandlerExecute和PreSendRequestContent之间的任何一个事件都可以,但我比较喜欢在EndRequest事件里编写代码。
            第一步:创建一个类库ClassLibrary831。
            第二步:编写一个类实现IHttpModule接口
                class TestModule:IHttpModule
                {
                    public void Dispose()
                    {
                    }
                    public void Init(HttpApplication context)
                    {
                    }
                } 
            第三步:在Init事件中注册EndRequest事件,并实现事件处理方法
               class TestModule:IHttpModule
                {
                    public void Dispose(){}
                    public void Init(HttpApplication context)
                    {
                        context.EndRequest += new EventHandler(context_EndRequest);
                    }
                    void context_EndRequest(object sender, EventArgs e)
                    {
                        HttpApplication ha = (HttpApplication)sender;
                        ha.Response.Write("<!--这是每个页面都会动态生成的文字。--grayworm-->");
                    }
                } 
            第四步:在Web.Conofig中注册一下这个HttpModule模块
          <httpModules>
           <add name="TestModule" type="ClassLibrary831.TestModule,ClassLibrary831"></add>
          </httpModules> 
          name:模块名称,一般是类名
          type:有两部分组成,前半部分是命名空间和类名组成的全名,后半部分是程序集名称,如果类是直接放在App_Code文件夹中,那程序名称是App_Code。
                这样在Web站点是添加该类库的引用后,运行每个页面,会发现其源文件中都会加入“<!--这是每个页面都会动态生成的文字。 --grayworm-->”这句话。同样的方法你也可以在其中加入JS代码。
       2、身份检查
            大家在作登录时,登录成功后,一般要把用户名放在Session中保存,在其它每一个页面的Page_Load事件中都检查Session中是否存在用户名,如果不存在就说明用户未登录,就不让其访问其中的内容。
            在比较大的程序中,这种做法实在是太笨拙,因为你几乎要在每一个页面中都加入检测Session的代码,导致难以开发和维护。下面我们看看如何使用HttpModule来减少我们的工作量
            由于在这里我们要用到Session中的内容,我们只能在AcquireRequestState和PreRequestHandlerExecute事件中编写代码,因为在HttpModule中只有这两事件中可以访问Session。这里我们选择PreRequestHandlerExecute事件编写代码。
            第一步:创建一个类库ClassLibrary831。
            第二步:编写一个类实现IHttpModule接口
                class TestModule:IHttpModule
                {
                    public void Dispose()
                    {
                    }
                    public void Init(HttpApplication context)
                    {
                    }
                } 
            第三步:在Init事件中注册PreRequestHandlerExecute事件,并实现事件处理方法
               class AuthenticModule:IHttpModule
                {
                    public void Dispose(){}
                    public void Init(HttpApplication context)
                    {
                        context.PreRequestHandlerExecute += new EventHandler(context_PreRequestHandlerExecute);
                    }
                    void context_PreRequestHandlerExecute(object sender, EventArgs e)
                    {
                        HttpApplication ha = (HttpApplication)sender;
                        string path = ha.Context.Request.Url.ToString();
                        int n = path.ToLower().IndexOf("Login.aspx"); 
                        if (n == -1) //是否是登录页面,不是登录页面的话则进入{}
                        {
                            if (ha.Context.Session["user"] == null) //是否Session中有用户名,若是空的话,转向登录页。
                            {
                                ha.Context.Response.Redirect("Login.aspx?source=" + path);
                            }
                        }
                    }
                } 
            第四步:在Login.aspx页面的“登录”按钮中加入下面代码
                protected void Button1_Click(object sender, EventArgs e)
                {
                    if(true)    //判断用户名密码是否正确
                    { 
                        if (Request.QueryString["source"] != null)
                        {
                            string s = Request.QueryString["source"].ToLower().ToString();   //取出从哪个页面转来的
                            Session["user"] = txtUID.Text;
                            Response.Redirect(s); //转到用户想去的页面
                        }
                        else
                        {
                            Response.Redirect("main.aspx");    //默认转向main.aspx
                        }
                    } 
                } 
            第五步:在Web.Conofig中注册一下这个HttpModule模块
          <httpModules>
           <add name="TestModule" type="ClassLibrary831.TestModule,ClassLibrary831"></add>
          </httpModules> 
       3、多模块的操作 
            如果定义了多个HttpModule,在web.config文件中引入自定义HttpModule的顺序就决定了多个自定义HttpModule在处理一个HTTP请求的接管顺序。
            

HttpHandler
    HttpHandler是HTTP请求的处理中心,真正地对客户端请求的服务器页面做出编译和执行,并将处理过后的信息附加在HTTP请求信息流中再次返回到HttpModule中。
    HttpHandler与HttpModule不同,一旦定义了自己的HttpHandler类,那么它对系统的HttpHandler的关系将是“覆盖”关系。
    IHttpHandler接口声明
    public interface IHttpHandler
    {
        bool IsReusable { get; }
        public void ProcessRequest(HttpContext context); //请求处理函数
    }
    
    示例:把硬盘上的图片以流的方式写在页面上
        class TestHandler : IHttpHandler
        {
            public void ProcessRequest(HttpContext context)
            {
                FileStream fs = new FileStream(context.Server.MapPath("worm.jpg"), FileMode.Open);
                byte[] b = new byte[fs.Length];
                fs.Read(b, 0, (int)fs.Length);
                fs.Close();
                context.Response.OutputStream.Write(b, 0, b.Length);
            }
            public bool IsReusable
            {
                get
                {
                    return true;
                }
            }
        }
        Web.Config配置文件
      <httpHandlers>
       <add verb="*" path="*" type="ClassLibrary831.TestHandler,ClassLibrary831"></add>
      </httpHandlers> 
           Verb属性:指定了处理程序支持的HTTP动作。*-支持所有的HTTP动作;“GET”-支持Get操作;“POST”-支持Post操作;“GET, POST”-支持两种操作。 
Path属性:指定了需要调用处理程序的路径和文件名(可以包含通配符)。“*”、“*.aspx”、“showImage.aspx”、“test1.aspx,test2.aspx”
Type属性:用名字空间、类名称和程序集名称的组合形式指定处理程序或处理程序工厂的实际类型。ASP.NET运行时首先搜索bin目录中的DLL,接着在GAC中搜索。 
        这样程序运行的效果是该网站的任何一个页面都会显示worm.jpg图片。如何只让一个页面(default21.aspx)执行HttpHandler 中的ProcessRequest方法呢?最简单的办法是在Web.Config文件中把path配置信息设为default21.aspx。
        根据这个例子大家可以考虑一下如何编写“验证码”了。

IHttpHandler工厂
    IHttpHandlerFactory的作用是对IHttpHandler进行管理。工厂的作用请见http://hi.baidu.com/grayworm/blog/item/4a832160f8c9de46eaf8f8c1.html"
    IHttpHandlerFactory接口的声明:
        public interface IHttpHandlerFactory
        {
            IHttpHandler GetHandler (HttpContext context,string requestType,string url,string pathTranslated);
            void ReleaseHandler (IHttpHandler handler);
        }
       GetHandler返回实现IHttpHandler接口的类的实例,ReleaseHandler使工厂可以重用现有的处理程序实例。 
    示例:两个用IHttpHandlerFactory来实现对不同HttpHandler的调用。
    有两个HttpHandler:将图片显示在页面上的HttpHandler和生成验证码的Handler
        //将图片显示在页面上的Handler
        class TestHandler : IHttpHandler
        {
            public void ProcessRequest(HttpContext context)
            {
                FileStream fs = new FileStream(context.Server.MapPath("worm.jpg"), FileMode.Open);
                byte[] b = new byte[fs.Length];
                fs.Read(b, 0, (int)fs.Length);
                fs.Close();
                context.Response.OutputStream.Write(b, 0, b.Length);
            }
            public bool IsReusable
            {
                get
                {
                    return true;
                }
            }
        }
        //生成验证码的Handler 
        class CodeHandler:IHttpHandler
        {
            public bool IsReusable
            {
                get
                {
                    return true;
                }
            }
            public void ProcessRequest(HttpContext context)
            {
                Image b = new Bitmap(50,20);
                Graphics g = Graphics.FromImage(b);
                SolidBrush sb = new SolidBrush(Color.White);
                Font f = new Font("宋体", 12);
                string str = "";
                Random r = new Random();
                for (int i = 0; i < 4; i++)
                {
                    str += r.Next(10);
                }
                g.DrawString(str,f,sb,0,0);
                b.Save(context.Response.OutputStream, System.Drawing.Imaging.ImageFormat.Jpeg);
            }
        } 
         IHttpHandler工厂
         class TestHandlerFactory : IHttpHandlerFactory
         {
            public IHttpHandler GetHandler(HttpContext context, string requestType, string url, string pathTranslated)
            {
                
                string fname = url.Substring(url.IndexOf('/') + 1);
                while (fname.IndexOf('/') != -1)
                    fname = fname.Substring(fname.IndexOf('/') + 1);
                string cname = fname.Substring(0, fname.IndexOf('.'));
                string className ="";

                className = "ClassLibrary831.CodeHandler";
                object h = null;
                try
                {
                    //h = new TestHandler();
                    h = Activator.CreateInstance(Type.GetType(className));
                }
                catch (Exception e)
                {
                    throw new HttpException("工厂不能为类型" + cname + "创建实例。", e);
                }
                return (IHttpHandler)h;
            }
            public void ReleaseHandler(IHttpHandler handler)
            {
            }
         }(车延禄)
        配置文件
    <httpHandlers>
    <add verb="*" path="default21.aspx,default22.aspx" type="ClassLibrary831.TestHandlerFactory,ClassLibrary831"></add>
   </httpHandlers>
   这样TestHandlerFactory就会根据请求的不同页面执行不同的HttpHandler处理程序了。

HttpHandler使用会话
    如果要在处理程序中使用Session,那必须把该HttpHandler实现IRequiresSessionState接口,,IRequiresSessionState接口是个空接口,它没有抽象方法,只是一个标记。下面是一个文件上传的例子

1、先引用System.Web.SessionState这个命名空间,
2、如果是要在HttpHandler中读取Session的内容,就要在实现IHttpHandler的类中同时实现IReadOnlySessionState这个接口。
3、如果是要在HttpHandler中读写Session的内容,就要在实现IHttpHandler的类中同时实现IRequiresSessionState
  
  这样就可以在自定义的HttpHandler 中正常的使用Session了。

/// <summary>
/// 上传文件事件;
/// </summary>
public class Upload : IHttpHandler, IRequiresSessionState
{    
    public Upload()
    {
    }

    #region IHttpHandler Members

    public bool IsReusable
    {
        get { return true; }
    }

    public void ProcessRequest(HttpContext context)
    {
        string temp = context.Session["temp"].ToString();

        string EncryptString = context.Request.QueryString["User"];
        
        if (temp!="" && context.Request.Files.Count > 0 )
        {
  
            string uploadPath = context.Server.MapPath(context.Request.ApplicationPath + "/Upload/" +temp);
   if (Directory.Exists(uploadPath) == false)//不存在该目录时自动创建一个目录
             {
                  Directory.CreateDirectory(uploadPath);
             }
           
            for(int j = 0; j < context.Request.Files.Count; j++)
            {
               
                HttpPostedFile uploadFile = context.Request.Files[j];
               
                if (uploadFile.ContentLength > 0)
                {
                    
                    uploadFile.SaveAs(Path.Combine(uploadPath, uploadFile.FileName));        
                }                
            }
        }
        
        //HttpContext.Current.Response.Write(" ");
       
    }

    #endregion
}


后台代码:

public partial class _Default : System.Web.UI.Page 
{
    protected void Page_Load(object sender, EventArgs e)
    {
        string jscript = "function UploadComplete(){" + ClientScript.GetPostBackEventReference(LinkButton1, "") + "};";
        Page.ClientScript.RegisterClientScriptBlock(this.GetType(), "FileCompleteUpload", jscript, true);
        Session["temp"] = "yekin";
        FormsIdentity cIdentity = User.Identity as FormsIdentity;
        string encryptString = Session["temp"].ToString();
        flashUpload.QueryParameters = string.Format("User={0}", encryptString);        
    }

    空LinkBut​​ton1_Click保護された(SENDERオブジェクト、EventArgsのE)
    {
 
 
  のResponse.Write( "<スクリプト>アラート( 'おめでとう、正しくアップロード!'); </ SCRIPT>");
 
        
        // MyGrid.DataBind();
    }
}
 
著者:ゆうソース出典:  http://www.cnblogs.com/yuanyuan/
この記事では、著者とブログパークの合計に属し転載を歓迎しますが、この節で宣言され、著者の同意なしに保持され、記事ページの見かけ上の位置にある元の接続、法的責任を追及するそうでない場合は権利を与えられなければなりません。

ます。https://www.cnblogs.com/zhangchenliang/p/4566676.htmlで再現

おすすめ

転載: blog.csdn.net/weixin_33701251/article/details/93495543