当创建一个asp.net mvc 1.0的项目后,在web工程中都会出现Views文件夹,这里面就是我们存放View Page或者是partial view的地方。而且系统对于Controller的名称以及Views文件夹下面的子文件夹名称均有一定的约束。

例如,有一个名称为GuestBookController的Controller,这时我们创建View Page时,就需要在Views下面创建一个GuestBook的子文件夹,不能随便命名。然后把View page或者是partial view放进来,或者把文件放在Shared文件夹中也行,如果把view page放在web工程根目录下面,系统会找不到对应的view。

本文解决问题:针对上面的局限性,我们能不能打破呢?即可以实现如下功能:

第一:view page可以放在views之外的文件夹中。

第二:view page的名称和Controller的名称取消名称上的约束,例如:view page名称是ViewContentPage1.aspx,而对应的Controller名称是testController.cs。

实现原理:asp.net mvc之所以能根据用户请求找到对应的view page,主要是路由。这其中有一个重要的类WebFormViewEngine,它负责发现我们创建的view page或者是partial view。为此我们可以重写一个新的ViewEngine来完成我的目的。

1:先看下webformviewengine的构造函数:

代码

public WebFormViewEngine()
{
    base.MasterLocationFormats = new string[] { "~/Views/{1}/{0}.master", "~/Views/Shared/{0}.master" };
    base.ViewLocationFormats = new string[] { "~/Views/{1}/{0}.aspx", "~/Views/{1}/{0}.ascx", "~/Views/Shared/{0}.aspx", "~/Views/Shared/{0}.ascx" };
    base.PartialViewLocationFormats = base.ViewLocationFormats;
}

base.ViewLocationFormats 可以看出view page为什么只能写在views文件夹下的原因了。所以我们只需要在新的view engine的构造函数中修改下base.ViewLocationFormats 路径即可。这里我创建一个新的WebViewEngine,它需要继承WebFormViewEngine。可以这样改写:这样第一点就完成了。

代码

public WebViewEngine()
        {
            base.MasterLocationFormats = new string[] { "~/Views/{1}/{0}.master", "~/Views/Shared/{0}.master" };
            base.ViewLocationFormats = new string[] { 
                 "~/com/{0}.aspx",
                "~/com/{0}.ascx",
                "~/Views/{1}/{0}.aspx",
                "~/Views/{1}/{0}.ascx", 
                 "~/Common/Views/{0}.aspx",
               "~/Common/Views/{0}.ascx",
                "~/Views/Shared/{0}.aspx",
                "~/Views/Shared/{0}.ascx" };
            base.PartialViewLocationFormats = base.ViewLocationFormats;
        }

2:WebFormViewEngine有两个重要方法:FindPartialView以及FindView。它负责从用户请求以及路由配置中查找到具体的view page或者是partial view。第二点就可以在这下手。
         首先:我们需要修改下路由配置,增加一个参数viewpath,用来指定路由规则使用的view path路径。

代码

routes.MapRoute(
                "Default2",
                "ViewContentPage1.aspx",
                new { id = "", viewpath = "~/com/ViewContentPage1.aspx", controller = "test", action = "test" }
            );

其次:修改下WebFormViewEngine的源码:这里主要是修改GetPath方法,它最终会返回一个view page的路径。这样我们就可以这样访问了http://www.testmy.com/guestbook/ViewContentPage1.aspx。

代码

