第三篇 基于.net搭建热插拔式web框架(重造Controller)
由于.net MVC 的controller 依赖于HttpContext,而我们在上一篇中的沙箱模式已经把一次http请求转换为反射调用,并且http上下文不支持跨域,所以我们要重造一个controller。
我们在写mvc项目的时候经常会用到ViewBag、ViewData,那我们就先声明这两个变量:
1 2 | public dynamic ViewBag = new DynamicViewBag(); public ViewDataDictionary ViewData = new ViewDataDictionary(); |
当然还可以根据自己的需要构建更多的特性。
我们在一个网络请求中避免不了会携带一些参数,那这些参数该如何传到沙箱中呢?我们定义了一个RefRequestEntity类,他负责对我们的参数经行打包,把参数打包后对象作为参数传到沙箱内部:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | /// <summary>用户的请求信息 /// </summary> [Serializable] public class RefRequestEntity { /// <summary>当前用户在本页面具备的所有权限 /// </summary> public List<RightEntity> PageRights; /// <summary>用户请求携带的所有参数 /// </summary> public HuberRequest< string , object > Request; /// <summary> /// 用户id /// </summary> public string UserID { get ; set ; } public RefRequestEntity() { PageRights = new List<RightEntity>(); Request = new HuberRequest< string , object >(); } } |
在.net mvc中我们可以返回ActionResult,在ActionResult内部调用时才会做出真正的Response(更多细节请参考mvc实现原理),当然它在执行的整个过程中都是由HttpContext贯穿的,我们没有了HttpContext,我们就只自己构造一些Response方法。
返回View()结果:
mvc中由ViewEngine来编译执行我们写好的视图文件(.aspx、.cshtml),而我们则借助于RazorEngine来编译执行razor视图文件,它可以支持我们常用的ViewBag、using、layout等(更多请见RazorEngine)。在本篇中我们还是把精力放回controller的实现中,关于视图的实现我们在下一篇中在讲。我们先看一下一个View的简单实现:
1 2 3 4 5 6 7 8 9 10 | /// <summary>返回试图的执行结果 /// </summary> /// <returns></returns> protected string View() { var tKey = Engine.Razor.GetKey(getActionPath(), ResolveType.Global); //getActionPath:获取action对应的视图文件key值。 return new CompileView().RunCompile(tKey, null , null , ViewBag); //返回执行结果 } |
View()的执行结果是一段html代码。这样我们在请求一个action的时候,就可以正常的呈现一个页面了。下边是一个Controller基类的实现,它完成了View、PartialView的实现Demo:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 | public class HuberController { public dynamic ViewBag = new DynamicViewBag(); public ViewDataDictionary ViewData = new ViewDataDictionary(); /// <summary>设置ViewBag的值 /// </summary> /// <param name="key">键</param> /// <param name="value">值</param> internal void AddViewBageValues( string key, object value) { Impromptu.InvokeSet(ViewBag, key, value); } /// <summary>返回试图的执行结果 /// </summary> /// <returns></returns> protected string View() { var tKey = Engine.Razor.GetKey(getActionPath(), ResolveType.Global); return new CompileView().RunCompile(tKey, null , null , ViewBag); } /// <summary>返回试图的执行结果 /// </summary> /// <typeparam name="T">model的类型</typeparam> /// <param name="model">model</param> /// <returns></returns> protected string View<T>(T model) { var tKey = Engine.Razor.GetKey(getActionPath(), ResolveType.Global); return new CompileView().RunCompile(tKey, typeof (T), model, ViewBag); } /// <summary>返回试图的执行结果 /// </summary> /// <param name="viewName">视图的全路径(相对于运行目录的全路径)</param> /// <returns></returns> protected string View( string viewName) { var tKey = Engine.Razor.GetKey(getActionPathWith(viewName), ResolveType.Global); return new CompileView().RunCompile(tKey, null , null , ViewBag); } /// <summary>返回试图的执行结果 /// </summary> /// <typeparam name="T">model的类型</typeparam> /// <param name="viewName">视图的全路径(相对于运行目录的全路径)</param> /// <param name="model">model</param> /// <returns></returns> protected string View<T>( string viewName, T model) { var tKey = Engine.Razor.GetKey(getActionPathWith(viewName), ResolveType.Global); return new CompileView().RunCompile(tKey, typeof (T), model, ViewBag); } /// <summary>返回局部试图的执行结果 /// </summary> /// <returns></returns> protected string PartialView() { var tKey = Engine.Razor.GetKey(getActionPath(), ResolveType.Include); return new CompileView().RunCompile(tKey, null , null , ViewBag); } /// <summary>返回局部试图的执行结果 /// </summary> /// <typeparam name="T">model的类型</typeparam> /// <param name="model">model</param> /// <returns></returns> protected string PartialView<T>(T model) { var tKey = Engine.Razor.GetKey(getActionPath(), ResolveType.Include); return new CompileView().RunCompile(tKey, typeof (T), model, ViewBag); } /// <summary>返回局部试图的执行结果 /// </summary> /// <param name="viewName">视图的全路径(相对于运行目录的全路径)</param> /// <returns></returns> protected string PartialView( string viewName) { var tKey = Engine.Razor.GetKey(getActionPathWith(viewName), ResolveType.Include); return new CompileView().RunCompile(tKey, null , null , ViewBag); } /// <summary>返回局部试图的执行结果 /// </summary> /// <typeparam name="T">model的类型</typeparam> /// <param name="viewName">视图的全路径(相对于运行目录的全路径)</param> /// <param name="model">model</param> /// <returns></returns> protected string PartialView<T>( string viewName, T model) { var tKey = Engine.Razor.GetKey(getActionPathWith(viewName), ResolveType.Include); return new CompileView().RunCompile(tKey, typeof (T), model, ViewBag); } /// <summary>获取action对应view的物理文件地址 /// </summary> /// <returns></returns> private string getActionPath() { string key = string .Empty; StackTrace trace = new StackTrace(); MethodBase methodName = trace.GetFrame(2).GetMethod(); string className = methodName.ReflectedType.FullName; string assName = HuberHttpModule.CurDomainAssemblyName; key = className.Substring(assName.Length); key = key.Replace( ".Controllers." , ".Views." ); key = key.Substring(0, key.Length - 10); key = key.Replace( "." , "\\" ); key += "\\" + methodName.Name + ".cshtml" ; return key; } /// <summary>根据action名获取其对应view的物理文件地址 /// </summary> /// <param name="ActionName">action名(同一controller中)</param> /// <returns></returns> private string getActionPathWith( string ActionName) { string key = string .Empty; StackTrace trace = new StackTrace(); MethodBase methodName = trace.GetFrame(2).GetMethod(); string className = methodName.ReflectedType.FullName; string assName = HuberHttpModule.CurDomainAssemblyName; key = className.Substring(assName.Length); key = key.Replace( ".Controllers." , ".Views." ); key = key.Substring(0, key.Length - 10); key = key.Replace( "." , "\\" ); key += "\\" + ActionName + ".cshtml" ; return key; } } |
我们上边列出了对Razor编译执行的简单过程,还是那句话,RazorEngine的更多实现细节将在下一篇讲解。那么现在问题来了,我们得到了html代码或者说我们执行玩自己的业务逻辑以后如何把这个结果输出呢(即HttpResponse)?
我们定义了一个RefRespondEntity类,它来承载返回结果,并把结果返回到沙箱外层的调用者,再由这个调用者将这个RefRespondEntity对象Response出去:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | [Serializable] public class RefRespondEntity { public RefRespondEntity(RespondType type) { ResultType = type; } /// <summary>返回结果的数据类型 /// </summary> public RespondType ResultType { get ; set ; } /// <summary>返回结果的内容 /// 如果是ResultType=_Redirect那么ResultContext=301 /// 如果是ResultType=_Stream那么ResultContext="文件名.zip",当然这个文件名可以随意定义 /// </summary> public object ResultContext { get ; set ; } /// <summary>返回结果的文件流 /// </summary> public byte [] ResultStream { get ; set ; } } |
1 2 3 4 5 6 7 8 9 10 11 12 13 | //一个action的demo public RefRespondEntity Index4(RefRequestEntity param) { object AA = param.Request[ "A" ]; object BB = param.Request[ "B" ]; object CC = param.Request[ "C" ]; RefRespondEntity result = new RefRespondEntity(RespondType._String); result.ResultContext = View(); object tt = ViewBag.test; return result; } |
1 | var result = sandBox.InvokeMothod(urlEntity.controller, urlEntity.action, paras); //sandBox是一个沙箱的实例化对象RequestHandle.ResposeResult(respond, result);//输出结果 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 | /// <summary>响应工具类 /// </summary> public class RequestHandle { private static bool IsAjax(HttpRequest request) { return request.Headers[ "X-Requested-With" ] != null ; } /// <summary>将reques请求的参数封装到CorRefEntity对象中 /// </summary> /// <param name="para"></param> /// <param name="request"></param> public static void FillCorRefEntity(RefRequestEntity para, HttpRequest request) { foreach ( var key in request.Params.AllKeys) { para.Request.Add(key, request.Params[key]); } } /// <summary>URL404 /// </summary> /// <param name="request"></param> /// <param name="respond"></param> public static void ResponseNotfound(HttpRequest request, HttpResponse respond) { if (IsAjax(request)) { respond.Write(ResponseCodeEntity.CODE404); respond.End(); } else { respond.Redirect(ResponseCodeEntity.ULR404); respond.End(); } } /// <summary>NoLogin /// </summary> /// <param name="request"></param> /// <param name="respond"></param> public static void ResponseNoLogin(HttpRequest request, HttpResponse respond) { if (IsAjax(request)) { respond.Write(ResponseCodeEntity.NoLogin); respond.End(); } else { respond.Redirect(ResponseCodeEntity.LoginURL); //需要改成非调转形式 respond.End(); } } /// <summary>NoRight /// </summary> /// <param name="request"></param> /// <param name="respond"></param> public static void ResponseNoRight(HttpRequest request, HttpResponse respond) { if (IsAjax(request)) { respond.Write(ResponseCodeEntity.NoRight); respond.End(); } else { respond.Redirect(ResponseCodeEntity.NoRightURL); //需要改成非调转形式 respond.End(); } } public static void ResposeResult(HttpResponse respond, object result) { if ( typeof (RefRespondEntity) == result.GetType()) { RefRespondEntity temp_result = (RefRespondEntity)result; if (temp_result.ResultType == RespondType._Redirect) { respond.Redirect(( string )temp_result.ResultContext); respond.End(); } else if (temp_result.ResultType == RespondType._Stream) { byte [] st = ( byte [])temp_result.ResultStream; respond.ContentType = "application/octet-stream" ; respond.AddHeader( "Content-Disposition" , string .Format( "attachment; filename={0}" , ( string )temp_result.ResultContext)); respond.OutputStream.Write(st, 0, st.Length); respond.End(); } else { respond.Write(temp_result.ResultContext); respond.End(); } } else { respond.Write( "Huber Module respose is not a RefRespondEntity" ); } } } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | public class ResponseCodeEntity { /// <summary>404 /// </summary> public static string ULR404 = "/NotPageFound/_404" ; /// <summary>404ajax /// </summary> public static string CODE404 = "NotPage" ; /// <summary>登录页URL /// </summary> public static string LoginURL = "/User/Login" ; /// <summary>未登录ajax /// </summary> public static string NoLogin = "NoLogin" ; /// <summary>没有权限ajax /// </summary> public static string NoRight = "NoRight" ; /// <summary>没有权限url /// </summary> public static string NoRightURL = "/User/NoRight" ; } |
转载请注明出处:http://www.cnblogs.com/eric-z/p/5047172.html
第四篇 基于.net搭建热插拔式web框架(RazorEngine实现)
【推荐】还在用 ECharts 开发大屏?试试这款永久免费的开源 BI 工具!
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步