需求:网站为两个角色的客户提供独立站点服务,每个角色的站点风格布局都不一样,但内容一样。要求用户访问不同的角色对应的站点时,加载相应的view视图模版。
疑问:使用ViewEngine的话,好像是在global中就直接注册死了,而我更希望在我的controller中去控制,实现不同角色返回不同的view,那么如何实现?
期待高手解答!
1 public class CustomRazorViewEngine : RazorViewEngine 2 { 14 public override ViewEngineResult FindView(ControllerContext controllerContext, string viewName, string masterName, bool useCache) 15 { 16 if (controllerContext.RouteData.Values["id"].ToString() == "1") 17 { 18 this.ViewLocationFormats = new string[] { "~/Views/{1}/{0}.cshtml", "~/Views/{0}.cshtml" }; 19 } 20 else 21 { 22 this.ViewLocationFormats = new string[] { "~/Views/Common/{1}/{0}.cshtml", "~/Views/Common/{0}.cshtml" }; 23 } 24 return base.FindView(controllerContext, viewName, masterName, useCache); 25 } 26 }
1. 继承默认的RazorViewEngine
2. 重写FindView方法
3. 关键地方是根据不同的参数,设置查找View的不同路径-> ViewLocationFormats
4. 注意在Global.asax中,注册CustomRazorViewEngine
ViewEngines.Engines.Insert(0, new CustomRazorViewEngine());
将自定义的ViewEngine通过Insert放在最前面,自定义的Engine会最先执行
ok,好方法哈,试试,多谢啦!
问题解决,谢谢,结贴!
@笑看山河: 我把CustomRazorViewEngine 写在Global.asax文件里面的,执行controllerContext.RouteData.Values["id"]的时候会报错误,错误信息:未将对象引用设置到对象的实例。请问怎么样弄啊
这样是根据条件来选择不同的view,View都是写死成固定的.cshtml文件的,我现在的需求是.cshtml文件的内容在数据库,如何动态的替换呢。我的view里只有一个div,根据不同的条件我会加载不同的内容到div里。然后再让razor去解析
Global.asax: ViewEngines.Engines.Clear(); ViewEngines.Engines.Add(new FormBuilderViewEngine()); public class FormBuilderViewEngine : RazorViewEngine { public FormBuilderViewEngine() { ViewLocationFormats = new[] { "~/Views/FormBuilder/{1}/{0}.cshtml" }; MasterLocationFormats = new[] { "~/Views/Shared/{0}.cshtml" }; PartialViewLocationFormats = new[] { "~/Views/Shared/{0}.cshtml", }; FileExtensions = new[] { "cshtml" }; } protected override IView CreatePartialView(ControllerContext controllerContext, string partialPath) { return new RazorView(controllerContext, partialPath, layoutPath: null, runViewStartPages: false, viewStartFileExtensions: FileExtensions, viewPageActivator: ViewPageActivator); } protected override IView CreateView(ControllerContext controllerContext, string viewPath, string masterPath) { string formId = (controllerContext.RouteData.Values["id"] ?? "").ToString(); if (!string.IsNullOrEmpty(formId) && controllerContext.RouteData.Values["controller"].ToString()=="Home" && controllerContext.RouteData.Values["action"].ToString() == "Index" ) { string[] names = formId.Split('_'); string functionName = "Home"; string pageName = "Index"; pageName = names[0]; if (names.Length > 1) { functionName = names[0]; pageName = names[1]; } viewPath = string.Format(ViewLocationFormats[0], pageName, functionName); } masterPath = string.Format(MasterLocationFormats[0], "_Layout"); var view = new RazorView(controllerContext, viewPath, layoutPath: masterPath, runViewStartPages: false, viewStartFileExtensions: FileExtensions, viewPageActivator: ViewPageActivator); return view; } } //上面我是根据id来使用不同的视图,你也可以根据条件使用不同的masterPath
3KO,感谢支持哈,测试下先!
按照你的方案处理了,但死活不行。也跟踪不到。代码如下,程序执行时设置断点根本进不到这个地方,帮看下,谢谢
protected override IView CreateView(ControllerContext controllerContext, string viewPath, string masterPath) { string controller = controllerContext.RouteData.Values["controller"].ToString(); if (controller.ToLower() == "site") { int id = (int)controllerContext.RouteData.Values["id"]; if (id == 1) { viewPath = "~/Views/StarBuilder/{1}/{0}.cshtml"; } else { viewPath = "~/Views/StarTeam/{1}/{0}.cshtml"; } } var view = new RazorView(controllerContext, viewPath, layoutPath: masterPath, runViewStartPages: true, viewStartFileExtensions: FileExtensions, viewPageActivator: ViewPageActivator); return view; }
@笑看山河:
有写ViewEngines.Engines.Clear()吗?没写会进默认的ViewEngine。
路由也要正确,先不加Clear(),能正确进到对应路由的action后再加上。
比如路由是:
"{controller }/{action}/{id}",
new { controller = "Home", action = "Index",id = UrlParameter.Optional}
那你也必须要有Views/StarBuilder/Home/Index.cshtml这个文件
@向往-SONG: 这些都有的,现在发现就是第一次能跟踪进来,只有就不行了,好像缓存了。另外,我的代码不知道写的是否正确,现在总提示找不到页面。
未找到视图“index”或其母版视图,或没有视图引擎支持搜索的位置。搜索了以下位置: ~/Views/Site/index.aspx
@笑看山河:
加一个/Views/Site/index.aspx,未改变viewPath前,它会去找这个视图。
@笑看山河: 我把CustomRazorViewEngine 写在Global.asax文件里面的,执行controllerContext.RouteData.Values["id"]的时候会报错误,错误信息:未将对象引用设置到对象的实例。请问怎么样弄啊
两种方法。如果只是风格样式不一样的话。分主题包就行了,路径不一样。
比如: Content/themes/style1 , Content/themes/style1
然后引用的时候不同的地方 就弄个变量。比如 (ViewBag.Theme) 。然后怎么做相信你也懂得。
建议最好弄个基类Controller。
如果连布局也不一样的话。 那就得分不同母版页咯。
用到这个重载方法 ViewResult View(string viewName, string masterName);
请问在Controller如何加载并return 指定的View?
方法一:return view("~/view/xxx/xxx.cshtml")
方法二:如果你需要规则化的指定,那么你可以参考“最佳答案”中的方法,我的就是用这种方式实现自定义模版的!
@笑看山河: 第一种是可以的,但第二种我试了下,但有问题?有单独实例的源码吗?
能指点一下吗?我的qq498669416,谢谢了