重写IHttpHandler,实现前后端分离

再说重写IHttpHandler,实现前后端分离

aspx页面第一次加载时,HttpHandler 里面是如何编译指定页面的呢?Framework提供了编译页面的API如下:

BuildManager.CreateInstanceFromVirtualPath(url, typeof(System.Web.UI.Page));根据虚拟路径生成实例。

但是url页面此时必需继承System.Web.UI.Page,就是我们常见的ASPX页面。但是这样编译时会调用aspx视图引擎来解析aspx和对应的CodeBehind类。

对于前台纯粹用JSON渲染的JS插件,解析编译ASPX页面似乎是多余的,aspx的生命周期也是复杂和没什么卵用的,那问题来了,能不能只编译类文件(当然要继承IHttpHandler),而aspx页面用html替换呢?

如下图的结构,(如何一键建立这样的文件结构下次再说,MVC中View和Controller分的太开了,不太习惯,中小型项目还是这样觉的更好。)

目标:html上发送ajax请求到.cs上,并返回数据到.html

Framework提供一个方法:

var ass = BuildManager.GetCompiledAssembly(url);根据虚拟路径得到程序集。第一次加载需要编译慢一点,之后会很快。

url可以是这样:/Portal/ListPageTmp.cs,即根据class文件路径生成Assembly,

当然此时浏览器url是/Portal/ListPageTmp.html

我们可以在前台ajax请求时就把路径由/Portal/ListPageTmp.html转换成/Portal/ListPageTmp.cs,再发送ajax,也可以在后台GetHandler方法里面转换。

我是在前台转换的如下:(把$.ajax封装一下,确保所有AJAX都调用此方法以便转换url)

$.ajax({
type: ‘post‘,
url: ‘/Portal/ListPageTmp.cs’,
async: async,
data: data,
success: function (data) { rtn = data; },
error: function (data) { rtn["result"] = "fail"; alert("操作失败") },
dataType: ‘json‘
});

要想以这样ajax请求(/Portal/ListPageTmp.cs)让IIS接收到 那必然要改web.Config:不解释

<system.webServer>
<handlers>
<add name="ddd" verb="*" path="*.cs" type="App.PageBase.CSHttpHandler" />
</handlers>
</system.webServer>

以下是IHttpHandlerFactory完整代码:

 1  public class CSHttpHandler : IHttpHandlerFactory
 2     {
 3         public IHttpHandler GetHandler(HttpContext context, string requestType, string url, string pathTranslated)
 4         {
 5
 6             try
 7             {
 8                 var ass = BuildManager.GetCompiledAssembly(url);//重要的一个方法,也见过其它的跟据url生成实例的方法,但是如果不同命名空间有同名类就不好办了。
 9                // var d = BuildManager.CreateInstanceFromVirtualPath(url, typeof(System.Web.UI.Page));
10
11                 TypeInfo pageType = ass.DefinedTypes.Where(p => p.IsClass == true && p.BaseType.BaseType == typeof(BasePage)).FirstOrDefault();
12                 BasePage basepage = Activator.CreateInstance(pageType) as BasePage;
13                 return (IHttpHandler)basepage;
14             }
15             catch (Exception ex)
16             {
17                 throw ex;
18             }
19
20         }
21
22         public void ReleaseHandler(IHttpHandler handler)
23         {
24
25
26         }
27
28     }