public override ViewEngineResult FindPartialView(ControllerContext controllerContext, string partialViewName, bool useCache)
        {
            string[] strArray;
            if (controllerContext == null)
            {
                throw new ArgumentNullException("controllerContext");
            }
            if (string.IsNullOrEmpty(partialViewName))
            {
                throw new ArgumentException("MvcResources.Common_NullOrEmpty", "partialViewName");
            }
            string requiredString = controllerContext.RouteData.GetRequiredString("controller");
            //string vp = this.GetParam(controllerContext, "viewpath");
            //if (!string.IsNullOrEmpty(vp))
            //{
            //    requiredString = vp;
            //}
            string str2 = this.GetPath(controllerContext, this.PartialViewLocationFormats, "PartialViewLocationFormats", partialViewName, requiredString, "Partial",

useCache,false , out strArray);
            if (string.IsNullOrEmpty(str2))
            {
                return new ViewEngineResult(strArray);
            }
            return new ViewEngineResult(this.CreatePartialView(controllerContext, str2), this);

}
        public override ViewEngineResult FindView(ControllerContext controllerContext, string viewName, string masterName, bool useCache)
        {
            string[] strArray;
            string[] strArray2;
            if (controllerContext == null)
            {
                throw new ArgumentNullException("controllerContext");
            }
            if (string.IsNullOrEmpty(viewName))
            {
                throw new ArgumentException("ArgumentException", "viewName");
            }
            string requiredString = controllerContext.RouteData.GetRequiredString("controller");
            //string vp=this.GetParam(controllerContext, "viewpath");
            //if (!string.IsNullOrEmpty(vp))
            //{
            //    requiredString = vp;
            //}
            string str2 = this.GetPath(controllerContext, this.ViewLocationFormats, "ViewLocationFormats", viewName, requiredString, "View", useCache,true , out strArray);
            string str3 = this.GetPath(controllerContext, this.MasterLocationFormats, "MasterLocationFormats", masterName, requiredString, "Master", useCache,true , out

strArray2);
            if (string.IsNullOrEmpty(str2) || (string.IsNullOrEmpty(str3) && !string.IsNullOrEmpty(masterName)))
            {
                return new ViewEngineResult(strArray.Union<string>(strArray2));
            }
            return new ViewEngineResult(this.CreateView(controllerContext, str2, str3), this);

}
        private string GetParam(ControllerContext controllerContext, string key)
        {
            return controllerContext.RouteData.Values[key] != null ? controllerContext.RouteData.Values[key].ToString() : string.Empty;
        }
        private string GetPath(ControllerContext controllerContext, string[] locations, string locationsPropertyName, string name, string controllerName, string cacheKeyPrefix,

bool useCache, bool isfindview, out string[] searchedLocations)
        {
            searchedLocations = _emptyLocations;
            if (string.IsNullOrEmpty(name))
            {
                return string.Empty;
            }
            if ((locations == null) || (locations.Length == 0))
            {
                throw new InvalidOperationException(string.Format(CultureInfo.CurrentUICulture, "MvcResources.Common_PropertyCannotBeNullOrEmpty", new object[] {

locationsPropertyName }));
            }
            bool flag = IsSpecificPath(name);
            string key = this.CreateCacheKey(cacheKeyPrefix, name, flag ? string.Empty : controllerName);
            if (useCache)
            {
                string viewLocation = this.ViewLocationCache.GetViewLocation(controllerContext.HttpContext, key);
                if (viewLocation != null)
                {
                    return viewLocation;
                }
            }
            
            return (flag ? this.GetPathFromSpecificName(controllerContext, name, key,isfindview , ref searchedLocations) : this.GetPathFromGeneralName(controllerContext,

locations, name, controllerName, key,isfindview , ref searchedLocations));
        }
        private string CreateCacheKey(string prefix, string name, string controllerName)
        {
            return string.Format(CultureInfo.InvariantCulture, ":ViewCacheEntry:{0}:{1}:{2}:{3}:", new object[] { base.GetType().AssemblyQualifiedName, prefix, name,

controllerName });
        }
        private static bool IsSpecificPath(string name)
        {
            char ch = name[0];
            return ((ch == '~') || (ch == '/'));
        }
        private string GetPathFromSpecificName(ControllerContext controllerContext, string name, string cacheKey,bool isfindview, ref string[] searchedLocations)
        {
            string virtualPath = name;
            if (!this.FileExists(controllerContext, name))
            {
                if (isfindview)
                {
                    string vp = this.GetParam(controllerContext, "viewpath");
                    if (!string.IsNullOrEmpty(vp))
                    {
                        virtualPath = vp;
                    }
                    if (string.IsNullOrEmpty(virtualPath))
                    {
                        virtualPath = string.Empty;
                        searchedLocations = new string[] { name };
                    }
                }
                else
                {
                    virtualPath = string.Empty;
                    searchedLocations = new string[] { name };
 
                }
            }
            this.ViewLocationCache.InsertViewLocation(controllerContext.HttpContext, cacheKey, virtualPath);
            return virtualPath;
        }
        private string GetPathFromGeneralName(ControllerContext controllerContext, string[] locations, string name, string controllerName, string cacheKey, bool isfindview, ref

string[] searchedLocations)
        {
            string virtualPath = string.Empty;
            searchedLocations = new string[locations.Length];
            for (int i = 0; i < locations.Length; i++)
            {
                string str2 = string.Format(CultureInfo.InvariantCulture, locations[i], new object[] { name, controllerName });
                if (this.FileExists(controllerContext, str2))
                {
                    searchedLocations = _emptyLocations;
                    virtualPath = str2;
                    this.ViewLocationCache.InsertViewLocation(controllerContext.HttpContext, cacheKey, virtualPath);
                    return virtualPath;
                }
                else
                {
                    if (isfindview)
                    {
                        string vp = this.GetParam(controllerContext, "viewpath");
                        if (!string.IsNullOrEmpty(vp))
                        {
                            searchedLocations = _emptyLocations;
                            virtualPath = vp;
                            return virtualPath;
                        }
                    }

}
                searchedLocations[i] = str2;
            }
            return virtualPath;
        }

最后:在程序中注册新的view engine:        

            //注册viewEngine
            ViewEngines.Engines.Clear();
            ViewEngines.Engines.Add(new
 WebViewEngine());
            RegisterRoutes(RouteTable.Routes);

           总结:很久没有更新mvc的文章了,不过这篇在实际项目中还是非常有用的,例如,我们可以把两个不同的view page指定同一个Controller等等。

