再说重写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