博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

Asp.Net MVC:基于cookie的用户自选视图引擎实现

Posted on 2009-02-11 09:44  linFen  阅读(1260)  评论(3编辑  收藏  举报
作者:
leven
日期:
2008-11-27 17:38:47

在我以前的文章中详细介绍了目前mvc框架中的视图引擎管理,这个视图引擎可以方便的实现系统多视图引擎的管理,让系统可以轻松更好视图引擎,但是,在一些应用,比如bbs,多用户blog中,往往需要提供用户自选skin的功能,比如bbs中某个用户通过菜单可以随意更换自己的skin设置,而mvc框架的默认视图管理器对这个要求就无法做到了,而本文则是使用viewengine规则来实现一个用户自选视图引擎的功能.

在本系统中,用户选择的skin信息将保存在cookie中,这意味着可以让用户控制这个选择保存的时间.

首先,这个系统仍然是基于ViewEngine,我们在以前的文章中可以看到,mvc框架用一个AutoViewEngine来管理存在的所有ViewEngine,那么我们也可以考虑用一个SelectViewEngine来管理一系列我们特定的可选择ViewEngine.下面先看看这个核心部分的类:

 


 

从图中可以看到,这儿我们提供了一个新的接口ISelectViewEngine,它在普通的ViewEngine上添加了一个新的Name属性,该属性标示着唯一的视图引擎名称,然后我们对WebFormViewEngine进行封装,并实现ISelectViewEngine接口:


        public SelectWebFormViewEngine(string name) {
            Name 
= name;
            MasterLocationFormats 
= new[] {
                
"~/skins/" + Name + "/{1}/{0}.master",
                
"~/skins/" + Name + "/shared/{0}.master"
            }
;
            ViewLocationFormats 
= new[] {
                
"~/skins/" + Name + "/{1}/{0}.aspx",
                
"~/skins/" + Name + "/{1}/{0}.ascx",
                
"~/skins/" + Name + "/shared/{0}.aspx",
                
"~/skins/" + Name + "/shared/{0}.ascx"
            }
;
            PartialViewLocationFormats 
= ViewLocationFormats;
        }

 

从上面的代码可以看到,默认的不同skin分别放在~/skins目录下,不同的SelectWebFormViewEngine对应不同的子目录.

然后我们实现一个基本的SelectViewEngine来管理所有的可选择ViewEngine,关键代码如下:

 


        /// <summary>
        
/// 可选择视图引擎容器,通过Add来增加系统中可用的视图引擎
         
/// </summary>
        public IDictionary<string, ISelectViewEngine> Engines {
            
get { return _engines; }
        }

        
/// <summary>
        
/// 通过Cookie来选择用户所选择的ViewEngine
        
/// </summary>
        
/// <param name="context"></param>
        
/// <returns></returns>
        private IViewEngine Find(ControllerContext context) {
            
string skin = context.HttpContext.GetSelectSkinName();
            
if (!_engines.ContainsKey(skin)) {
                
throw new Exception(String.Format("模板{0}未找到.", skin));
            }
            
return _engines[skin];
        }

        
#region IViewEngine Members

        
/// <summary>
        
/// 调用通过Find方法找到的ViewEngine的FindPartialView方法
        
/// </summary>
        
/// <param name="controllerContext"></param>
        
/// <param name="partialViewName"></param>
        
/// <returns></returns>
        public ViewEngineResult FindPartialView(ControllerContext controllerContext, string partialViewName) {
            
return Find(controllerContext).FindPartialView(controllerContext, partialViewName);
        }

        
/// <summary>
        
/// 调用通过Find方法找到的ViewEngine的FindView方法
        
/// </summary>
        
/// <param name="controllerContext"></param>
        
/// <param name="viewName"></param>
        
/// <param name="masterName"></param>
        
/// <returns></returns>
        public ViewEngineResult FindView(ControllerContext controllerContext, string viewName, string masterName) {
            
return Find(controllerContext).FindView(controllerContext, viewName, masterName);
        }


 

那么我们如何确定用户选择了哪个ViewEngine呢?在本例中是采用了cookie的方式,在ViewEngineExtension中,我们封装了几个扩展方法用来获取cookie和设置cookie:

 


    public static class ViewEngineExtension {
        
private static readonly string _cookiename = "select_skin_name";
        
private static readonly string _defaultskin = "default";

        
public static string GetSelectSkinName(this HttpContextBase context) {
            HttpCookie cookie 
= context.Request.Cookies[_cookiename];
            
if (cookie != null{
                
return cookie.Value;
            }

            
return _defaultskin;
        }


        
public static void SelectSkin(this HttpContextBase context, ISelectViewEngine select) {
            HttpCookie cookie 
= new HttpCookie(_cookiename);
            cookie.Value 
= select.Name;
            
if (context.Response.Cookies.AllKeys.Contains(_cookiename))
                context.Response.Cookies.Remove(_cookiename);
            context.Response.Cookies.Add(cookie);
        }


        
public static void SelectSkin(this HttpContextBase context, string name) {
            HttpCookie cookie 
= new HttpCookie(_cookiename);
            cookie.Value 
= name;
            
if (context.Response.Cookies.AllKeys.Contains(_cookiename))
                context.Response.Cookies.Remove(_cookiename);
            context.Response.Cookies.Add(cookie);
        }


        
public static void ResetSkin(this HttpContextBase context) {
            HttpCookie cookie 
= new HttpCookie(_cookiename);
            cookie.Value 
= _defaultskin;
            
if (context.Response.Cookies.AllKeys.Contains(_cookiename))
                context.Response.Cookies.Remove(_cookiename);
            context.Response.Cookies.Add(cookie);
        }

    }

 

总结下VIewEngine的工作流程:

Controller -> ViewEngines.Default.FindView -> SelectViewEngine.FindView -> SelectWebFormViewEngine.FindView

也就是说,系统调用FindView或者FindPartialView方法最终还是会调用到我们在系统中已经注册过的ISelectViewEngine的FindView或者FindPartialView方法.最后展示下如何注册这些SelectViewEngine:

 


        protected void Application_Start(object sender, EventArgs e) {
        
//注册路由
             InitRouting(RouteTable.Routes); 
            ViewEngines.Engines.Clear();
            SelectViewEngine engine 
= new SelectViewEngine();
            SelectWebFormViewEngine defaultEngine 
= new SelectWebFormViewEngine();
            engine.Engines.Add(defaultEngine.Name, defaultEngine);
            SelectWebFormViewEngine selectEngine 
= new SelectWebFormViewEngine("select");
            engine.Engines.Add(selectEngine.Name, selectEngine);
            ViewEngines.Engines.Add(engine); 
        }