BasePage类,和System.Web.UI.Page类功能相当。

  1     public class BasePage : IHttpHandler
  2     {
  3
  4      private bool _IsAjaxRequest;
  7         private string _Action;
  8         private ActionResult _ActionResult;
  9         AppCache cache = new AppCache();
 10         public BasePage()
 11         {
 12             this.IsCheckLogin = true;
 13
 14             this.IsCheckAuth = true;
 15
 16             _ActionResult = new ActionResult();
 17
 18
 19
 20         }
 21
 22         public bool IsReusable { get; set; }
 23         protected HttpRequest Request
 24         {
 25             get;
 26             set;
 27         }
 28         protected HttpResponse Response
 29         {
 30             get;
 31             set;
 32         }
 33
 34         public virtual void ProcessRequest(HttpContext context)
 35         {
 36             this.Request = context.Request;
 37             this.Response = context.Response;
 38             this.OnInit();
 39
 40         }
 41         protected string Action
 42         {
 43             get
 44             {
 45                 return _Action;
 46             }
 47
 48
 49         }            //判断是否AJAX请求,这种模式,到这里的请求都是AJAX请求,因为HTML加载时不用触发请求到后端的。
 50         protected bool IsAjaxRequest
 51         {
 52             get
 53             {
 54                 return _IsAjaxRequest;
 55             }
 56
 57
 58         }
 59         protected virtual void OnInit()
 60         {
 61             _IsAjaxRequest = this.Request.Headers["X-Requested-With"] == "XMLHttpRequest" ? true : false;
 62             _Action = Request.QueryString["Action"] == null ? "" : Request.QueryString["Action"].ToString();
 63             form = new FormData(Request.Form);                //根据URL上的Action参数找到继承此类上的方法,并反射调用。

MethodInfo method = this.GetType().GetMethod(Action);
if (method == null)
{
throw new Exception("找不到【" + method.Name + "】方法.");
}
else
{
try
{

//绑定参数并调用,当然调用前也可以也可以做ActionFilter检查
InvokMethod(this, method);


}
catch (Exception ex)
{
 actionResut.hasError = true;
 actionResut.message = ex.InnerException.Message;
}


}

//返回json数据
ReturnData(actionResut);

 64         }            //绑定Action方法的参数。
 65         protected object InvokMethod(object ins, MethodInfo method)
 66         {
 67
 68
 69             var methodParam = method.GetParameters();
 70             object[] param = new object[methodParam.Length];
 71             for (int i = 0; i < methodParam.Length; i++)
 72             {
 73                 string name = methodParam[i].Name;
 74                 Type paramType = methodParam[i].ParameterType;
 75                 if (paramType.IsGenericType) paramType = paramType.GetGenericArguments()[0];
 76                 string ArgValue = Request.QueryString[name];
 77                 string FormValue = Request.Form[name];
 78                 string value = string.IsNullOrEmpty(ArgValue) ? FormValue : ArgValue;
 79                 if (!string.IsNullOrEmpty(value))
 80                 {
 81                     if (paramType.IsValueType)
 82                     {
 83                         param[i] = Convert.ChangeType(value, paramType);
 84                     }
 85                     else if (paramType == typeof(string))
 86                     {
 87                         param[i] = value;
 88                     }
 89                     else
 90                     {
 91                         param[i] = JsonHelper.Json2Object(value.ToString(), paramType);
 92                     }
 93                 }
 94
 95                 else
 96                 {
 97                     param[i] = null;
 98                 }
 99             }
100             return method.Invoke(ins, param);
101
102         }
103 }

ListPageTmp.html对应的类文件是这样的:
如果有ListPageTmp.html?Action=Test&Id=1&name=zhangsan的ajax请求,会根据名称找到ListPageTmp.cs,实例化后将url参数绑定到Test方法参数上执行,返回JSON.
 

 1     public partial class ListPageTmp :BasePage
 2     {
 3                [Auth(Role="Admin")]//反射调用前也可检查是否有attribute并做 拦截 ,类似MVC的ActionFilter.
 4         public void Test(int Id,string name)
 5         {
 6
 7             actionResut.Add("Name",name);
               actionResut.Add("Id",Id);
 8
 9         }
10
11
12
13     }

这样前后端就分开了。html加载完成后,根据不同需要发送ajax从服务端取json数据绑定的前台。

也实现了MVC里面的一些功能,如ActionFilter,Action参数绑定,ActionResult和MVC的不太一样。没有很复杂的ActionResult,只是封装json.

MVC是通过URL 路由 找到 Control和Action,由Action定向到View,

今天说的这个方案,是通过View找到Control和Action 执行后返回JSON给View.

唉,不知道说明白了没有。。。。

分类: .NET

时间: 2024-08-09 17:13:25

重写IHttpHandler,实现前后端分离的相关文章

关于大型网站技术演进的思考(十七)--网站静态化处理—满足静态化的前后端分离(9)

前后端分离的主题虽然讲完了,但是前后端分离的内容并没有结束,本篇将继续前后端分离的问题,只不过这次前后端分离的讲述将会围绕着本系列的主题网站静态化进行.在讲本篇主题之前,我需要纠正一下前后端分离主题讲述中会让朋友们产生误导的地方,这种误导就是对时下流行的一些前后端分离方案(没有使用nodejs的前后端分离方案)的评价问题,其实本人任然觉得不管什么样的前后端分离方案只要成功被实施,并且产生了良好的效果,那么它就是一个成功的前后端分离方案,前面我以一种批判的角度讲述这些前后端分离方案,并不是想在否定

[转] 前后端分离开发模式的 mock 平台预研

引入 mock(模拟): 是在项目测试中,对项目外部或不容易获取的对象/接口,用一个虚拟的对象/接口来模拟,以便测试. 背景 前后端分离 前后端仅仅通过异步接口(AJAX/JSONP)来编程 前后端都各自有自己的开发流程,构建工具,测试集合 关注点分离,前后端变得相对独立并松耦合 开发流程 后台编写和维护接口文档,在 API 变化时更新接口文档 后台根据接口文档进行接口开发 前端根据接口文档进行开发 开发完成后联调和提交测试 面临问题 没有统一的文档编写规范,导致文档越来越乱,无法维护和阅读 开

【开源.NET】 分享一个前后端分离的轻量级内容管理框架

