利用多态,实现一般处理程序(ashx)中的AOP(切面编程)
本文是对工作中的项目进行代码优化(完善登陆验证的AOP切面编程)时,所遇到的各种解决方案思考过程。
项目背景:由ashx+nvelocity构建的简单B/S问卷系统,现需要优化登录验证环节(时隔若干个月在回顾代码果然是一个痛苦的过程~)
nvelocity是velocity框架针对.net的版本,核心是拼html字符串后返回客户端,与MVC的前后端代码隔离有异曲同工之妙。加之一般处理程序ashx不需要像asp.net那样走生成控件树的过程,执行上更是省时省力。故简单系统用ashx+nvelocity的形式构建笔者个人还是比较推荐的。如果那么在意访问地址(如www.abc.com/news/index.ashx?id=234)中的ashx后缀不好看,完全可以通过模块(HttpModule)来实现url重写。
本文讨论的是:如何在ashx中体现AOP切面编程思想?
(1)回顾asp.net,所有页面继承自Page类,可通过Page的子类来实现AOP。原来是:Default : Page,切面插入后是:Default : LoginCheckPage,LoginCheckPage : Page。如此便能在LoginCheckPage类中编写登录验证的代码,且能实现所有需要验证页面的有效解耦——解耦是相对于专门写一个LoginCheck类,并在各个Default页面做验证(如LoginCheck.Check(context))而言,更利于修改与拓展。
(2)回顾MVC,可以依样画葫芦像上述asp.net那样,原来是:HomeController:Controller,切面插入后是:HomeController:LoginCheckController,LoginCheckController:Controller。除此之外,还能利用类/方法头上的特性标签来做AOP。
在asp.net与MVC中的AOP体现还有许多做法,此处抛砖引玉、仅为比对ashx的AOP做思考:上述方法在ashx中能行得通吗? 能!但要做些微调:
(独写一个LoginCheck类,然后在每个需要验证的ashx.pr()中加上LoginCheck.Check(context)实在不是长久之计,故本文就不另说了)
第一种尝试:(没错,本文最后一次才尝试成功,不过写出尝试过程也是为了将自己所走的弯路做下记录,且希望能给读者更多思考的提示,感谢坚持读完三种尝试的朋友。)
利用HttpModule。类似url重写那样,url重写不都是每次请求一来就做处理吗,那Module应该也能做登陆吧——两者差异:普通的url重写不涉及客户端隔离、不考虑请求的资源,登录验证要做客户端隔离(cookie)、要考虑请求的资源(并不是所有资源都不给访问,有的是游客级别就行的)。
对于要考虑请求资源的差异,如果恶心一点,可以在代码中写死(可优化成在webcofig、其他配置文件、数据库存储)来做差异化处理——以正则表达式匹配请求地址,用来隔离需要验证登陆的请求与不需要验证的请求。
对于客户端隔离,能否直接在Module中用session?首先要使HttpModule继承自IReadonlySessionState/IRequiresSessionState接口(HttpHandler也是如此),以便在走管道的时候能被.net认出来你这个Module想用session。注册到BeginRequest事件。别忘了还要注册到webconfig。一切就绪,调试,报错——HttpApplication中的Session属性报错,未将对象引用设置到对象实例。是不是注册的事件错了?我查了一遍HttpApplication管道中的19个事件,最佳的切入点在第10-11个事件之间,也就是+=PostAcquireRequest,才能在获取Session之后、在执行ashx之前做登陆验证。
然而并没有什么X用……依旧未将对象引用设置到对象实例。怎么还是没有呢,奇了怪了。
又是一边各种查,查到一句话说得好:Module是应用程序级的事儿,是过滤作用,而Session是页面级的事儿,是要根据发来的请求做不同的处理,故在Module中用Session本就不是最佳方案。故放弃Module这条弯路。
第二种尝试:
自定义继承自IHttpHandler的ashx。原来:Index:IHttpHandler,优化后:Index:LoginCheckHandler,LoginCheckHandler:IHttpHandler。学的上述asp.net与mvc中的插入到继承树的方法。但调试结果是根本不走Index的ProcessRequest(),直接走完LoginCheckHandler.ProcessRequest()就返回了,客户端就是空白一片。究其原因:实现IHttpHandler的一般处理程序(无论是Index,还是LoginCheckHandler),都只会执行一次ProcessRequest()。
第三种尝试:
在第二种的基础上修改为:LoginCheckHandler中的ProcessRequest()改为virtual,并在Index子类中override重写,并在Index.ProcessRequest()中调用base.ProcessRequest(context)。执行的时候,程序会因为看到override而忽略父类的PR方法,而Index子类中的base.PR()又要求程序先走父类的PR方法,且结合Response.Redirect()的立即输出特性(先Flush,在End),可以使得不满足登录验证条件的请求被挡在门外。小功告成!
麻烦的是,要修改子类为override,且在子类中存在base.PR()代码(也只比简单粗暴的调用LoginCheck.Check(context)来验证减少了一些些耦合度),那么还有更好的AOP方法吗?望各位大牛看官提点。
利用多态,实现一般处理程序(ashx)中的AOP(切面编程)的更多相关文章
- [译]如何在ASP.NET Core中实现面向切面编程(AOP)
原文地址:ASPECT ORIENTED PROGRAMMING USING PROXIES IN ASP.NET CORE 原文作者:ZANID HAYTAM 译文地址:如何在ASP.NET Cor ...
- C#使用一般处理程序(ashx)中session
.ashx中引用 session必须 using System.Web.SessionState ,继承IReadOnlySessionState/IRequiresSessionState IRea ...
- Spring中的面向切面编程(AOP)简介
一.什么是AOP AOP(Aspect-Oriented Programming, 面向切面编程): 是一种新的方法论, 是对传统 OOP(Object-Oriented Programming, 面 ...
- C# 中使用面向切面编程(AOP)中实践代码整洁
1. 前言 最近在看<架构整洁之道>一书,书中反复提到了面向对象编程的 SOLID 原则(在作者的前一本书<代码整洁之道>也是被大力阐释),而面向切面编程(Aop)作为面向对象 ...
- C# 中使用面向切面编程(AOP)中实践代码整洁(转)
出处:https://www.cnblogs.com/chenug/p/9848852.html 1. 前言 最近在看<架构整洁之道>一书,书中反复提到了面向对象编程的 SOLID 原则( ...
- spring aop 切面编程中获取具体方法的方法
spring 切面编程中获取具体方法的方法 工作中,使用环绕通知,用来捕获异常,然后通过获取方法的返回值,返回不同的数据给到调用方. 由于方法的返回值不同,我们处理异常时,也需要返回不同的格式. 这时 ...
- Spring中AOP切面编程学习笔记
注解方式实现aop我们主要分为如下几个步骤: 1.在切面类(为切点服务的类)前用@Aspect注释修饰,声明为一个切面类. 2.用@Pointcut注释声明一个切点,目的是为了告诉切面,谁是它的服务对 ...
- Java中的面向切面编程(AOP)
一.什么是AOP? Aspect Oriented Programming ,即面向切面编程. AOP是对面向对象编程的一个补充. 它的目的是将复杂的需求分解为不同的切面,将散布在系统中的公共功能集中 ...
- 一般处理程序 ashx中使用外部Session 出现不存在 解决方案
MXS&Vincene ─╄OvЁ &0000004 ─╄OvЁ MXS&Vincene MXS&Vincene ─╄OvЁ:今天很残酷,明天更残酷,后天很美好 ...
- await和async在C#一般处理程序(ashx)中的使用
public class hello : HttpTaskAsyncHandler, IReadOnlySessionState { public IFetchServise fetch { get; ...
随机推荐
- Xshell连接mysql数据库乱码问题解决思路总结
乱码问题一直是一件让人头疼的事情,乱码就是编码格式不统一产生的,下面将一些常见的解决思路整理: 先Xshell连接上数据库,查看数据的编码格式: 一般需要看这么几个地方(附修改命令): 1.数据库的编 ...
- SQL语句详细汇总[转]
经典SQL语句大全 一.基础 1.说明:创建数据库CREATE DATABASE database-name 2.说明:删除数据库drop database dbname3.说明:备份sql serv ...
- vue - src for components || router(index.js)
描述:重新编写一个组件 1.1 编写一个PrintName.vue <!--这里是模板 --> <template> <div class="hello&quo ...
- 算法笔记_061:蓝桥杯练习 字串统计(Java)
目录 1 问题描述 2 解决方案 1 问题描述 问题描述 给定一个长度为n的字符串S,还有一个数字L,统计长度大于等于L的出现次数最多的子串(不同的出现可以相交),如果有多个,输出最长的,如果仍然 ...
- Windows下如何安装 Composer
如何安装 Composer Windows下如何安装 Composer 下载 Composer 安装前请务必确保已经正确安装了 PHP.打开命令行窗口并执行 php -v 查看是否正确输出版本号. 打 ...
- RAC环境下的堵塞(blocking blocked)
RAC环境下的堵塞不同于单实例情形,由于我们须要考虑到位于不同实例的session.也就是说之前查询的v$session,v$lock对应的应变化为全局范围来查找.本文提供了2个查询脚本,并给出实例演 ...
- 【微信小程序】退款功能教程(含申请退款和退款回调)
1.一定要区分小程序和公众号的退款,唯一的区别就是 appid不一样,其他的都是一样的. 不废话,直接写代码了啊. 放大招!!! 然后,需要注意的:最好是把证书放在下面的php的同级或者下级. 证书的 ...
- 安装Drupal7.12升级至7.22
怀揣着为中小企业量身定做一整套开源软件解决方案的梦想开始了一个网站的搭建.http://osssme.org/ [2013-08-11] 资料更新,Drupal 7.22升级至7.23 访问自己的Dr ...
- linux 重启网卡的方法
http://blog.163.com/drzxqing@126/blog/static/59351445201052392516841/
- 測试赛C - Eqs(哈希)
C - Eqs Time Limit:5000MS Memory Limit:65536KB 64bit IO Format:%I64d & %I64u Submit Stat ...