httpModules 与 httpHandlers

httpModules 与 httpHandlers

ASP.NET对请求处理的过程:
当请求一个*.aspx文件的时候,这个请求会被inetinfo.exe进程截获,它判断文件的后缀(aspx)之后,将这个请求转交给ASPNET_ISAPI.dll,ASPNET_ISAPI.dll会通过http管道(Http PipeLine)将请求发送给ASPNET_WP.exe进程,在ASPNET_WP.exe进程中通过HttpRuntime来处理这个请求,处理完毕将结果返回客户端。
    inetinfo.exe进程:是www服务的进程,IIS服务和ASPNET_ISAPI.DLL都寄存在此进程中。
    ASPNET_ISAPI.DLL:是处理.aspx文件的win32组件。其实IIS服务器是只能识别.html文件的,当IIS服务器发现被请求的文件是.aspx文件时,IIS服务器将其交给aspnet_isapi.dll来处理。
    aspnet_wp.exe进程:ASP.NET框架进程,提供.net运行的托管环境,.net的CLR(公共语言运行时)就是寄存在此进程中。

ASP.NET Framework处理一个Http Request的流程:
    HttpRequest-->inetinfo.exe-->ASPNET_ISAPI.dll-->ASPNET_WP.exe-->HttpRuntime-->HttpApplication Factory-->HttpApplication-->HttpModule-->HttpHandler Factory-->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接口的声明:
        public interface IHttpModule
        {
            void Init (HttpApplication context);
            void Dispose ();
        }
        Init 方法:系统初始化的时候自动调用,这个方法允许HTTP模块向HttpApplication 对象中的事件注册自己的事件处理程序。
        Dispose方法: 这个方法给予HTTP模块在对象被垃圾收集之前执行清理的机会。此方法一般无需编写代码。
    
    HTTP模块可以向System.Web.HttpApplication对象注册下面一系列事件:
        AcquireRequestState 当ASP.NET运行时准备好接收当前HTTP请求的对话状态的时候引发这个事件。 
        AuthenticateRequest 当ASP.NET 运行时准备验证用户身份的时候引发这个事件。 
        AuthorizeRequest 当ASP.NET运行时准备授权用户访问资源的时候引发这个事件。 
        BeginRequest 当ASP.NET运行时接收到新的HTTP请求的时候引发这个事件。 
        Disposed 当ASP.NET完成HTTP请求的处理过程时引发这个事件。 
        EndRequest 把响应内容发送到客户端之前引发这个事件。 
        Error 在处理HTTP请求的过程中出现未处理异常的时候引发这个事件。 
        PostRequestHandlerExecute 在HTTP处理程序结束执行的时候引发这个事件。 
        PreRequestHandlerExecute 在ASP.NET开始执行HTTP请求的处理程序之前引发这个事件。在这个事件之后,ASP.NET 把该请求转发给适当的HTTP处理程序。 
        PreSendRequestContent 在ASP.NET把响应内容发送到客户端之前引发这个事件。这个事件允许我们在内容到达客户端之前改变响应内容。我们可以使用这个事件给页面输出添加用于所有页面的内容。例如通用菜单、头信息或脚信息。 
        PreSendRequestHeaders 在ASP.NET把HTTP响应头信息发送给客户端之前引发这个事件。在头信息到达客户端之前,这个事件允许我们改变它的内容。我们可以使用这个事件在头信息中添加cookie和自定义数据。 
        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接口是个空接口,它没有抽象方法,只是一个标记。此处就不作例子验证了

 

 

ASP.Net处理Http Request时,使用Pipeline(管道)方式,由各个HttpModule对请求进行处理,然后到达 HttpHandler,HttpHandler处理完之后,仍经过Pipeline中各个HttpModule的处理,最后将HTML发送到客户端浏览 器中。