作者:姜敏
出处:http://www.cnblogs.com/aspnet2008/

转载于:https://www.cnblogs.com/ASPNET2008/archive/2010/06/30/1768497.html

asp.net mvc(十一)自定义view engine相关推荐

  1. [ASP.NET MVC] 利用自定义的AuthenticationFilter实现Basic认证

    很多情况下目标Action方法都要求在一个安全上下文中被执行,这里所谓的安全上下文主要指的是当前请求者是一个经过授权的用户.授权的本质就是让用户在他许可的权限范围内做他能够做的事情,授权的前提是请求者 ...

  2. ASP.NET MVC - 设置自定义IIdentity或IPrincipal

    我需要做一些相当简单的事情:在我的ASP.NET MVC应用程序中,我想设置一个自定义IIdentity / IPrincipal. 哪个更容易/更合适. 我想扩展默认值,以便我可以调用User.Id ...

  3. asp.net MVC之 自定义过滤器(Filter)

    一.系统过滤器使用说明 1.OutputCache过滤器 OutputCache过滤器用于缓存你查询结果,这样可以提高用户体验,也可以减少查询次数.它有以下属性: Duration:缓存的时间,以秒为 ...

  4. 【译】Asp.net MVC 利用自定义RouteHandler来防止图片盗链 (转)

    你曾经注意过在你服务器请求日志中多了很多对图片资源的请求吗?这可能是有人在他们的网站中盗链了你的图片所致,这会占用你的服务器带宽.下面这种方法可以告诉你如何在ASP.NET MVC中实现一个自定义Ro ...

  5. ASP.NET MVC: 使用自定义 ModelBinder 过滤敏感信息

    昨天发表了一篇随笔<ASP.NET MVC: 使用 Filters 附加过滤敏感信息功能>(以下简称<Filter过滤>),今天一早醒来发现一处重大漏洞,于是在发了一条评论指出 ...

  6. ASP.NET MVC 动态选择VIEW

    若要在 ASP.NET MVC 中创建视图,通常是调用一个使用模型来准备视图数据的操作方法. 然后,该操作方法调用控制器的 View 方法来创建视图. 但是,您可能要调用不同的操作方法来创建视图的不同 ...

  7. ASP.NET MVC过滤器自定义Authorize实现身份验证

    最近在做一个.NET MVC框架的后台项目,涉及到5个权限,而控制器下的方法有些只能高权限用户使用,低权限用户不能访问,一开始是在方法里面写判断,但是功能方法多了以后,发现代码重复的很严重,不符合面向 ...

  8. asp.net mvc 如何在View中获取Url参数的值

    如果url是 /home/index?id=3 直接Request就ok. 但是如果路由设定为:{controller}/{action}/{id} url是 /home/index/3    这时想 ...

  9. ASP.NET MVC ActionFilter自定义过滤器异常过滤器过滤器用法

    自定义过滤器使用非常灵活,可以精确的注入到请求前.请求中和请求后.继承抽象类ActionFilterAttribute并重写里面的方法即可: public class SystemLogAttribu ...

最新文章

  1. web页面实现地图展示,可缩放,标点并点击---使用高德地图
  2. 利用matlab实现SAR 图像线性拉伸显示
  3. JavaFX将会留下来!
  4. 具有Spring Boot和数据功能的Java头优先弹性搜索
  5. DataTemplate——数据模板的一个典型例子
  6. 通过DOS命令nslookup查域名DNS服务器
  7. pillow是python的图像处理标准库_详解Python图像处理库Pillow常用使用方法
  8. 精诚合作 共创未来——阿里云数据智能合作策略介绍
  9. 旅游中用稳定器和相机拍视频是怎样的体验?
  10. 如何测量C#代码的运行时间
  11. 代码审计:命令注入学习
  12. 来自于51CTO的经典学习资料汇总
  13. codeforces Div.2(5.21)B题
  14. 谈谈如何正确的送领土
  15. 因计算机中丢失msvcr120.dll,msvcr120.dll一键修复工具 | 麦田一棵葱
  16. 高效记忆/形象记忆(06)110数字编码表 01-10
  17. 搭建个人云盘保姆级教程
  18. 数据分析之数据透视表(Office2019)
  19. 服务器有无线网卡么,全面认识服务器网卡:理论篇
  20. PL/0 语言简介、PL/0 文法

热门文章

  1. [暖冬限定]DevExpress WinForms冬季款皮肤/主题全新上线
  2. android qq pad,腾讯QQ for Pad Android版本流出
  3. Switch 中参数的范围探讨
  4. PHP学习笔记之PHP函数(三)
  5. 【操作系统篇】第一篇——计算机系统概述(上)
  6. EM算法之推荐系统(二)隐语义模型
  7. 从公众号内跳转到另一个公众号关注页面怎么实现
  8. ES9JavaScript新特性
  9. 油田钻头行业调研报告 - 市场现状分析与发展前景预测
  10. 90后主导下美妆新青年的需求手册.pdf