ASP.NET MVC:多模板支持

背景

准备写个博客练习一下WEB编程,有一个需求就是多模板支持,类似博客园的自定义模板一样,在ASP.NET MVC中如何处理这个需求呢?

需求

描述

允许自定义模板,比如:传统模板、Metro模板等

模板结构

ASP.NET MVC:多模板支持_第1张图片

实现思路1

重写模板引擎的默认搜索路径

 1         private void SetTemplate(string template)
 2         {
 3             var razorViewEngine = ViewEngines.Engines.First(x => x is RazorViewEngine) as RazorViewEngine;
 4 
 5             razorViewEngine.ViewLocationFormats = razorViewEngine.ViewLocationFormats.Select(x =>
 6             {
 7                 return x.Replace("~/Views", string.Format("~/Views/Front/Templates/{0}", template));
 8             }).ToArray();
 9             razorViewEngine.MasterLocationFormats = razorViewEngine.ViewLocationFormats.Select(x =>
10             {
11                 return x.Replace("~/Views", string.Format("~/Views/Front/Templates/{0}", template));
12             }).ToArray();
13             razorViewEngine.PartialViewLocationFormats = razorViewEngine.ViewLocationFormats.Select(x =>
14             {
15                 return x.Replace("~/Views", string.Format("~/Views/Front/Templates/{0}", template));
16             }).ToArray();
17         }

分析

这回导致全局的修改,或者应该增加一个搜索路径(这里就不测试了),因为有些视图是不用多模板支持的,因此这种方式不太适合。

实现思路2

为VIewResult指定路径

1         public ActionResult Index(string template = "Classic")
2         {
3             return this.View("~/Views/Front/Templates/" + template + "/Home/Index.cshtml");
4         }

分析

这种非常灵活,符合需要,但是代码看起来不够漂亮,好在MVC非常灵活,可以用Filter机制帮我们处理。

实现思路3

Filter机制

 1 using System;
 2 using System.Collections.Generic;
 3 using System.Linq;
 4 using System.Text;
 5 using System.Threading.Tasks;
 6 using System.Web.Mvc;
 7 using System.Threading;
 8 
 9 using Happy.Bootstrap;
10 
11 namespace Happy.Web.Mvc.Template
12 {
13     /// <summary>
14     /// 模板相关。
15     /// </summary>
16     public sealed class TemplateRelevantAttribute : ActionFilterAttribute
17     {
18         /// <inheritdoc />
19         public override void OnResultExecuting(ResultExecutingContext filterContext)
20         {
21             var viewResult = filterContext.Result as ViewResult;
22             if (viewResult != null)
23             {
24                 var currentUserTemplate = this.GetCurrentUserTemplate();
25                 var template = string.IsNullOrEmpty(currentUserTemplate) ? TemplateService.DefaultTemplateName : currentUserTemplate;
26                 var controller = filterContext.RequestContext.RouteData.Values["Controller"].ToString();
27                 var action = filterContext.RequestContext.RouteData.Values["Action"].ToString();
28 
29                 if (string.IsNullOrWhiteSpace(viewResult.ViewName))
30                 {
31                     viewResult.ViewName = string.Format(
32                         "~/Views/{0}/{1}/{2}/{3}.{4}",
33                         TemplateService.TemplateDirectoryName,
34                         template,
35                         controller,
36                         action,
37                         TemplateService.TemplateFileExtension);
38 
39                     return;
40                 }
41             }
42 
43             base.OnResultExecuting(filterContext);
44         }
45 
46         private string GetCurrentUserTemplate()
47         {
48             return TemplateService.Current.GetTemplate(Thread.CurrentPrincipal.Identity.Name);
49         }
50     }
51 }
 1 using System;
 2 using System.Collections.Generic;
 3 using System.Linq;
 4 using System.Text;
 5 using System.Threading.Tasks;
 6 
 7 using Happy.Infrastructure.ExtentionMethods;
 8 
 9 namespace Happy.Web.Mvc.Template
10 {
11     /// <summary>
12     /// 获取或访问<see cref="ITemplateService"/>实例的唯一入口。
13     /// </summary>
14     public static class TemplateService
15     {
16         private static readonly EmptyTemplateService _DefaultCommandService = new EmptyTemplateService();
17 
18         private static TemplateServiceProvider currentProvider = () => _DefaultCommandService;
19 
20         static TemplateService()
21         {
22             TemplateDirectoryName = "Templates";
23             DefaultTemplateName = "Default";
24             TemplateFileExtension = "cshtml";
25         }
26 
27         /// <summary>
28         /// 获取当前应用程序正在使用的模板服务。
29         /// </summary>
30         public static ITemplateService Current
31         {
32             get { return currentProvider(); }
33         }
34 
35         /// <summary>
36         /// 设置当前应用程序正在使用的模板服务提供者。
37         /// </summary>
38         public static void SetProvider(TemplateServiceProvider provider)
39         {
40             provider.MustNotNull("provider");
41 
42             currentProvider = provider;
43         }
44 
45         /// <summary>
46         /// 模板路径。
47         /// </summary>
48         public static string TemplateDirectoryName { get; set; }
49 
50         /// <summary>
51         /// 默认模板。
52         /// </summary>
53         public static string DefaultTemplateName { get; set; }
54 
55         /// <summary>
56         /// 默认模板。
57         /// </summary>
58         public static string TemplateFileExtension { get; set; }
59     }
60 }

分析

采用FIlter这种AOP机制,让调用代码看起来非常漂亮,最终就采用这种方式。

测试

代码

 1 using System;
 2 using System.Collections.Generic;
 3 using System.Linq;
 4 using System.Web;
 5 using System.Web.Mvc;
 6 
 7 using Happy.Web.Mvc.Template;
 8 
 9 namespace Happy.MvcExample.Controllers
10 {
11     [TemplateRelevant]
12     public class HomeController : Controller
13     {
14         //
15         // GET: /Home/
16 
17         public ActionResult Index()
18         {
19             return View();
20         }
21 
22         //
23         // GET: /Home/
24 
25         public ActionResult ChangeTemplate(string template)
26         {
27             TemplateService.DefaultTemplateName = template ?? TemplateService.DefaultTemplateName;
28 
29             return this.RedirectToAction("Index");
30         }
31     }
32 }

运行效果

 ASP.NET MVC:多模板支持_第2张图片

ASP.NET MVC:多模板支持_第3张图片

备注

ViewResult的ViewName可以是绝对路径,也可以是相对路径,默认的相对路径是相对于Controller目录。

最后补上代码:http://yunpan.cn/QnYjcK3hTB3qk。


你可能感兴趣的:(ASP.NET MVC:多模板支持)