zoukankan      html  css  js  c++  java
  • 第三篇 基于.net搭建热插拔式web框架(重造Controller)

      由于.net MVC 的controller 依赖于HttpContext,而我们在上一篇中的沙箱模式已经把一次http请求转换为反射调用,并且http上下文不支持跨域,所以我们要重造一个controller。

      我们在写mvc项目的时候经常会用到ViewBag、ViewData,那我们就先声明这两个变量:

      

    public dynamic ViewBag = new DynamicViewBag();
    public ViewDataDictionary ViewData = new ViewDataDictionary();
    

      当然还可以根据自己的需要构建更多的特性。

       我们在一个网络请求中避免不了会携带一些参数,那这些参数该如何传到沙箱中呢?我们定义了一个RefRequestEntity类,他负责对我们的参数经行打包,把参数打包后对象作为参数传到沙箱内部:

    /// <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的简单实现:

    /// <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:

    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出去:

      [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; }
        }
    

      

            //一个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;
            }
    

      

     

    var result = sandBox.InvokeMothod(urlEntity.controller, urlEntity.action, paras);//sandBox是一个沙箱的实例化对象
    RequestHandle.ResposeResult(respond, result);//输出结果

      

    /// <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");
                }
            }
        }
    

      

       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实现)
  • 相关阅读:
    make 实例 一 3463
    python3 中对arrow库的总结(转发)
    impala 导出CSV 或excel
    设置虚拟机IP
    centos7 tomcat9
    eclipse 创建普通maven项目
    java log4j日志配置
    java运行jar命令提示没有主清单属性
    Java 读取 .properties 配置文件
    python 机器学习多项式回归
  • 原文地址:https://www.cnblogs.com/eric-z/p/5047172.html
Copyright © 2011-2022 走看看