ASP.NET Core 自定义视图路径及主题切换

原文地址:https://www.cnblogs.com/ElderJames/p/Customized-View-Path-And-Theme-Switching-In-AspNetCore.html

0|1背景

切换主题,是博客、CMS等系统的必备功能,一般来说,有三种切换主题的需求。

  1. 在管理后台上传主题包,并选择主题
  2. 前端自动按照频道、栏目等切换模版
  3. 用户在前端切换主题,并记录用户的选择

这三种需求,其实核心原理都是一样,就是制定一套主题的目录,切换主题等于切换目录名。主题内的页面模版都是按照一定的规则存放的。

下面是两个主题包的目录示例:

  .
  ├── theme0
  |   ├── Assets
  |   |   ├── js
  |   |   ├── css
  |   |   └── img
  |   ├── Home
  |   |   ├── Index.cshtml
  |   |   └── About.cshtml
  |   ├── Article
  |   |   ├── Index.cshtml
  |   |   └── Detail.cshtml
  |   └── Shared
  |       ├── Page.cshtml
  |       └──  _Layout.cshtml
  └── theme1
      ├── Assets
      |   ├── js
      |   ├── css
      |   └── img
      ├── Home
      |   ├── Index.cshtml
      |   └── About.cshtml
      ├── Article
      |   ├── Index.cshtml
      |   └── Detail.cshtml
      └── Shared
          ├── Page.cshtml
          └──  _Layout.cshtml

大家一定注意到了,上面每个主题包里都按照传统ASP.NET MVC的约定来划分目录:控制器名为文件夹,操作名为视图文件。其实这里只是方便起见,按照接下来介绍的方法,是可以完全地自定义这个目录划分的。

0|1原理

当ASP.NET MVC从控制器处理完数据返回视图的时候,ASP.NET MVC会按照默认的多个路径去查找文件,如果文件存在,则使用该文件渲染,如果不存在,则寻找下一个路径,比如默认的路径会有/{Area}/{Controller}/{Action}.cshtml/{Controller}/{Action}.cshtml/Shared/{Action}.cshtml等等我们熟悉的约定,那么在查找视图文件时,会安装从左往右的路径去查询,如果都查询不出来,是会报错的。

而如果要做到切换主题文件夹名来切换主题,我们就需要在默认规则上加主题的目录占位符,使的查询时用主题文件夹名来替换占位符,例如/{theme}/{Controller}/{Action}.cshtml/{theme}/Shared/{Action}.cshtml等等,这样,当查询视图文件时,就能匹配到对应的主题文件夹,并且找到相应的视图了。

总结起来,切换主题功能有两个重点需要我们去实现:

  1. 在原有规则中加入占位符
  2. 每次请求都获取当前的主题名,并改变视图查询路径

0|1实现

最简单的实现,在操作(action)的最后return View(viewPath)时传入视图路径,直接就能指向对应视图,但是,这样做一点都不灵活,而且每个操作都要传路径也是不够简洁,不容易维护,所以我们需要更好的解决方案。

ASP.NET MVC 实现

在ASP.NET MVC时代,我们可通过继承RazorViewEngine类,在基类的ViewLocationFormatsPartialViewLocationFormats两个属性中加入有主题目录名占位符的路径,并重写CreateViewCreatePartialViewFileExists三个方法,使每次请求都能获取最新的主题名,如下面的例子中从路由数据对象中获取主题名:

public class TemplateViewEngine : RazorViewEngine
{
    public TemplateViewEngine() : base()
    {
        ViewLocationFormats = new[] {
            "~/Views/{1}%1/{0}.cshtml",
            "~/Views/{1}/{0}.cshtml",//默认路径
            "~/Views/Shared%1/{0}.cshtml",
            "~/Views/Shared/{0}.cshtml",
        };

        PartialViewLocationFormats = new[] {
            "~/Views/{1}%1/{0}.cshtml",
            "~/Views/{1}/{0}.cshtml",//默认路径
            "~/Views/Shared%1/{0}.cshtml",
            "~/Views/Shared/{0}.cshtml",
        };
    }