生命周期中涉及到几个非常重要的对象:HttpHandler,HttpModule,IHttpHandlerFactory,他们的执行(顺序)大致的执行过程是这样的:client端发送页面请求,被IIS的某个进程截获,它根据申请的页 面后缀(.aspx)不同,调用不同的页面处理程序(.asp->asp.dll; .aspx->ISAPI.dll).而页面处理程序在处理过程中,则要经历HttpModule,HttpHandler的处理:前者HttpModule用于页面处理前和处理后的一些事件的处理后者HttpHandler进行真正的页面的处理
如前所说,HttpModule会在页面处理前和后对页面进行处理,所以它不会影响真正的页面请求。通常用在给每个页面的头部或者尾部添加一些信息(如版 权声明)等.曾经见过一些免费的空间,我们的页面上传上去后,浏览的时候发现,在每个页面的头部和尾部多了很多小广告....,如果理解了 HttpModule的原理,要做这个就不是很难了~


IHttpModule与IHttpHandler的区别整理
    1.先后次序.先IHttpModule,后IHttpHandler. 注:Module要看你响应了哪个事件,一些事件是在Handler之前运行的,一些是在Handler之后运行的
    2.对请求的处理上:
        IHttpModule是属于大小通吃类型,无论客户端请求的是什么文件,都会调用到它;例如aspx,rar,html的请求.
        IHttpHandler则属于挑食类型,只有ASP.net注册过的文件类型(例如aspx,asmx等等)才会轮到调用它.
   3.IHttpHandler按照你的请求 生成响应的内容,IHttpModule对请求进行预处理,如验证、修改、过滤等等,同时也可以对响应进行处理

 

 

ASP.Net系统本身配置有很多HttpHandler和HttpModule,以处理aspx等.Net标准的页面文件,以及这些页面文件中标 准的事件处理等。查看%System%/Microsoft.NET\Framework\v2.0.50727\CONFIG目录下的 web.config文件中的httpHandlers和httpModules节点,可以看到这些配置。如果有兴趣,可以使用Reflector查 看.Net系统中相关的类和方法,了解.Net如何处理以及做了什么处理。

.Net也提供了一套机制来开发自定义的HttpHandler和 HttpModule,均可以用于对HttpRequest的截取,完成自定义的处理。 HttpModule 继承System.Web.IHttpModule接口,实现自己的HttpModule类。必须要实现接口的两个方法:Init和Dispose。在 Init中,可以添加需要截取的事件;Dispose用于资源的释放,如果在Init中创建了自己的资源对象,请在Dispose中进行释放。

namespace MyModule
{
public class MyHttpModule : IHttpModule
{
    public MyHttpModule()
    {
    }

    
   //Init方法用来注册HttpApplication 事件。
   public void Init(HttpApplication r_objApplication)
    {
      r_objApplication.BeginRequest += new EventHandler(this.BeginRequest);
    }    

 

public void Dispose()
    {
    }    

private void BeginRequest(object r_objSender, EventArgs r_objEventArgs)
    {
      HttpApplication objApp = (HttpApplication)r_objSender;
      objApp.Response.Write("您请求的URL为" + objApp.Request.Path);
    }
}


}   

将编译的dll文件拷贝到web项目的bin目录下,在web项目的web.config文件system.web节点中配置: 
    这样就将自定义的HttpModule类MyHttpModule插入到了当前web的HttpModule的Pipeline中。 HttpModule主要功能是Application的各个事件进行截取,在这些事件中完成自己的处理。其实如果自己开发一些项目,直接在 Global.asax中处理已经足够了。如果是开发一个Framework或者是某些方面的组件,需要在事件中添加处理,开发自定义的 HttpModule,可以避免使用Framework或者组件时,还得手工在Global.asax中添加代码。     目前想到的开发自定义HttpModule的用途,有全局的身份/权限验证、自定义网站访问/操作日志的记录、处于管理/调试等目的对站点进行监控追踪 等。当然,如果是结合自定义的HttpHandler进行Framework的开发,HttpModule可以用于其它的一些特殊的处理。

      <httpModules>
         <add name="test" type="MyHttpModuleTest.MyHttpModule,MyHttpModule"/>
       </httpModules>
   注意要区分大小写,因为web.config作为一个XML文件是大小写敏感的。“type=MyHttpModuleTest.MyHttpModule,MyHttpModule”告诉我们
   系统将会将http request请求交给位于MyHttpModule.dll文件中的MyHttpModuleTest.MyHttpModule类去处理。

 

 

 

