ASP.NET WebAPI框架解析第二篇(HttpModule的创建和使用)
我们先看一下执行流程图
图中画红圈的部分便是HttpModule,在说创建HttpModule之前,先说一下HttpApplication对象,HttpApplication对象由Asp.net框架创建,每个请求对应一个HttpApplcation实例对象,Asp.Net框架内部维护了一个HttpApplication对象池,可以复用该对象,以便节省服务器资源。HttpApplication对象内部有许多事件,其中的一些事件如下:
BeginRequest Asp.net处理的第一个事件,表示处理的开始
AuthenticateRequest 验证请求,一般用来取得请求用户的信息
PostResolveRequestCache 已经完成缓存的获取操作
……
EndRequest 本次请求处理完成
其中PostResolveRequestCache 这个事件就被路由模块监听了。我们看看一个标准HttpModule模块的接口定义是怎么样的。
public interface IHttpModule
{
void Init(HttpApplication context);void Dispose();
}
注意到Init(HttpApplication context)这个方法,每注册一个HttpModule模块,Asp.Net框架内部通过反射获取对应的程序集,并通过反射调用Init方法,Context参数便是处理一个Http请求的HttpApplication实例对象。那怎么让我们注册的模块参与到处理Http请求中呢?前面提到HttpApplication内部有许多事件,而我们的HttpModule中的Init方法会被Asp.Net框架调用,所以我们可以利用这个去注册相应的事件,执行我们的代码,我们在这里可以做很多事,比如自定义验证、自定义授权,图片压缩,图片加水印,服务器日志记录、恶意请求拦截等等。
为了演示自定义HttpModule的使用,我们创建一个寄宿模式为WebHost的WebAPI,为了便于理解ASP.NET WebAPI的组成,我们不直接创建一个WebAPI模板的项目。
1.使用VS2017创建一个空的解决方案
2.新建一个空的.NetFramwork类库项目和一个空的ASP.NET Web应用
我们对WebAPI类库项目引用WebAPI所需的System.Web.Http.dll。我在I:\Program Files (x86)\Microsoft Visual Studio\Shared\Packages\Microsoft.AspNet.WebApi.Core.5.2.7\lib\net45路径下找到了该dll。
然后在WebAPI项目下建立一个类,使用命名空间System.Web.Htpp,继承该命名空间下的ApiController即可,然后定义一个方法,我定义的如下。注意类名一定要以Controller结尾,否则在路由匹配成功后,WebAPI框架内部不能通过路由解析到的值去反射构建对应的控制器实例对象。
然后对WebHost项目引用如下dll(我都是在I:\Program Files (x86)\Microsoft Visual Studio\Shared\Packages\目录下找到的,实在找不到就创建一个WEBAPI模板然后到项目目录下的Package文件中去拷贝)
System.Web.Http.dll
System.Web.Http.WebHost.dll
System.Net.Http.Formatting.dll
WebHost项目还要保持对WebAPI项目的引用。
为WebHost项目添加Global.asax文件,VS为我们自动创建了一个Global类,并继承于System.Web命名空间下的HttpApplication类。这个类就是处理Http请求的类。我们也可以在这里监听相应的事件,监听函数格式以XXX_XXX的形式定义,至于为什么要这么定义的原因是为了便于通过反射进行注册。有些事件只能在这里监听,比如Application_Start,Application_Start在整个应用生命周期中只会执行一次,相当于静态构造函数.我们在Application_Start中去注册全局的路由表,在WebHost模式下,WebAPI的路由系统实际上由ASP.NET的路由系统完成的,当然WebAPI本身的路由系统也可以完成。我们注册以下路由表。
protected void Application_Start(object sender, EventArgs e)
{
GlobalConfiguration.Configuration.Routes.MapHttpRoute(name: "first",routeTemplate: "webapi/{controller}/{action}");}
然后在VS2017环境下使用IIS Express启动,然后在浏览器输入http://localhost:63210/webapi/home/index,注意在我这里端口号是63210。便可得到如下结果。
我们回顾一下这个流程。
->客户端(在这里是浏览器)发起HTTP请求
->IIS Express接收到该请求
->IIS Express发现该请求路径不是已知的静态资源类型,进而把请求交给Asp.Net托管代码处理
->Asp.Net从HttpApplication池中取一个实例对象去处理该Http请求
->注册相应HttpModule模块,并调用Init()函数,这个时候HttpContext还没有形成,我们只能在这里注册相应的监听事件函数。
->HttpContext形成,HttpApplication实例对象内部的事件轮流触发,其中有一个PostMapRequestHandler事件,在这个事件触发后,会调用相应HttpHandler执行相应的处理,后面再说HttpHandler
->必要的事件触发完成之后生成Http报文并交由IIS Express返回给客户端
->客户端接受Http报文并解析显示在客户端中。
这只是一个大概的过程,具体比这复杂,但我们关注点在HttpModule上,所以足够了。
我们现在尝试自己创建HttpModule
我在WebHost项目下建立了一个文件夹,然后新建了一个AuthorizeHttpModule,模拟授权,功能很简单,看Http请求头中是否包含name字段,并且值为HK,否则,向Http响应报文中的Body部分写入内容,并拦截请求。
namespace WebHost.HttpModules
{
public class AuthorizeHttpModule : IHttpModule
{
public void Dispose()
{
return;
}public void Init(HttpApplication context)
{
//此时HttpContext还未构建完成,不能在这里操作HttpContext
//注册事件监听函数
context.BeginRequest += Authorize;
}
private void Authorize(object sender,EventArgs e)
{
HttpApplication app = sender as HttpApplication;if (app.Request.Headers.Get("name") != "HK")
{
//不加这一行客户端可能不能自动正确的解析字符编码
app.Response.Headers.Add("content-Type", "text/html;charset=utf-8");
//通过Write(string s)写入的字符串在内部默认被转换为utf-8编码。C#string默认编码为UTF-16
//要先写入原始的字符串编码,调用BinaryWrite(byte[] bytes)
app.Response.Write("验证不通过!");
app.CompleteRequest();
}
}
}
}
在WebHost项目目录下的Web.Config中配置HttpModule信息,以便Asp.Net框架读取。注意,有个全局的Web.Config文件,其中默认注册了许多HttpModule,其中有一个HttpModule(WebDAVModule)会截断Put和Delete请求。
如上,我添加了system.webServer节点(IIS集成模式下是这样配置,经典模式自行搜索),并在子节点modules下添加了自定义的HttpModule,其中name是HttpModule名称,ASP.NET内部会以这个名称作为Key,type表示HttpModule的类型名,以便反射读取相应的类型对象。该类型所在的程序集必须在Web应用程序的Bin目录,否则不能正常加载,由于我创建的HttpMudle是在WebHost项目中,所以不会出现问题。我们现在启动IIS Express看看效果。
可以看到我们的HttpModule起作用了。我们用PostMan为请求头添加一个字段name,值为HK,然后请求/webapi/home/index试试看
可以看到没有被拦截。前面我们提到了一个HttpHandler,这个HttpHandler实际上是最终处理页面的处理者,后面再说。
ASP.NET WebAPI框架解析第二篇(HttpModule的创建和使用)的更多相关文章
- ASP.NET WebAPI框架解析第一篇
ASP.NET WebAPI有两种寄宿模式,一种是WebHost,一种是SelfHost,为什么可以有两种模式的原因在于WebAPI有一个相对独立的消息处理管道,只要给这个消息管道传递一个封装好的对象 ...
- ASP.NET MVC案例教程(基于ASP.NET MVC beta)——第二篇:第一个页面
摘要 本文首先一步一步完成Demo的第一个页面——首页.然后根据实现过程,说明一下其中用到的与ASP.NET MVC相关的概念与原理. 让第一个页面跑起来 现在,我们来实现公告系统 ...
- ASP.NET Core 学习笔记 第二篇 依赖注入
前言 ASP.NET Core 应用在启动过程中会依赖各种组件提供服务,而这些组件会以接口的形式标准化,这些组件这就是我们所说的服务,ASP.NET Core框架建立在一个底层的依赖注入框架之上,它使 ...
- ASP.NET WebApi 学习与实践系列(1)---如何创建 WebApi
写在前面 最近在做一个app的时候发现需要写后台服务.所以,在考虑是使用webapi还是使用webserver来写这个后台服务的时候.爱纠结的我,最后还是选择了使用webapi来写这个后台服务. 原因 ...
- Lucene&Solr框架之第二篇
2.1.开发环境准备 2.1.1.数据库jar包 我们这里可以尝试着从数据库中采集数据,因此需要连接数据库,我们一直用MySQL,所以这里需要MySQL的jar包 2.1.2.MyBatis的jar包 ...
- SpringMVC框架之第二篇
6.参数绑定(重点) Springmvc作为表现层框架,是连接页面和service层的桥梁,它负责所有请求的中转.怎么从请求中接收参数是重点,这也体现了我们刚开始说的Springmvc的第一个作用:“ ...
- Django框架之第二篇--app注册、静态文件配置、form表单提交、pycharm连接数据库、django使用mysql数据库、表字段的增删改查、表数据的增删改查
本节知识点大致为:静态文件配置.form表单提交数据后端如何获取.request方法.pycharm连接数据库,django使用mysql数据库.表字段的增删改查.表数据的增删改查 一.创建app,创 ...
- Django(三)框架之第二篇
https://www.cnblogs.com/haiyan123/p/7717788.html 一.知识点回顾 1.MTV模型 model:模型,和数据库相关的 template:模板,存放html ...
- Django框架之第二篇
一.知识点回顾 1.MTV模型 model:模型,和数据库相关的 template:模板,存放html文件,模板语法(目的是将变量如何巧妙的嵌入到HTML页面中). views:视图函数 另加urls ...
随机推荐
- 面向对象案例-学生信息管理系统V0.6
更新版本 面向对象案例 - 学生信息管理系统V1.0 项目要求: 实体类: 学生类: id, 姓名,年龄,性别,成绩 需要使用数组保存学生信息 Student[] allStu 需要完成的方法 1. ...
- Vue 百度地图显示规划路线
Vue 百度地图显示规划路线 1.首选引入相应的文件(建议单页面引入)(如有问题找上一篇博客园) 2.区别就是需要多引入几根不同的文件 import { BaiduMap, BmScale, BmGe ...
- (板子) 最小生成树 买礼物 luogu P1194
luogu题目传送门! 懒得找最小生成树模板了,就把这题当板子吧. 最小生成树,就是指对于一张图,我们将图转换成一棵树,连通的,同时让所有的边尽可能的小(废话). 最小生成树一般都采用Kruskal算 ...
- css定位和css3的基本
定位方式:position需要搭配left|right |top |bottom 1.相对定位:相对于自身的位置进行偏移position: relative; 2.绝对定位:相对于有position属 ...
- (Java实现) 洛谷 P1605 迷宫
题目背景 迷宫 [问题描述] 给定一个N*M方格的迷宫,迷宫里有T处障碍,障碍处不可通过.给定起点坐标和 终点坐标,问: 每个方格最多经过1次,有多少种从起点坐标到终点坐标的方案.在迷宫 中移动有上下 ...
- Java实现 LeetCode 398 随机数索引
398. 随机数索引 给定一个可能含有重复元素的整数数组,要求随机输出给定的数字的索引. 您可以假设给定的数字一定存在于数组中. 注意: 数组大小可能非常大. 使用太多额外空间的解决方案将不会通过测试 ...
- Java实现 LeetCode 321 拼接最大数
321. 拼接最大数 给定长度分别为 m 和 n 的两个数组,其元素由 0-9 构成,表示两个自然数各位上的数字.现在从这两个数组中选出 k (k <= m + n) 个数字拼接成一个新的数,要 ...
- Java实现蓝桥杯VIP 算法训练 P0501
试题 算法训练 P0501 资源限制 时间限制:1.0s 内存限制:256.0MB 输入两个无符号整数x, y, 用位操作实现无符号整数的乘法运算.不用考虑整数的溢出. 输入: 235 657 输出: ...
- Java实现 LeetCode 204 计数质数
204. 计数质数 统计所有小于非负整数 n 的质数的数量. 示例: 输入: 10 输出: 4 解释: 小于 10 的质数一共有 4 个, 它们是 2, 3, 5, 7 . class Solutio ...
- Java实现 LeetCode 124 二叉树中的最大路径和
124. 二叉树中的最大路径和 给定一个非空二叉树,返回其最大路径和. 本题中,路径被定义为一条从树中任意节点出发,达到任意节点的序列.该路径至少包含一个节点,且不一定经过根节点. 示例 1: 输入: ...