zoukankan      html  css  js  c++  java
  • asp.net mvc(十一)自定义view engine

            当创建一个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等等。

  • 相关阅读:
    【原】OpenEdx平台安装及出错解决方案
    【转】R语言中的并行计算——搭建R的集群
    【转】机器学习中的相似性度量
    A--Scikit-Learn入门
    A--最近邻分类器-KNN
    A--K-Means快速聚类
    A--无监督学习算法示例: DBSCAN(聚类)
    A-无监督学习算法示例:层次聚类
    A-岭回归的python'实现
    A--利用梯度下降求解逻辑回归的python实现
  • 原文地址:https://www.cnblogs.com/ASPNET2008/p/1768497.html
Copyright © 2011-2022 走看看