HttpHandler是完全的对Http Request的截取。
    首先,继承System.Web.IHttpHandler接口,实现自己的HttpHandler类。必须要实现接口的ProcessRequest方 法和IsReusable属性。ProcessRequest方法中完成对每个Http Request的处理,发送处理结果的HTML到输出缓存中。IsReusable属性被.Net Framework调用,用以确定这个HttpHandler的实例是否可以被重用于同类型其它的Request处理。
    如果你在自己的HttpHandler类中,需要读取或者是写Session值,需要再继承一个接口IRequiresSessionState。这个接 口没有任何方法,只是一个标记接口。继承这个接口之后,就可以在自己的HttpHandler中访问Session,可以在Session中写入值。
namespace MyHandler
{
public class MyHttpHandler : IHttpHandler, IRequiresSessionState
{
    public MyHttpHandler() {}
    public bool IsReusable
    {
      get { return true; }
    }
    public void ProcessRequest(HttpContext context)
    {
      HttpResponse objResponse = context.Response ;
      objResponse.Write(" 
This request is handled by MyHttpHandler
");
    }
}
}
    把编译的dll文件拷贝到web项目的bin目录下。
    接下来,这样来测试一下MyHttpHandler。我们为IIS配置一个以.cc为后缀名的文件类型,用我们写的MyHttpHandler来处理。
    首先,在IIS站点的Configuration配置里面,添加一个对.cc后缀名处理的Application Extention Mapping项。   
    然后,在web项目的web.config节点节点中配置:

MyHttpHandler, MyHandler"/>

    verb属性配置这个HttpHandler处理那些HTTP方法,例如GET、POST等,如果是处理所有方法,就用*。path属性配置HttpHandler对哪些文件进行处理,例如可以是myfile.cc,如果是处理所有的.cc文件,就用*.cc。
    这样,这个站点上所有.cc类型文件的访问,都由MyHttpHandler处理。使用http://localhost/站点虚拟目录/a.cc访问测试站点,可以看到测试效果。当然,a.cc这个文件在Web服务器上是并不存在的。

    对HttpHandler的使用,比较典型的有.Net的Web MVC开源项目Maverick。Maverick使用一个Dispatcher类对所有的Http Request进行截取,他以.m作为后缀名向Web服务器提交请求,在Dispatcher中,将.m的后缀去掉,提取Command Name,然后以这个command name从配置文件中加载处理的flow,形成一个chain,依次对chain上的各个command和view进行处理,对各个command和 view的处理结果可能会在chain中选择不同的处理分支,每个处理的Step中将处理结果的HTML写入Response的缓存中进行输出。
    总体来说,Maverick的框架架构概念很不错,但也存在明显的缺陷,以后有时间再详细的写写它的架构和需要改进之处。

    总之,将HttpModule、HttpHandler,以及使用Ajax等将客户端进行封装结合起来,能够给web项目的开发带来非常大的改善空间。

Asp.Net HttpHandler实现URL重写的
我们经常看到很多网站访问文章的时候才用的是***.html 或***.shtml (如本blog的日志访问效果),其时这写文件在服务器上不存在的,那为什么会出现这样的效果呢,是因为Web服务器上对URL执行了重写,把访问的 URL根据特定的格式重写成内部访问页面来实现的,它的好处是便于用户理解,同时搜索引擎也能更好地收入你的网站,当然其它的好处也很多,这里不做一一介 绍了。 
本文所讲的是使用Asp.Net中的HttpHandler实现URL重写的,它所实现的原理请看这里,本程序可以处理任何Url,因为我在程序中使用了URL过虑,只有访问文件名是数字的才进行处理,并指在内部执行一个新的页面,并输出数据,代码如下:
public void ProcessRequest(HttpContext Context)
{    
try {        
         //申明Request         
HttpRequest Request = Context.Request; 
//取来路Url的绝对路径        
string Url = Request.Url.AbsolutePath; 
//取访问的Web文件的开始字符间隔数
int RegStart = Url.LastIndexOf("/") + 1; 
//申明一个确定Web文件名是否全是数字
Regex Reg = new Regex(@"\d+"); 
//用正则表达式进行匹配 
if (Reg.IsMatch(Url, RegStart)) 

// 如果web文件名是数字,则判定是查询相关文章,执行指定页面             Context.Server.Execute("~/PermaLink.aspx?id=" + Reg.Match(Url, RegStart).Value);        
}    
}
catch
{
      Context.Response.Redirect(Context.Request.Url.ToString()); 
}
}
当然你首先要做的是先建一个类,并继承自IHttpHandler,然后把这段代码拷入,并编译。在Web项目中若要使用此功能,需要在web.config里面加上如下语句:
<httpHandlers>
    <add verb="*" path="*.shtml" type="HttpHandle.UrlRewrite" />