开发框架要考虑的面太多了:安全.稳定.性能.效率.扩展.整洁,还要经得起实践的考验,从零开发一个可用的框架,是很耗时费神的工作.网上很多开源的框架,为何还要自己开发?我是基于以下两点: 没找到合适的:安全.稳定.简单.易用.高效.免费: 想成为架构师: 于是就自己动手,参考网上开源的项目和借鉴网友的设计思路(特别是萧秦系列博文),结合自己的实践,开发了一个简单.易用.高效的的框架,虽然不完善,但也能解决现实中的问题.不过随着见识增广,发现没负责过千万级别的项目难以成为架构师,也不可能开发出一个完

【转】关于大型网站技术演进的思考(十七)--网站静态化处理—满足静态化的前后端分离(9)

前后端分离的主题虽然讲完了,但是前后端分离的内容并没有结束,本篇将继续前后端分离的问题,只不过这次前后端分离的讲述将会围绕着本系列的主题网站静态化进行.在讲本篇主题之前,我需要纠正一下前后端分离主题讲述中会让朋友们产生误导的地方,这种误导就是对时下流行的一些前后端分离方案(没有使用nodejs的前后端分离方案)的评价问题,其实本人任然觉得不管什么样的前后端分离方案只要成功被实施,并且产生了良好的效果,那么它就是一个成功的前后端分离方案,前面我以一种批判的角度讲述这些前后端分离方案,并不是想在否定

前后端分离实践

前后端分离并不是什么新鲜事,到处都是前后端分离的实践.然而一些历史项目在从一体化 Web 设计转向前后端分离的架构时,仍然不可避免的会遇到各种各样的问题.由于层出不穷的问题,甚至会有团队质疑,一体化好好的,为什么要前后端分离? 说到底,并不是前后分离不好,只是可能不适合,或者说--设计思维还没有转变过来-- 一体式 Web 架构示意 前后分离式 Web 架构示意 为什么要前后端分离 比为什么要前后端分离更现实的问题是什么时候需要前后端分离,即前后端分离的应用场景. 说起这个问题,我想到了 201

[原创]基于VueJs的前后端分离框架搭建之完全攻略

首先请原谅本文标题取的有点大,但并非为了哗众取宠.本文取这个标题主要有3个原因,这也是写作本文的初衷: (1)目前国内几乎搜索不到全面讲解如何搭建前后端分离框架的文章,讲前后端分离框架思想的就更少了,而笔者希望在本文中能够全面.详细地阐述我们团队在前后端分离的摸索中所得到的搭建思路.最佳实践以及架构思想: (2)我们团队所搭建的前后端分离框架,并非只是将网上传播的知识碎片简单拼装,而是一开始就从全局出发,按照整个系统对前后端分离框架的最高期望进行设计,到目前为止,可以说我们的框架完全实现了对我们

SpringBoot20 集成SpringSecurity02 -&gt; 利用SpringSecurity进行前后端分离的登录验证

1 SpirngBoot环境搭建 创建一个SpringBoot项目即可,详情参见三少的相关博文 参考博文 -> 点击前往 SpirngBoot项目脚手架 -> 点击前往 2 引入SpirngSecurity依赖 技巧01:引入了springSecurity相关依赖后,项目就会被SpringSecurity进行管理了:默认的登录名为user,登录密码会被打印到控制台上 技巧02:SpringSecurity默认的配置使用的是 <!--spring-security相关--> <

SpringBoot2.0.3 + SpringSecurity5.0.6 + vue 前后端分离认证授权

新项目引入安全控制 项目中新近添加了Spring Security安全组件,前期没怎么用过,加之新版本少有参考,踩坑四天,终完成初步解决方案.其实很简单,Spring Security5相比之前版本少了许多配置,操作起来更轻量 MariaDb登录配置加密策略 SpringSecurity5在执行登录认证时,需预设加密策略. 坑一:加密策略配置,验密始终不通过,报错401 坑二:本地重写的UserDetailsService实现类在注入的时候找不到,目前图省事直接用了 @Qualifier制定 其

从壹开始前后端分离【 .NET Core2.0 Api + Vue 2.0 + AOP + 分布式】框架之七 || API项目整体搭建 6.2 轻量级ORM

代码已上传Github,文末有地址 书接上文:<从壹开始前后端分离[ .NET Core2.0 Api + Vue 2.0 + AOP + 分布式]框架之六 || API项目整体搭建 6.1 仓储>,我们简单的对整体项目进行搭建,用到了项目中常见的仓储模式+面向接口编程,核心的一共是六层,当然你也可以根据自己的需求进行扩展,比如我在其他的项目中会用到Common层,当然我们这个项目接下来也会有,或者我还会添加Task层,主要是作为定时项目使用,我之前用的是Task Schedule,基本能满足