    protected override IView CreatePartialView(ControllerContext controllerContext, string partialPath)
    {
        var template = controllerContext.RouteData.Values["template"] != null ? "/" + controllerContext.RouteData.Values["template"].ToString() : "";

        return base.CreatePartialView(controllerContext, partialPath.Replace("%1", template));
    }

    protected override IView CreateView(ControllerContext controllerContext, string viewPath, string masterPath)
    {
        var template = controllerContext.RouteData.Values["template"] != null ? "/" + controllerContext.RouteData.Values["template"].ToString() : "";

        return base.CreateView(controllerContext, viewPath.Replace("%1", template), masterPath);
    }

    protected override bool FileExists(ControllerContext controllerContext, string virtualPath)
    {
        var template = controllerContext.RouteData.Values["template"] != null ? "/" + controllerContext.RouteData.Values["template"].ToString() : "";

        return base.FileExists(controllerContext, virtualPath.Replace("%1", template));
    }
}

事实上,如果是需要实现不同用户不同主题的功能,主题信息可以存储在Session中,还能从controllerContext实例获取Session中存储的主题名。

那么,在ASP.NET Core中如何实现呢?

ASP.NET Core 实现

ASP.NET Core 相比ASP.NET MVC框架,虽然使用上为了开发者平滑过渡,很多约定都相同,但是架构本身是做了翻天覆地的重构和优化,得益于一脉相承的MSDI框架,ASP.NET Core框架实现了组件化,很多功能都通过IoC的方式修改或扩展。例如本文介绍的主题情况功能,就是实现IViewLocationExpander接口来达到扩展配置的目的,而且还比ASP.NET MVC的更加简洁:

public class TemplateViewLocationExpander : IViewLocationExpander
{
    public IEnumerable<string> ExpandViewLocations(ViewLocationExpanderContext context, IEnumerable<string> viewLocations)
    {
        var template = context.Values["template"] ?? "Default";

        string[] locations = { "/Views/" + template + "/{1}/{0}.cshtml", "/Views/" + template + "/{0}.cshtml", "/Views/" + template + "/Shared/{0}.cshtml" };
        return locations.Union(viewLocations);
    }

    public void PopulateValues(ViewLocationExpanderContext context)
    {
        context.Values["template"] = context.ActionContext.RouteData.Values["Template"]?.ToString() ?? "Default";
    }
}

这个接口里面,PopulateValues方法主要用来获取实时的主题信息,context.ActionContext中除了RouteData可获得实时数据,还有HttpContext实例可获得用户信息,甚至能利用RequestServices实例注入服务。而只有在PopulateValues中修改了contextExpandViewLocations方法才会从context中获得主题信息,从而达到修改视图查找路径的目的。

当我们实现了IViewLocationExpander接口后,还需要在Startup类的services.AddMvc();下修改MVC的配置:

services.AddMvc();
//配置模版视图路径
services.Configure<RazorViewEngineOptions>(options =>
{
    options.ViewLocationExpanders.Add(new TemplateViewLocationExpander());
});

PS:这种修改MVC内部配置的方式很有趣,以后有空会研究一番。

0|1总结

本文主要介绍了在ASP.NET Core中利用修改视图查询路径实现主题切换的功能,虽然只介绍了核心部分,但是其它部分如管理主题、前端切换等功能,都是很容易实现的,以后我会在我的框架样例中实现,敬请大家关注啦

原文地址:https://www.cnblogs.com/fei686868/p/12298891.html

时间: 2024-08-01 00:07:23

ASP.NET Core 自定义视图路径及主题切换的相关文章

Asp.Net Core Web相对路径、绝对路径整理

一.相对路径 1.关于Asp.Net Core中的相对路径主要包括两个部分:一.Web根目录,即当前网站的目录为基础:二.内容目录wwwroot文件夹,对于静态文件都放在这个目录. 2.获取控制器,Action的路径 对于控制器.视图的链接生成,主要通过视图上下文.控制器上下文的Url对象 Url对象实现了IUrlHelper接口,主要功能是获取网站的相对目录,也可以将'~'发号开头的转换成相对目录. // // 摘要: // Defines the contract for the helpe

ASP.NET Core 入门教程 5、ASP.NET Core MVC 视图传值入门