</httpHandlers>
同时,还要在IIS中对Web项目进行配置,在Web项目的属性中,在主目录选项卡里,把执行权限改为"脚本和可执行文件",然后打开配置,在应用程序扩展里加上需重写的文件格式的扩展,好了,成事具备,只欠运行了。

转载于:https://www.cnblogs.com/cmblogs/p/4028621.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/292794.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

多比Web 3D展示(3D机房/3D监控)中间件多比Web 3D展示(3D机房/3D监控)中间件免费下载购买地址...

多比3D是实现3D场景搭建的软件开发包&#xff0c;可以创建广泛的3D应用&#xff0c;适用于高端制造、能源、国防军工、教育科研、城市规划及建筑环艺、生物医学等领域的虚拟仿真&#xff0c;应用于虚拟展示、虚拟设计、方案评审、虚拟装配、虚拟实训等工作环节。 特点与优势 支…

python 工资管理软件_智慧职教云课堂2020Python程序设计(深圳信息职业技术学院)题目答案...

智慧职教云课堂2020Python程序设计&#xff08;深圳信息职业技术学院)题目答案 更新时间&#xff1a;2020-11-23 20:41点击&#xff1a; 智慧职教云课堂2020Python程序设计&#xff08;深圳信息职业技术学院)题目答案 更多相关问题 【判断题】在声明类的成员属性时必须要用关键…

中国已消失的九所世界级大学

全世界只有3.14 % 的人关注了爆炸吧知识众所周知&#xff0c;我们国家的大学数量在世界范围内数一数二&#xff0c;但是有很多赫赫有名的大学却在历史中被人们遗忘&#xff0c;下面我们一起回顾一下那些不该被忘记的大学。>>>>▌燕京大学燕京大学&#xff08;Yench…

IOS Table中Cell的重用reuse机制分析

2019独角兽企业重金招聘Python工程师标准>>> 解决代码&#xff1a; - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { NSString *CellIdentifier [NSString stringWithFormat:"Cell%d%d", …

VS2017/2019 F12无法导航到定义

今天对项目里某个对象点F12转到定义&#xff0c;无法跳转,研究了一会儿&#xff0c;找到如下解决方案:首先确认该函数是否能够正确被跳转到..就是是否真实定义了&#xff0c;然后确保要跳转的定义源码在项目文件下&#xff08;而不是直接引用的DLL&#xff09;接下来关闭VS2017…

unable to launch什么意思_都表示太...以至于,so … that…?与too… to …有着明显区别...

【2019年12月8日 百天英语-Day135】【华东师范大学-林森撰写】昨日内容复习提要&#xff1a;昨天学习了主要学习了 ①be able to …与can的区别。②如何通过不认识的单词&#xff0c;猜到作者表达的含义。昨天文章如下&#xff1a;表示有能力做某事&#xff0c;be able to …与…

求指教、。。。关于调用so文件

问题描述今天同事给我发来一个文件&#xff0c;说让我通过android调用里面的函数文件是&#xff1a;里面的内容是&#xff1a;call_so.cpp文件的内容&#xff1a;#pragma pack(1) //非常重要的申明&#xff0c;内存对齐的方法&#xff0c;影响sizeof()的结果#include <stdio…

人类历史上最伟大的物理学家

