第三篇 基于.net搭建热插拔式web框架(重造Controller)

摘要:
因为的控制器。netMVC依赖于HttpContext,我们在上一篇文章中的沙盒模式已经将http请求转换为反射调用,而http上下文不支持跨域,因此我们需要重新创建一个控制器。在本文中,我们仍然关注控制器的实现。我们将在下一篇文章中讨论视图的实现。让我们先看看View:///的一个简单实现,它返回尝试的执行结果//////protectedstringView(){vartKey=Engine.Razor.GetKey;//getActionPath:获取与操作对应的视图文件的键值。

  由于.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实现)

免责声明:文章转载自《第三篇 基于.net搭建热插拔式web框架(重造Controller)》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇Android应用添加(创建)和删除及判断是否存在桌面快捷方式Oracle使用——PLSQL查询表结构并导出EXCEL下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

二、vue响应式对象

Object.defineProperty Object.defineProperty 方法会直接在一个对象上定义一个新属性,或者修改一个对象的现有属性, 并返回这个对象,先来看一下它的语法: Object.defineProperty(obj, prop, descriptor) obj 是要在其上定义属性的对象; prop 是要定义或修改的属性的...

[java]创建一个默认TreeMap() key为什么不能为null

 本文版权归 远方的风lyh和博客园共有,欢迎转载,但须保留此段声明,并给出原文链接,谢谢合作。 先看一下 TreeMap 的 put(K key, V value) public TreeMap() { comparator = null;} public V put(K key, V value) { Entry<K,V...

spring-redis SortedSet类型成员的过期时间处理

redis默认是只支持简单key的过期处理的,像SortedSet类型,也是针对整个set的过期处理,不支持对set的某个成员的过期处理; 为了解决这个问题,做法如下: 1.存储key及值信息到redis,并将key存入set里,设置key的过期时间; 这样key可以支持过期处理并在过期后移除key及值;但是set里的key还是存在的; a、在需要判断ke...

原来zabbix监控进程与端口是如此的简单!

使用zabbix自带key监控进程与端口 每个公司都有自己的程序,自己的进程名与端口监听,对于nagios来说,这些都经常需要自己去写插件,但是zabbix不需要,它自己就有监控进程与端口的key。 在使用zabbix的key来监控进程与端口前,我也自己写了插件,但用起来很不爽,因为需要在所有agent上都要进行配置与维护。如果用zabbix自带的功能,只...

redis 常用操作

/*1.Connection*/$redis = newRedis(); $redis->connect('127.0.0.1',6379,1);//短链接,本地host,端口为6379,超过1秒放弃链接 $redis->open('127.0.0.1',6379,1);//短链接(同上) $redis->pconnect('127.0....

php可选缓存APC

1、APC缓存简介 APC,全称是Alternative PHP Cache,官方翻译叫”可选PHP缓存”。它为我们提供了缓存和优化PHP的中间代码的框架。 APC的缓存分两部分:系统缓存和用户数据缓存。 系统缓存 它是指APC把PHP文件源码的编译结果缓存起来,然后在每次调用时先对比时间标记。如果未过期,则使用缓存的中间代码运行。默认缓存 3600s(...