原文:ASP.NET Core 入门教程 5.ASP.NET Core MVC 视图传值入门 一.前言 1.本教程主要内容 ASP.NET Core MVC 视图引擎(Razor)简介 ASP.NET Core MVC 视图(Razor)ViewData使用示例 ASP.NET Core MVC 视图(Razor)ViewBag使用示例 ASP.NET Core NVC 视图(Razor)强类型传值(ViewModel)页示例 2.本教程环境信息 软件/环境 说明 操作系统 Windows 10

asp.net core 自定义认证方式--请求头认证

原文:asp.net core 自定义认证方式--请求头认证 asp.net core 自定义认证方式--请求头认证 Intro 最近开始真正的实践了一些网关的东西,最近写几篇文章分享一下我的实践以及遇到的问题. 本文主要介绍网关后面的服务如何进行认证. 解决思路 网关可以做一部分的认证和授权,服务内部有时候也会需要用户的信息,这时该怎么办呢,我们使用的是 JWT 认证,有一个 identity server去颁发,验证 token,一种简单方式可以把 token 直接往后传,传递给后面的具体某

asp.net core 自定义异常处理中间件

原文:asp.net core 自定义异常处理中间件 asp.net core 自定义异常处理中间件 Intro 在 asp.net core 中全局异常处理,有时候可能不能满足我们的需要,可能就需要自己自定义一个中间件处理了,最近遇到一个问题,有一些异常,不希望记录错误日志,目前主要是用户请求取消导致的 TaskCanceledException 和 OperationCanceledException 异常.因为我的 ERROR 级别的日志会输出到 Sentry,sentry的异常会自动发邮

ASP.NET Core MVC 视图

ASP.NET Core MVC中视图的知识和ASP.NET MVC有很多相似之处,学习难度较低.以下内容主要体现了编程中模块化的思想,模块化才应是我们关注的重点. Layout 布局用于提供各个页面所需的公共部分,如:菜单.页头.页尾等.在ASP.NET Core中默认的布局文件是位于/Views/Shared文件夹下的_Layout.cshtml文件: 我们通常在_Layout.cshtml中引入公共资源,如: <link href="~/css/reset.css" rel

[Asp.net core]自定义中间件

我们知道在asp.net中每次请求,都要经过请求管道,依次触发管道中的一系列事件.那么我们可以这么理解,中间件是请求管道中的一个组件,可以用来拦截请求,以方便我们进行请求和响应处理,中间件可以定义多个,每一个中间件都可以对管道中的请求进行拦截,它可以决定是否将请求转移给下一个中间件. 中间件如何工作? 默认情况下,中间件的执行顺序根据Startup.cs文件中,在public void Configure(IApplicationBuilder app){} 方法中注册的先后顺序执行.大概有3种

ASP.NET Core Razor 视图组件

视图组件简介 在新的ASP.NET Core MVC中,视图组件类似于局部视图,但它们更强大.视图组件不使用模型绑定,仅依赖于您在调用时提供的数据. 视图组件特性: 呈现页面响应的某一部分而不是整个响应 包括在控制器和视图之间发现的关注分离和可测试性优势 可以具有参数和业务逻辑 通常在页面布局中调用 视图组件是在任何地方可重用的呈现逻辑,对于局部视图来说相对复杂,例如: 动态导航菜单 标签云(查询数据库) 登录面板 购物车 最近发表的文章 典型博客上的侧边栏内容 将在每个页面上呈现的登录面板,并

iOS7新特性 ViewController转场切换(三) 自定义视图控制器容器的切换---非交互式

@继续前面的内容,这一章,主要介绍自定义ViewController容器上视图VC的切换.先来看看系统给我们提供的容器控制器 UINavigationController和UITabBarController 都有一个NSArray类型的属性viewControllers,很明显,存储的就是需要切换的视图VC.同理,我们定义一个ContainerViewController,是UIViewController的直接子类,用来作为容器依托,额,其他属性定义详见代码吧,这里不多说了.(PS:原先我进

asp.net core 自定义中间件和service

首先新建项目看下main方法: public static void Main(string[] args) { var host = new WebHostBuilder() .UseKestrel() .UseContentRoot(Directory.GetCurrentDirectory()) .UseIISIntegration() .UseStartup<Startup>() .Build(); host.Run(); } main方法 其中,UseStartup<Start