全世界只有3.14 % 的人关注了爆炸吧知识一沙见世界 一花窥天堂手心握无限 须臾纳永恒杨振宁曾说读上面的四句诗可以感受到物理的美但物理的美不止于此物理还有一种庄严美一种神秘美一种初窥宇宙奥秘的畏惧美物理就是如此的迷人任何语言在它的面前都很贫瘠数学让人摆脱了愚昧而…

DevToys - 开发人员的瑞士军刀

DevToys 是一个适用于开发人员的工具箱, 基于 UWP 开发, DevToys 旨在拥抱 Windows 生态系统, 免费并且开源, 拥有现代化的界面, 支持中文, 有深色/浅色主题可选, 并且它是离线化的, 所以你完全可以在无网络环境中使用。你可以使用它处理与开发相关的一些任务, 它提供 了14…

python写小猪佩奇_python之小猪佩奇

该楼层疑似违规已被系统折叠 隐藏此楼查看此楼 小猪佩奇 &#xff08;源码有点长&#xff09;# coding:utf-8 import turtle as t t.pensize(4) t.hideturtle() t.colormode(255) t.color((255,155,192),"pink") t.setup(840,500) t.speed(10) #鼻子 t.pu() t.goto(-…

你和985硕博研究生,差了这些东西

全世界只有3.14 % 的人关注了爆炸吧知识明明都是在搞科研为什么别人的思路比你开阔&#xff1f;明明都是在写文章为什么别人的方向比你更新颖&#xff1f;今天小编就来推荐几个能拓展视野的公号快点收藏起来吧&#xff01;募格课堂ID&#xff1a;mugeketang推荐理由&#xff1a…

产品运行所需的信息检索失败_禁煤后用什么替代锅炉?看看三种热源运行费用对比就知道了...

山西是我国的煤炭大省&#xff0c;煤炭资源丰富&#xff0c;自然而然也是燃煤大省。在打赢蓝天保卫战的目标任务下&#xff0c;拆除燃煤锅炉&#xff0c;改用清洁能源产品是大势所趋。这样的市场背景下&#xff0c;显然可见的是&#xff0c;山西地区将会迎来一大波的燃煤锅炉改…

图像处理技术(三)白平衡

在现实生活中&#xff0c;同学们经常会出旅游、去景点打卡&#xff0c;拍照&#xff0c;发个朋友圈&#xff0c;如果遇到阴雨天、雾霾天或者沙尘天气&#xff0c;那拍照的效果&#xff0c;可是让人头疼。好不容易去北京故宫玩一次&#xff0c;这不&#xff0c;遇到这种天气&…

mysql查看日志命令_面对成百上千台服务器产生的日志,试试这款轻量级日志搬运神器!

之前我们搭建的ELK日志收集系统&#xff0c;主要是用来收集SpringBoot应用的日志。其原理是应用通过Logstash插件&#xff0c;使用TCP向Logstash传输日志&#xff0c;从而存储到Elasticsearch中去。但是有很多中间件的日志都是直接存储在文件中的&#xff0c;比如Nginx、Elasti…

单元测试 | 如何Mock IHttpClientFactory

前言编写单元测试时&#xff0c;常常需要使用Mock框架&#xff08;例如Moq&#xff09;生成测试类的依赖接口的"模拟"实现&#xff0c;并验证接口是否按预期使用&#xff1a;_mediatorMock new Mock<IMediator>();_mediatorMock.Setup(x > x.Send(It.IsAny…

Wireshark和 TcpDump抓包分析心得

1. Wireshark与tcpdump介绍 Wireshark是一个网络协议检测工具&#xff0c;支持Windows平台和Unix平台&#xff0c;我一般只在Windows平台下使用Wireshark&#xff0c;如果是Linux的话&#xff0c;我直接用tcpdump了&#xff0c;因为我工作环境中的Linux一般只有字符界面&#x…

遇到可爱女生如何搭讪?

1 旺仔落泪▼。。。2 养狗一日&#xff0c;用狗一时&#xff08;素材来源网络&#xff0c;侵删&#xff09;▼3 试图混进芒果里的鹦鹉&#xff08;素材来源网络&#xff0c;侵删&#xff09;▼4 把滴滴司机的坐垫沾走了▼5 如何高效记单词&#xff08;素材来源网络&#xf…