代码拉取完成,页面将自动刷新
<!DOCTYPE html>
<html style="display: none;" lang="zh">
<head>
<meta charset="utf-8">
<!--
© Material Theme
https://github.com/viosey/hexo-theme-material
Version: 1.5.0 -->
<script>
window.materialVersion = "1.5.0"
// Delete localstorage with these tags
window.oldVersion = [
'codestartv1',
'1.3.4',
'1.4.0',
'1.4.0b1'
]
</script>
<!-- dns prefetch -->
<meta http-equiv="x-dns-prefetch-control" content="on">
<link rel="dns-prefetch" href="https://busuanzi.ibruce.info"/>
<!-- Title -->
<title>
ASP.NET Core 中的SEO优化(4):自定义视图路径及主题切换 |
ElderJames' Blog
</title>
<!-- Meta & Info -->
<meta http-equiv="X-UA-Compatible" content="IE=Edge,chrome=1">
<meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=no">
<meta name="format-detection" content="telephone=no"/>
<meta name="theme-color" content="#0097A7">
<meta name="author" content="James Yeung">
<meta name="description" itemprop="description" content="学习、札记、分享">
<meta name="keywords" content="ElderJames' Blog,.NET Core,ASP.NET Core">
<!-- Import lsloader -->
<script>(function(){window.lsloader={jsRunSequence:[],jsnamemap:{},cssnamemap:{}};lsloader.removeLS=function(key){try{localStorage.removeItem(key)}catch(e){}};lsloader.setLS=function(key,val){try{localStorage.setItem(key,val)}catch(e){}};lsloader.getLS=function(key){var val="";try{val=localStorage.getItem(key)}catch(e){val=""}return val};versionString="/*"+(window.materialVersion||"unknownVersion")+"*/";lsloader.clean=function(){try{var keys=[];for(var i=0;i<localStorage.length;i++){keys.push(localStorage.key(i))}keys.forEach(function(key){var data=lsloader.getLS(key);if(window.oldVersion){var remove=window.oldVersion.reduce(function(p,c){return p||data.indexOf("/*"+c+"*/")!==-1},false);if(remove){lsloader.removeLS(key)}}})}catch(e){}};lsloader.clean();lsloader.load=function(jsname,jspath,cssonload,isJs){if(typeof cssonload==="boolean"){isJs=cssonload;cssonload=undefined}isJs=isJs||false;cssonload=cssonload||function(){};var code;code=this.getLS(jsname);if(code&&code.indexOf(versionString)===-1){this.removeLS(jsname);this.requestResource(jsname,jspath,cssonload,isJs);return}if(code){var versionNumber=code.split(versionString)[0];if(versionNumber!=jspath){console.log("reload:"+jspath);this.removeLS(jsname);this.requestResource(jsname,jspath,cssonload,isJs);return}code=code.split(versionString)[1];if(isJs){this.jsRunSequence.push({name:jsname,code:code});this.runjs(jspath,jsname,code)}else{document.getElementById(jsname).appendChild(document.createTextNode(code));cssonload()}}else{this.requestResource(jsname,jspath,cssonload,isJs)}};lsloader.requestResource=function(name,path,cssonload,isJs){var that=this;if(isJs){this.iojs(path,name,function(path,name,code){that.setLS(name,path+versionString+code);that.runjs(path,name,code)})}else{this.iocss(path,name,function(code){document.getElementById(name).appendChild(document.createTextNode(code));that.setLS(name,path+versionString+code)},cssonload)}};lsloader.iojs=function(path,jsname,callback){var that=this;that.jsRunSequence.push({name:jsname,code:""});try{var xhr=new XMLHttpRequest;xhr.open("get",path,true);xhr.onreadystatechange=function(){if(xhr.readyState==4){if(xhr.status>=200&&xhr.status<300||xhr.status==304){if(xhr.response!=""){callback(path,jsname,xhr.response);return}}that.jsfallback(path,jsname)}};xhr.send(null)}catch(e){that.jsfallback(path,jsname)}};lsloader.iocss=function(path,jsname,callback,cssonload){var that=this;try{var xhr=new XMLHttpRequest;xhr.open("get",path,true);xhr.onreadystatechange=function(){if(xhr.readyState==4){if(xhr.status>=200&&xhr.status<300||xhr.status==304){if(xhr.response!=""){callback(xhr.response);cssonload();return}}that.cssfallback(path,jsname,cssonload)}};xhr.send(null)}catch(e){that.cssfallback(path,jsname,cssonload)}};lsloader.iofonts=function(path,jsname,callback,cssonload){var that=this;try{var xhr=new XMLHttpRequest;xhr.open("get",path,true);xhr.onreadystatechange=function(){if(xhr.readyState==4){if(xhr.status>=200&&xhr.status<300||xhr.status==304){if(xhr.response!=""){callback(xhr.response);cssonload();return}}that.cssfallback(path,jsname,cssonload)}};xhr.send(null)}catch(e){that.cssfallback(path,jsname,cssonload)}};lsloader.runjs=function(path,name,code){if(!!name&&!!code){for(var k in this.jsRunSequence){if(this.jsRunSequence[k].name==name){this.jsRunSequence[k].code=code}}}if(!!this.jsRunSequence[0]&&!!this.jsRunSequence[0].code&&this.jsRunSequence[0].status!="failed"){var script=document.createElement("script");script.appendChild(document.createTextNode(this.jsRunSequence[0].code));script.type="text/javascript";document.getElementsByTagName("head")[0].appendChild(script);this.jsRunSequence.shift();if(this.jsRunSequence.length>0){this.runjs()}}else if(!!this.jsRunSequence[0]&&this.jsRunSequence[0].status=="failed"){var that=this;var script=document.createElement("script");script.src=this.jsRunSequence[0].path;script.type="text/javascript";this.jsRunSequence[0].status="loading";script.onload=function(){that.jsRunSequence.shift();if(that.jsRunSequence.length>0){that.runjs()}};document.body.appendChild(script)}};lsloader.tagLoad=function(path,name){this.jsRunSequence.push({name:name,code:"",path:path,status:"failed"});this.runjs()};lsloader.jsfallback=function(path,name){if(!!this.jsnamemap[name]){return}else{this.jsnamemap[name]=name}for(var k in this.jsRunSequence){if(this.jsRunSequence[k].name==name){this.jsRunSequence[k].code="";this.jsRunSequence[k].status="failed";this.jsRunSequence[k].path=path}}this.runjs()};lsloader.cssfallback=function(path,name,cssonload){if(!!this.cssnamemap[name]){return}else{this.cssnamemap[name]=1}var link=document.createElement("link");link.type="text/css";link.href=path;link.rel="stylesheet";link.onload=link.onerror=cssonload;var root=document.getElementsByTagName("script")[0];root.parentNode.insertBefore(link,root)};lsloader.runInlineScript=function(scriptId,codeId){var code=document.getElementById(codeId).innerText;this.jsRunSequence.push({name:scriptId,code:code});this.runjs()};lsloader.loadCombo=function(jslist){var updateList="";var requestingModules={};for(var k in jslist){var LS=this.getLS(jslist[k].name);if(!!LS){var version=LS.split(versionString)[0];var code=LS.split(versionString)[1]}else{var version=""}if(version==jslist[k].path){this.jsRunSequence.push({name:jslist[k].name,code:code,path:jslist[k].path})}else{this.jsRunSequence.push({name:jslist[k].name,code:null,path:jslist[k].path,status:"comboloading"});requestingModules[jslist[k].name]=true;updateList+=(updateList==""?"":";")+jslist[k].path}}var that=this;if(!!updateList){var xhr=new XMLHttpRequest;xhr.open("get",combo+updateList,true);xhr.onreadystatechange=function(){if(xhr.readyState==4){if(xhr.status>=200&&xhr.status<300||xhr.status==304){if(xhr.response!=""){that.runCombo(xhr.response,requestingModules);return}}else{for(var i in that.jsRunSequence){if(requestingModules[that.jsRunSequence[i].name]){that.jsRunSequence[i].status="failed"}}that.runjs()}}};xhr.send(null)}this.runjs()};lsloader.runCombo=function(comboCode,requestingModules){comboCode=comboCode.split("/*combojs*/");comboCode.shift();for(var k in this.jsRunSequence){if(!!requestingModules[this.jsRunSequence[k].name]&&!!comboCode[0]){this.jsRunSequence[k].status="comboJS";this.jsRunSequence[k].code=comboCode[0];this.setLS(this.jsRunSequence[k].name,this.jsRunSequence[k].path+versionString+comboCode[0]);comboCode.shift()}}this.runjs()}})();</script>
<!-- Import queue -->
<script>function Queue(){this.dataStore=[];this.offer=b;this.poll=d;this.execNext=a;this.debug=false;this.startDebug=c;function b(e){if(this.debug){console.log("Offered a Queued Function.")}if(typeof e==="function"){this.dataStore.push(e)}else{console.log("You must offer a function.")}}function d(){if(this.debug){console.log("Polled a Queued Function.")}return this.dataStore.shift()}function a(){var e=this.poll();if(e!==undefined){if(this.debug){console.log("Run a Queued Function.")}e()}}function c(){this.debug=true}}var queue=new Queue();</script>
<!-- Favicons -->
<link rel="icon shortcut" type="image/ico" href="/img/favicon.png">
<link rel="icon" sizes="192x192" href="/img/favicon.png">
<link rel="apple-touch-icon" href="/img/favicon.png">
<!--iOS -->
<meta name="apple-mobile-web-app-title" content="Title">
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-status-bar-style" content="black">
<meta name="HandheldFriendly" content="True">
<meta name="MobileOptimized" content="480">
<!-- Add to homescreen for Chrome on Android -->
<meta name="mobile-web-app-capable" content="yes">
<!-- Add to homescreen for Safari on iOS -->
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-status-bar-style" content="black">
<meta name="apple-mobile-web-app-title" content="ElderJames' Blog">
<!-- Site Verification -->
<!-- RSS -->
<link rel=alternate type="application/rss+xml" href="rss.xml">
<!--[if lte IE 9]>
<link rel="stylesheet" href="/css/ie-blocker.css">
<script src="/js/ie-blocker.zhCN.js"></script>
<![endif]-->
<!-- Import CSS -->
<style id="material_css"></style><script>if(typeof window.lsLoadCSSMaxNums === "undefined")window.lsLoadCSSMaxNums = 0;window.lsLoadCSSMaxNums++;lsloader.load("material_css","/css/material.min.css?976y5g1pRWbrdcUItimr0g==",function(){if(typeof window.lsLoadCSSNums === "undefined")window.lsLoadCSSNums = 0;window.lsLoadCSSNums++;if(window.lsLoadCSSNums == window.lsLoadCSSMaxNums)document.documentElement.style.display="";}, false)</script>
<style id="style_css"></style><script>if(typeof window.lsLoadCSSMaxNums === "undefined")window.lsLoadCSSMaxNums = 0;window.lsLoadCSSMaxNums++;lsloader.load("style_css","/css/style.min.css?J9YGUOg9VFzvsUAJ8qxFsQ==",function(){if(typeof window.lsLoadCSSNums === "undefined")window.lsLoadCSSNums = 0;window.lsLoadCSSNums++;if(window.lsLoadCSSNums == window.lsLoadCSSMaxNums)document.documentElement.style.display="";}, false)</script>
<style id="prettify_css"></style><script>if(typeof window.lsLoadCSSMaxNums === "undefined")window.lsLoadCSSMaxNums = 0;window.lsLoadCSSMaxNums++;lsloader.load("prettify_css","/css/prettify.min.css?UDVrysExI1W3AEkuJF/bUQ==",function(){if(typeof window.lsLoadCSSNums === "undefined")window.lsLoadCSSNums = 0;window.lsLoadCSSNums++;if(window.lsLoadCSSNums == window.lsLoadCSSMaxNums)document.documentElement.style.display="";}, false)</script>
<style id="prettify_theme"></style><script>if(typeof window.lsLoadCSSMaxNums === "undefined")window.lsLoadCSSMaxNums = 0;window.lsLoadCSSMaxNums++;lsloader.load("prettify_theme","/css/prettify/github-v2.min.css?AfzKxt++K+/lhZBlSjnxwg==",function(){if(typeof window.lsLoadCSSNums === "undefined")window.lsLoadCSSNums = 0;window.lsLoadCSSNums++;if(window.lsLoadCSSNums == window.lsLoadCSSMaxNums)document.documentElement.style.display="";}, false)</script>
<!-- Config CSS -->
<!-- Other Styles -->
<style>
body, html {
font-family: Roboto, "Helvetica Neue", Helvetica, "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", "微软雅黑", Arial, sans-serif;
overflow-x: hidden !important;
}
code {
font-family: Consolas, Monaco, 'Andale Mono', 'Ubuntu Mono', monospace;
}
a {
color: #00838F;
}
.mdl-card__media,
#search-label,
#search-form-label:after,
#scheme-Paradox .hot_tags-count,
#scheme-Paradox .sidebar_archives-count,
#scheme-Paradox .sidebar-colored .sidebar-header,
#scheme-Paradox .sidebar-colored .sidebar-badge{
background-color: #0097A7 !important;
}
/* Sidebar User Drop Down Menu Text Color */
#scheme-Paradox .sidebar-colored .sidebar-nav>.dropdown>.dropdown-menu>li>a:hover,
#scheme-Paradox .sidebar-colored .sidebar-nav>.dropdown>.dropdown-menu>li>a:focus {
color: #0097A7 !important;
}
#post_entry-right-info,
.sidebar-colored .sidebar-nav li:hover > a,
.sidebar-colored .sidebar-nav li:hover > a i,
.sidebar-colored .sidebar-nav li > a:hover,
.sidebar-colored .sidebar-nav li > a:hover i,
.sidebar-colored .sidebar-nav li > a:focus i,
.sidebar-colored .sidebar-nav > .open > a,
.sidebar-colored .sidebar-nav > .open > a:hover,
.sidebar-colored .sidebar-nav > .open > a:focus,
#ds-reset #ds-ctx .ds-ctx-entry .ds-ctx-head a {
color: #0097A7 !important;
}
.toTop {
background: #757575 !important;
}
.material-layout .material-post>.material-nav,
.material-layout .material-index>.material-nav,
.material-nav a {
color: #757575;
}
#scheme-Paradox .MD-burger-layer {
background-color: #757575;
}
#scheme-Paradox #post-toc-trigger-btn {
color: #757575;
}
.post-toc a:hover {
color: #00838F;
text-decoration: underline;
}
</style>
<!-- Theme Background Related-->
<style>
body {
background-color: undefined;
}
/* blog_info bottom background */
#scheme-Paradox .material-layout .something-else .mdl-card__supporting-text {
background-color: #fff;
}
</style>
<!-- Fade Effect -->
<style>
.fade {
transition: all 800ms linear;
-webkit-transform: translate3d(0,0,0);
-moz-transform: translate3d(0,0,0);
-ms-transform: translate3d(0,0,0);
-o-transform: translate3d(0,0,0);
transform: translate3d(0,0,0);
opacity: 1;
}
.fade.out{
opacity: 0;
}
</style>
<!-- Import Font -->
<!-- Import Roboto -->
<style>
@font-face {
font-family: Roboto;
font-style: normal;
font-weight: 300;
src: url(https://lib.baomitu.com/fonts/roboto/roboto-v15-latin-300.eot);
src: local('Roboto'),local('Roboto-Normal'),url(https://lib.baomitu.com/fonts/roboto/roboto-v15-latin-300.eot?#iefix) format('embedded-opentype'),url(https://lib.baomitu.com/fonts/roboto/roboto-v15-latin-300.woff2) format('woff2'),url(https://lib.baomitu.com/fonts/roboto/roboto-v15-latin-300.woff) format('woff'),url(https://lib.baomitu.com/fonts/roboto/roboto-v15-latin-300.ttf) format('truetype'),url(https://lib.baomitu.com/fonts/roboto/roboto-v15-latin-300.svg#Roboto) format('svg')
}
@font-face {
font-family: Roboto;
font-style: normal;
font-weight: regular;
src: url(https://lib.baomitu.com/fonts/roboto/roboto-v15-latin-regular.eot);
src: local('Roboto'),local('Roboto-Normal'),url(https://lib.baomitu.com/fonts/roboto/roboto-v15-latin-regular.eot?#iefix) format('embedded-opentype'),url(https://lib.baomitu.com/fonts/roboto/roboto-v15-latin-regular.woff2) format('woff2'),url(https://lib.baomitu.com/fonts/roboto/roboto-v15-latin-regular.woff) format('woff'),url(https://lib.baomitu.com/fonts/roboto/roboto-v15-latin-regular.ttf) format('truetype'),url(https://lib.baomitu.com/fonts/roboto/roboto-v15-latin-regular.svg#Roboto) format('svg')
}
@font-face {
font-family: Roboto;
font-style: normal;
font-weight: 500;
src: url(https://lib.baomitu.com/fonts/roboto/roboto-v15-latin-500.eot);
src: local('Roboto'),local('Roboto-Normal'),url(https://lib.baomitu.com/fonts/roboto/roboto-v15-latin-500.eot?#iefix) format('embedded-opentype'),url(https://lib.baomitu.com/fonts/roboto/roboto-v15-latin-500.woff2) format('woff2'),url(https://lib.baomitu.com/fonts/roboto/roboto-v15-latin-500.woff) format('woff'),url(https://lib.baomitu.com/fonts/roboto/roboto-v15-latin-500.ttf) format('truetype'),url(https://lib.baomitu.com/fonts/roboto/roboto-v15-latin-500.svg#Roboto) format('svg')
}
</style>
<!-- Import Material Icon -->
<link rel="stylesheet" href="//cdn.bootcss.com/material-design-icons/3.0.1/iconfont/material-icons.min.css">
<!-- Import jQuery -->
<script>lsloader.load("jq_js","https://cdn.bootcss.com/jquery/2.2.1/jquery.js", true)</script>
<!-- The Open Graph protocol -->
<meta property="og:url" content="https://yangshunjie.com">
<meta property="og:type" content="blog">
<meta property="og:title" content="ASP.NET Core 中的SEO优化(4):自定义视图路径及主题切换 | ElderJames' Blog">
<meta property="og:image" content="https://yangshunjie.com/img/favicon.png" />
<meta property="og:description" content="学习、札记、分享">
<meta property="og:article:tag" content=".NET Core"> <meta property="og:article:tag" content="ASP.NET Core">
<meta property="article:published_time" content="Thu Nov 30 2017 21:44:19 GMT+0000" />
<meta property="article:modified_time" content="Fri Dec 15 2017 09:43:03 GMT+0000" />
<!-- The Twitter Card protocol -->
<meta name="twitter:title" content="ASP.NET Core 中的SEO优化(4):自定义视图路径及主题切换 | ElderJames' Blog">
<meta name="twitter:description" content="学习、札记、分享">
<meta name="twitter:image" content="https://yangshunjie.com/img/favicon.png">
<meta name="twitter:card" content="summary_large_image" />
<meta name="twitter:url" content="https://yangshunjie.com" />
<!-- Add canonical link for SEO -->
<link rel="canonical" href="https://yangshunjie.com/Customized-View-Path-And-Theme-Switching-In-AspNetCore.html" />
<!-- Structured-data for SEO -->
<script type="application/ld+json">
{
"@context": "https://schema.org",
"@type": "BlogPosting",
"mainEntityOfPage": "https://yangshunjie.com/Customized-View-Path-And-Theme-Switching-In-AspNetCore.html",
"headline": "ASP.NET Core 中的SEO优化(4):自定义视图路径及主题切换",
"datePublished": "Thu Nov 30 2017 21:44:19 GMT+0000",
"dateModified": "Fri Dec 15 2017 09:43:03 GMT+0000",
"author": {
"@type": "Person",
"name": "James Yeung",
"image": {
"@type": "ImageObject",
"url": "https://avatars0.githubusercontent.com/u/7550366?v=4&s=460"
},
"description": "学习/创作/分享"
},
"publisher": {
"@type": "Organization",
"name": "ElderJames' Blog",
"logo": {
"@type":"ImageObject",
"url": "/img/favicon.png"
}
},
"keywords": ",.NET Core,ASP.NET CoreElderJames' Blog",
"description": "学习、札记、分享",
}
</script>
<!-- Analytics -->
<!-- Custom Head -->
<link rel="stylesheet" href="/css/prism-vs.css" type="text/css">
<link rel="stylesheet" href="/css/prism-line-numbers.css" type="text/css"></head>
<body id="scheme-Paradox" class="lazy">
<div class="material-layout mdl-js-layout has-drawer is-upgraded">
<!-- Main Container -->
<main class="material-layout__content" id="main">
<!-- Top Anchor -->
<div id="top"></div>
<!-- Hamburger Button -->
<button class="MD-burger-icon sidebar-toggle">
<span class="MD-burger-layer"></span>
</button>
<!-- Post TOC -->
<!-- Back Button -->
<!--
<div class="material-back" id="backhome-div" tabindex="0">
<a class="mdl-button mdl-js-button mdl-js-ripple-effect mdl-button--icon"
href="#" onclick="window.history.back();return false;"
target="_self"
role="button"
data-upgraded=",MaterialButton,MaterialRipple">
<i class="material-icons" role="presentation">arrow_back</i>
<span class="mdl-button__ripple-container">
<span class="mdl-ripple"></span>
</span>
</a>
</div>
-->
<!-- Left aligned menu below button -->
<button id="post-toc-trigger-btn"
class="mdl-button mdl-js-button mdl-button--icon">
<i class="material-icons">format_list_numbered</i>
</button>
<ul class="post-toc-wrap mdl-menu mdl-menu--bottom-left mdl-js-menu mdl-js-ripple-effect" for="post-toc-trigger-btn" style="max-height:80vh; overflow-y:scroll;">
<ol class="post-toc"><li class="post-toc-item post-toc-level-2"><a class="post-toc-link" href="#系列回顾"><span class="post-toc-number">1.</span> <span class="post-toc-text"><a href="#系列回顾" class="headerlink" title="系列回顾"></a>系列回顾</span></a></li><li class="post-toc-item post-toc-level-2"><a class="post-toc-link" href="#背景"><span class="post-toc-number">2.</span> <span class="post-toc-text"><a href="#背景" class="headerlink" title="背景"></a>背景</span></a></li><li class="post-toc-item post-toc-level-2"><a class="post-toc-link" href="#原理"><span class="post-toc-number">3.</span> <span class="post-toc-text"><a href="#原理" class="headerlink" title="原理"></a>原理</span></a></li><li class="post-toc-item post-toc-level-2"><a class="post-toc-link" href="#实现"><span class="post-toc-number">4.</span> <span class="post-toc-text"><a href="#实现" class="headerlink" title="实现"></a>实现</span></a><ol class="post-toc-child"><li class="post-toc-item post-toc-level-4"><a class="post-toc-link" href="#ASP-NET-MVC-实现"><span class="post-toc-number">4.0.1.</span> <span class="post-toc-text"><a href="#ASP-NET-MVC-实现" class="headerlink" title="ASP.NET MVC 实现"></a>ASP.NET MVC 实现</span></a></li><li class="post-toc-item post-toc-level-4"><a class="post-toc-link" href="#ASP-NET-Core-实现"><span class="post-toc-number">4.0.2.</span> <span class="post-toc-text"><a href="#ASP-NET-Core-实现" class="headerlink" title="ASP.NET Core 实现"></a>ASP.NET Core 实现</span></a></li></ol></li></ol></li><li class="post-toc-item post-toc-level-2"><a class="post-toc-link" href="#总结"><span class="post-toc-number">5.</span> <span class="post-toc-text"><a href="#总结" class="headerlink" title="总结"></a>总结</span></a></li></ol>
</ul>
<!-- Layouts -->
<!-- Post Module -->
<div class="material-post_container">
<div class="material-post mdl-grid">
<div class="mdl-card mdl-shadow--4dp mdl-cell mdl-cell--12-col">
<!-- Post Header(Thumbnail & Title) -->
<!-- Paradox Post Header -->
<!-- Random Thumbnail -->
<div class="post_thumbnail-random mdl-card__media mdl-color-text--grey-50">
<script type="text/ls-javascript" id="post-thumbnail-script">
var randomNum = Math.floor(Math.random() * 19 + 1);
$('.post_thumbnail-random').attr('data-original', '/img/random/material-' + randomNum + '.png');
$('.post_thumbnail-random').addClass('lazy');
</script>
<p class="article-headline-p">
ASP.NET Core 中的SEO优化(4):自定义视图路径及主题切换
</p>
</div>
<!-- Paradox Post Info -->
<div class="mdl-color-text--grey-700 mdl-card__supporting-text meta">
<!-- Author Avatar -->
<div id="author-avatar">
<img src="https://avatars0.githubusercontent.com/u/7550366?v=4&s=460" width="44px" height="44px" alt="Author Avatar"/>
</div>
<!-- Author Name & Date -->
<div>
<strong>James Yeung</strong>
<span>11月 30, 2017</span>
</div>
<div class="section-spacer"></div>
<!-- Favorite -->
<!--
<button id="article-functions-like-button" class="mdl-button mdl-js-button mdl-js-ripple-effect mdl-button--icon btn-like">
<i class="material-icons" role="presentation">favorite</i>
<span class="visuallyhidden">favorites</span>
</button>
-->
<!-- Qrcode -->
<button id="article-functions-qrcode-button" class="mdl-button mdl-js-button mdl-js-ripple-effect mdl-button--icon">
<i class="material-icons" role="presentation">devices other</i>
<span class="visuallyhidden">devices other</span>
</button>
<ul class="mdl-menu mdl-menu--bottom-right mdl-js-menu mdl-js-ripple-effect" for="article-functions-qrcode-button">
<li class="mdl-menu__item">在其它设备中阅读本文章</li>
<img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAPYAAAD2CAAAAADAeSUUAAAC5UlEQVR42u3ay1LDMAwF0Pz/T8OWGWhyJQVI7eMV06SJj1moehwfW64DGxsbGxsbGxsb+5HsI17f7//6yQ+vie9J7pzsGRsbG3sHdvKaZBM56dW38u9W94yNjY29A/s8aM3D0qujyUNUb8/Y2NjY2OfB6Rw52XRyWNjY2NjYvUecH0F+NdlJfic2NjY2dr6hXjqRPHOSAv1iLQ0bGxv78exqo/cJf/9DfxsbGxv7key71iTAJOlK8syLN2JjY2Mvyu41bu9tLVykEMU7m7U0bGxs7Ldlv3p0r7mbFPqrjYTqJ4VUBBsbG3sJdj5SUy309J7wG3vDxsbGXpudB4BJOKkmFdXUJSpjYWNjYy/KnpeKelfzNkCv8FSeVMLGxsZ+W3a1uJ8c0F2Brfrki6PBxsbG3pLdK/3kyDzNmLQusLGxsfdh58WavJTTG/2ZpEnlWho2Njb2Eux7U4VeIzZJfnplKWxsbOy12b2m7GTTSdCaNxgKk0rY2NjYS7DzYs2kAXxvI+GGmVNsbGzshdh5gaZaTkpC3WQYqJDAYGNjYy/Krhblk1JUPujTa1Q0y1XY2NjYi7LLP+hbyUk18aiOWkbHh42Njb0ou/ejPx+dnIeoXusXGxsbex92nhjkIaQXbHqjmc3hS2xsbOyF2EnRP0lIJoX75F3VY23GbWxsbOw3Z/eKSr1DyYcp8wZwMwPDxsbGfnN2vvVqgOkNa/bSnmhX2NjY2Iuykx/xky32QmOvRXFxENjY2NiLso/WGjVcg5BZbTBjY2Nj78yurnk60Ut+JgNA2NjY2Guzq0FrknhUi02TkhM2Njb2buzeGE3CqAae5C3V52BjY2Pvw86bu3mSkF+tDgDlxSlsbGxs7CTlqBbue2lJtamAjY2Njd0rJDUbsYOAF/2rsLGxsTdgT4pKSdGnF6KSw4pa1NjY2NhLs+eN3vwgyg3aYhv4T/vb2NjY2A9g77OwsbGxsbGxsbGxH7M+ATL4mt1sL0IfAAAAAElFTkSuQmCC">
</ul>
<!-- Tags (bookmark) -->
<button id="article-functions-viewtags-button" class="mdl-button mdl-js-button mdl-js-ripple-effect mdl-button--icon">
<i class="material-icons" role="presentation">bookmark</i>
<span class="visuallyhidden">bookmark</span>
</button>
<ul class="mdl-menu mdl-menu--bottom-right mdl-js-menu mdl-js-ripple-effect" for="article-functions-viewtags-button">
<li class="mdl-menu__item">
<a class="post_tag-link" href="/tags/NET-Core/">.NET Core</a></li><li class="mdl-menu__item"><a class="post_tag-link" href="/tags/ASP-NET-Core/">ASP.NET Core</a>
</ul>
<!-- Share -->
<button id="article-fuctions-share-button" class="mdl-button mdl-js-button mdl-js-ripple-effect mdl-button--icon">
<i class="material-icons" role="presentation">share</i>
<span class="visuallyhidden">share</span>
</button>
<ul class="mdl-menu mdl-menu--bottom-right mdl-js-menu mdl-js-ripple-effect" for="article-fuctions-share-button">
<!-- Busuanzi Views -->
<a class="post_share-link" href="#">
<li class="mdl-menu__item">
<span id="busuanzi_container_page_pv">
<span id="busuanzi_value_page_pv"></span> 浏览量
</span>
</li>
</a>
<!-- Share Weibo -->
<a class="post_share-link" href="http://service.weibo.com/share/share.php?appkey=&title=ASP.NET Core 中的SEO优化(4):自定义视图路径及主题切换&url=https://yangshunjie.com/Customized-View-Path-And-Theme-Switching-In-AspNetCore.html&pic=https://yangshunjie.com/img/favicon.png&searchPic=false&style=simple" target="_blank">
<li class="mdl-menu__item">
分享到微博
</li>
</a>
<!-- Share Twitter -->
<!-- Share Facebook -->
<!-- Share Google+ -->
<!-- Share LinkedIn -->
<!-- Share QQ -->
<a class="post_share-link" href="http://connect.qq.com/widget/shareqq/index.html?site=ElderJames' Blog&title=ASP.NET Core 中的SEO优化(4):自定义视图路径及主题切换&summary=学习、札记、分享&pics=https://yangshunjie.com/img/favicon.png&url=https://yangshunjie.com/Customized-View-Path-And-Theme-Switching-In-AspNetCore.html" target="_blank">
<li class="mdl-menu__item">
分享到 QQ
</li>
</a>
<!-- Share Telegram -->
</ul>
</div>
<!-- Post Content -->
<div id="post-content" class="mdl-color-text--grey-700 mdl-card__supporting-text fade out">
<script src="\assets\js\APlayer.min.js"> </script><h2 id="系列回顾"><a href="#系列回顾" class="headerlink" title="系列回顾"></a>系列回顾</h2><ul>
<li><a href="A-Middleware-Implement-For-Server-Side-Static-Caching-In-AspNetCore.html">《ASP.NET Core 中的SEO优化(1):中间件实现服务端静态化缓存》</a></li>
<li><a href="A-Middleware-Implement-For-Rendering-Razor-Views-In-AspNetCore.html">《ASP.NET Core 中的SEO优化(2):中间件中渲染Razor视图》</a></li>
<li><a href="A-Middleware-Implement-For-Customized-Routing-In-AspNetCore.html">《ASP.NET Core 中的SEO优化(3):自定义路由匹配和生成》</a></li>
</ul>
<h2 id="背景"><a href="#背景" class="headerlink" title="背景"></a>背景</h2><p>切换主题,是博客、CMS等系统的必备功能,一般来说,有三种切换主题的需求。</p>
<ol>
<li>在管理后台上传主题包,并选择主题</li>
<li>前端自动按照频道、栏目等切换模版</li>
<li>用户在前端切换主题,并记录用户的选择</li>
</ol>
<p>这三种需求,其实核心原理都是一样,就是制定一套主题的目录,切换主题等于切换目录名。主题内的页面模版都是按照一定的规则存放的。</p>
<p>下面是两个主题包的目录示例:</p>
<pre class="line-numbers language-shell"><code class="language-shell"> .
├── 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
<span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre>
<p> 大家一定注意到了,上面每个主题包里都按照传统ASP.NET MVC的约定来划分目录:控制器名为文件夹,操作名为视图文件。其实这里只是方便起见,按照接下来介绍的方法,是可以完全地自定义这个目录划分的。</p>
<h2 id="原理"><a href="#原理" class="headerlink" title="原理"></a>原理</h2><p>当ASP.NET MVC从控制器处理完数据返回视图的时候,ASP.NET MVC会按照默认的多个路径去查找文件,如果文件存在,则使用该文件渲染,如果不存在,则寻找下一个路径,比如默认的路径会有<code>/{Area}/{Controller}/{Action}.cshtml</code>、<code>/{Controller}/{Action}.cshtml</code>、<code>/Shared/{Action}.cshtml</code>等等我们熟悉的约定,那么在查找视图文件时,会安装从左往右的路径去查询,如果都查询不出来,是会报错的。</p>
<p>而如果要做到切换主题文件夹名来切换主题,我们就需要在默认规则上加主题的目录占位符,使的查询时用主题文件夹名来替换占位符,例如<code>/{theme}/{Controller}/{Action}.cshtml</code>、<code>/{theme}/Shared/{Action}.cshtml</code>等等,这样,当查询视图文件时,就能匹配到对应的主题文件夹,并且找到相应的视图了。</p>
<p>总结起来,切换主题功能有两个重点需要我们去实现:</p>
<ol>
<li>在原有规则中加入占位符</li>
<li>每次请求都获取当前的主题名,并改变视图查询路径</li>
</ol>
<h2 id="实现"><a href="#实现" class="headerlink" title="实现"></a>实现</h2><p>最简单的实现,在操作(action)的最后<code>return View(viewPath)</code>时传入视图路径,直接就能指向对应视图,但是,这样做一点都不灵活,而且每个操作都要传路径也是不够简洁,不容易维护,所以我们需要更好的解决方案。</p>
<h4 id="ASP-NET-MVC-实现"><a href="#ASP-NET-MVC-实现" class="headerlink" title="ASP.NET MVC 实现"></a>ASP.NET MVC 实现</h4><p>在ASP.NET MVC时代,我们可通过继承RazorViewEngine类,在基类的<code>ViewLocationFormats</code>和<code>PartialViewLocationFormats</code>两个属性中加入有主题目录名占位符的路径,并重写<code>CreateView</code>、<code>CreatePartialView</code>、<code>FileExists</code>三个方法,使每次请求都能获取最新的主题名,如下面的例子中从路由数据对象中获取主题名:</p>
<pre class="line-numbers language-csharp"><code class="language-csharp"><span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">TemplateViewEngine</span> <span class="token punctuation">:</span> RazorViewEngine
<span class="token punctuation">{</span>
<span class="token keyword">public</span> <span class="token function">TemplateViewEngine</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">:</span> <span class="token keyword">base</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
<span class="token punctuation">{</span>
ViewLocationFormats <span class="token operator">=</span> <span class="token keyword">new</span><span class="token punctuation">[</span><span class="token punctuation">]</span> <span class="token punctuation">{</span>
<span class="token string">"~/Views/{1}%1/{0}.cshtml"</span><span class="token punctuation">,</span>
<span class="token string">"~/Views/{1}/{0}.cshtml"</span><span class="token punctuation">,</span><span class="token comment" spellcheck="true">//默认路径</span>
<span class="token string">"~/Views/Shared%1/{0}.cshtml"</span><span class="token punctuation">,</span>
<span class="token string">"~/Views/Shared/{0}.cshtml"</span><span class="token punctuation">,</span>
<span class="token punctuation">}</span><span class="token punctuation">;</span>
PartialViewLocationFormats <span class="token operator">=</span> <span class="token keyword">new</span><span class="token punctuation">[</span><span class="token punctuation">]</span> <span class="token punctuation">{</span>
<span class="token string">"~/Views/{1}%1/{0}.cshtml"</span><span class="token punctuation">,</span>
<span class="token string">"~/Views/{1}/{0}.cshtml"</span><span class="token punctuation">,</span><span class="token comment" spellcheck="true">//默认路径</span>
<span class="token string">"~/Views/Shared%1/{0}.cshtml"</span><span class="token punctuation">,</span>
<span class="token string">"~/Views/Shared/{0}.cshtml"</span><span class="token punctuation">,</span>
<span class="token punctuation">}</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token keyword">protected</span> <span class="token keyword">override</span> IView <span class="token function">CreatePartialView</span><span class="token punctuation">(</span>ControllerContext controllerContext<span class="token punctuation">,</span> <span class="token keyword">string</span> partialPath<span class="token punctuation">)</span>
<span class="token punctuation">{</span>
<span class="token keyword">var</span> template <span class="token operator">=</span> controllerContext<span class="token punctuation">.</span>RouteData<span class="token punctuation">.</span>Values<span class="token punctuation">[</span><span class="token string">"template"</span><span class="token punctuation">]</span> <span class="token operator">!=</span> <span class="token keyword">null</span> <span class="token operator">?</span> <span class="token string">"/"</span> <span class="token operator">+</span> controllerContext<span class="token punctuation">.</span>RouteData<span class="token punctuation">.</span>Values<span class="token punctuation">[</span><span class="token string">"template"</span><span class="token punctuation">]</span><span class="token punctuation">.</span><span class="token function">ToString</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">:</span> <span class="token string">""</span><span class="token punctuation">;</span>
<span class="token keyword">return</span> <span class="token keyword">base</span><span class="token punctuation">.</span><span class="token function">CreatePartialView</span><span class="token punctuation">(</span>controllerContext<span class="token punctuation">,</span> partialPath<span class="token punctuation">.</span><span class="token function">Replace</span><span class="token punctuation">(</span><span class="token string">"%1"</span><span class="token punctuation">,</span> template<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token keyword">protected</span> <span class="token keyword">override</span> IView <span class="token function">CreateView</span><span class="token punctuation">(</span>ControllerContext controllerContext<span class="token punctuation">,</span> <span class="token keyword">string</span> viewPath<span class="token punctuation">,</span> <span class="token keyword">string</span> masterPath<span class="token punctuation">)</span>
<span class="token punctuation">{</span>
<span class="token keyword">var</span> template <span class="token operator">=</span> controllerContext<span class="token punctuation">.</span>RouteData<span class="token punctuation">.</span>Values<span class="token punctuation">[</span><span class="token string">"template"</span><span class="token punctuation">]</span> <span class="token operator">!=</span> <span class="token keyword">null</span> <span class="token operator">?</span> <span class="token string">"/"</span> <span class="token operator">+</span> controllerContext<span class="token punctuation">.</span>RouteData<span class="token punctuation">.</span>Values<span class="token punctuation">[</span><span class="token string">"template"</span><span class="token punctuation">]</span><span class="token punctuation">.</span><span class="token function">ToString</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">:</span> <span class="token string">""</span><span class="token punctuation">;</span>
<span class="token keyword">return</span> <span class="token keyword">base</span><span class="token punctuation">.</span><span class="token function">CreateView</span><span class="token punctuation">(</span>controllerContext<span class="token punctuation">,</span> viewPath<span class="token punctuation">.</span><span class="token function">Replace</span><span class="token punctuation">(</span><span class="token string">"%1"</span><span class="token punctuation">,</span> template<span class="token punctuation">)</span><span class="token punctuation">,</span> masterPath<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token keyword">protected</span> <span class="token keyword">override</span> <span class="token keyword">bool</span> <span class="token function">FileExists</span><span class="token punctuation">(</span>ControllerContext controllerContext<span class="token punctuation">,</span> <span class="token keyword">string</span> virtualPath<span class="token punctuation">)</span>
<span class="token punctuation">{</span>
<span class="token keyword">var</span> template <span class="token operator">=</span> controllerContext<span class="token punctuation">.</span>RouteData<span class="token punctuation">.</span>Values<span class="token punctuation">[</span><span class="token string">"template"</span><span class="token punctuation">]</span> <span class="token operator">!=</span> <span class="token keyword">null</span> <span class="token operator">?</span> <span class="token string">"/"</span> <span class="token operator">+</span> controllerContext<span class="token punctuation">.</span>RouteData<span class="token punctuation">.</span>Values<span class="token punctuation">[</span><span class="token string">"template"</span><span class="token punctuation">]</span><span class="token punctuation">.</span><span class="token function">ToString</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">:</span> <span class="token string">""</span><span class="token punctuation">;</span>
<span class="token keyword">return</span> <span class="token keyword">base</span><span class="token punctuation">.</span><span class="token function">FileExists</span><span class="token punctuation">(</span>controllerContext<span class="token punctuation">,</span> virtualPath<span class="token punctuation">.</span><span class="token function">Replace</span><span class="token punctuation">(</span><span class="token string">"%1"</span><span class="token punctuation">,</span> template<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span>
<span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre>
<p>事实上,如果是需要实现不同用户不同主题的功能,主题信息可以存储在Session中,还能从<code>controllerContext</code>实例获取<code>Session</code>中存储的主题名。</p>
<p>那么,在ASP.NET Core中如何实现呢?</p>
<h4 id="ASP-NET-Core-实现"><a href="#ASP-NET-Core-实现" class="headerlink" title="ASP.NET Core 实现"></a>ASP.NET Core 实现</h4><p>ASP.NET Core 相比ASP.NET MVC框架,虽然使用上为了开发者平滑过渡,很多约定都相同,但是架构本身是做了翻天覆地的重构和优化,得益于一脉相承的MSDI框架,ASP.NET Core框架实现了组件化,很多功能都通过IoC的方式修改或扩展。例如本文介绍的主题情况功能,就是实现<code>IViewLocationExpander</code>接口来达到扩展配置的目的,而且还比ASP.NET MVC的更加简洁:</p>
<pre class="line-numbers language-csharp"><code class="language-csharp"><span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">TemplateViewLocationExpander</span> <span class="token punctuation">:</span> IViewLocationExpander
<span class="token punctuation">{</span>
<span class="token keyword">public</span> IEnumerable<span class="token operator"><</span><span class="token keyword">string</span><span class="token operator">></span> <span class="token function">ExpandViewLocations</span><span class="token punctuation">(</span>ViewLocationExpanderContext context<span class="token punctuation">,</span> IEnumerable<span class="token operator"><</span><span class="token keyword">string</span><span class="token operator">></span> viewLocations<span class="token punctuation">)</span>
<span class="token punctuation">{</span>
<span class="token keyword">var</span> template <span class="token operator">=</span> context<span class="token punctuation">.</span>Values<span class="token punctuation">[</span><span class="token string">"template"</span><span class="token punctuation">]</span> <span class="token operator">?</span><span class="token operator">?</span> <span class="token string">"Default"</span><span class="token punctuation">;</span>
<span class="token keyword">string</span><span class="token punctuation">[</span><span class="token punctuation">]</span> locations <span class="token operator">=</span> <span class="token punctuation">{</span> <span class="token string">"/Views/"</span> <span class="token operator">+</span> template <span class="token operator">+</span> <span class="token string">"/{1}/{0}.cshtml"</span><span class="token punctuation">,</span> <span class="token string">"/Views/"</span> <span class="token operator">+</span> template <span class="token operator">+</span> <span class="token string">"/{0}.cshtml"</span><span class="token punctuation">,</span> <span class="token string">"/Views/"</span> <span class="token operator">+</span> template <span class="token operator">+</span> <span class="token string">"/Shared/{0}.cshtml"</span> <span class="token punctuation">}</span><span class="token punctuation">;</span>
<span class="token keyword">return</span> locations<span class="token punctuation">.</span><span class="token function">Union</span><span class="token punctuation">(</span>viewLocations<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">PopulateValues</span><span class="token punctuation">(</span>ViewLocationExpanderContext context<span class="token punctuation">)</span>
<span class="token punctuation">{</span>
context<span class="token punctuation">.</span>Values<span class="token punctuation">[</span><span class="token string">"template"</span><span class="token punctuation">]</span> <span class="token operator">=</span> context<span class="token punctuation">.</span>ActionContext<span class="token punctuation">.</span>RouteData<span class="token punctuation">.</span>Values<span class="token punctuation">[</span><span class="token string">"Template"</span><span class="token punctuation">]</span><span class="token operator">?</span><span class="token punctuation">.</span><span class="token function">ToString</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">?</span><span class="token operator">?</span> <span class="token string">"Default"</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span>
<span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre>
<p>这个接口里面,<code>PopulateValues</code>方法主要用来获取实时的主题信息,<code>context.ActionContext</code>中除了<code>RouteData</code>可获得实时数据,还有<code>HttpContext</code>实例可获得用户信息,甚至能利用<code>RequestServices</code>实例注入服务。而只有在<code>PopulateValues</code>中修改了<code>context</code>,<code>ExpandViewLocations</code>方法才会从<code>context</code>中获得主题信息,从而达到修改视图查找路径的目的。</p>
<p>当我们实现了<code>IViewLocationExpander</code>接口后,还需要在<code>Startup</code>类的<code>services.AddMvc();</code>下修改MVC的配置:</p>
<pre class="line-numbers language-csharp"><code class="language-csharp">services<span class="token punctuation">.</span><span class="token function">AddMvc</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token comment" spellcheck="true">//配置模版视图路径</span>
services<span class="token punctuation">.</span><span class="token generic-method function">Configure<span class="token punctuation"><</span>RazorViewEngineOptions<span class="token punctuation">></span></span><span class="token punctuation">(</span>options <span class="token operator">=</span><span class="token operator">></span>
<span class="token punctuation">{</span>
options<span class="token punctuation">.</span>ViewLocationExpanders<span class="token punctuation">.</span><span class="token function">Add</span><span class="token punctuation">(</span><span class="token keyword">new</span> <span class="token class-name">TemplateViewLocationExpander</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span aria-hidden="true" class="line-numbers-rows"><span></span><span></span><span></span><span></span><span></span><span></span></span></code></pre>
<p><em>PS:这种修改MVC内部配置的方式很有趣,以后有空会研究一番。</em></p>
<h2 id="总结"><a href="#总结" class="headerlink" title="总结"></a>总结</h2><p>本文主要介绍了在ASP.NET Core中利用修改视图查询路径实现主题切换的功能,虽然只介绍了核心部分,但是其它部分如管理主题、前端切换等功能,都是很容易实现的,以后我会在我的框架样例中实现,敬请大家关注啦!</p>
<blockquote style="margin: 2em 0 0;padding: 0.5em 1em;border-left: 3px solid #F44336;background-color: #F5F5F5;list-style: none;">
<p><strong>
<a rel="license" href="http://creativecommons.org/licenses/by-nc-sa/4.0/"><img alt="知识共享许可协议" style="border-width:0" src="https://i.creativecommons.org/l/by-nc-sa/4.0/80x15.png" /></a><br />本作品采用<a rel="license" href="http://creativecommons.org/licenses/by-nc-sa/4.0/">知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议</a>进行许可。
</strong>
<br>
<strong>本文链接:</strong><a href="https://yangshunjie.com/Customized-View-Path-And-Theme-Switching-In-AspNetCore.html">https://yangshunjie.com/Customized-View-Path-And-Theme-Switching-In-AspNetCore.html</a>
</p>
</blockquote>
</div>
<!-- Post Comments -->
<!-- 使用 Gitalk -->
<div id="gitalk-comment">
<!-- Gitalk 评论框 -->
<div id="gitalk-container"></div>
<link rel="stylesheet" href="https://unpkg.com/gitalk/dist/gitalk.css">
<script src="https://unpkg.com/gitalk/dist/gitalk.min.js"></script>
<script>
var gitalk = new Gitalk({
clientID: '695234dcb3266b06c9bc',
clientSecret: '9012a4415f4672e4858df564fc9999e9b6d5cec0',
repo: 'elderjames.github.io',
owner: 'ElderJames',
admin: ['ElderJames'],
// facebook-like distraction free mode
distractionFreeMode: false
})
gitalk.render('gitalk-container')
</script>
</div>
<style>
#gitalk-comment {
background-color: #eee;
padding: 2pc;
}
</style>
</div>
<!-- Post Prev & Next Nav -->
<nav class="material-nav mdl-color-text--grey-50 mdl-cell mdl-cell--12-col">
<!-- Prev Nav -->
<a href="/my-first-respberry-pi.html" id="post_nav-newer" class="prev-content">
<button class="mdl-button mdl-js-button mdl-js-ripple-effect mdl-button--icon mdl-color--white mdl-color-text--grey-900" role="presentation">
<i class="material-icons">arrow_back</i>
</button>
新篇
</a>
<!-- Section Spacer -->
<div class="section-spacer"></div>
<!-- Next Nav -->
<a href="/A-Middleware-Implement-For-Customized-Routing-In-AspNetCore.html" id="post_nav-older" class="next-content">
旧篇
<button class="mdl-button mdl-js-button mdl-js-ripple-effect mdl-button--icon mdl-color--white mdl-color-text--grey-900" role="presentation">
<i class="material-icons">arrow_forward</i>
</button>
</a>
</nav>
</div>
</div>
<!-- Overlay For Active Sidebar -->
<div class="sidebar-overlay"></div>
<!-- Material sidebar -->
<aside id="sidebar" class="sidebar sidebar-colored sidebar-fixed-left" role="navigation">
<div id="sidebar-main">
<!-- Sidebar Header -->
<div class="sidebar-header header-cover" style="background-image: url(/img/sidebar_header.png);">
<!-- Top bar -->
<div class="top-bar"></div>
<!-- Sidebar toggle button -->
<button type="button" class="sidebar-toggle mdl-button mdl-js-button mdl-js-ripple-effect mdl-button--icon" style="display: initial;" data-upgraded=",MaterialButton,MaterialRipple">
<i class="material-icons">clear_all</i>
<span class="mdl-button__ripple-container">
<span class="mdl-ripple">
</span>
</span>
</button>
<!-- Sidebar Avatar -->
<div class="sidebar-image">
<img src="https://avatars0.githubusercontent.com/u/7550366?v=4&s=460" alt="James Yeung's avatar">
</div>
<!-- Sidebar Email -->
<a data-toggle="dropdown" class="sidebar-brand" href="#settings-dropdown">
shunjiey@hotmail.com
<b class="caret"></b>
</a>
</div>
<!-- Sidebar Navigation -->
<ul class="nav sidebar-nav">
<!-- User dropdown -->
<li class="dropdown">
<ul id="settings-dropdown" class="dropdown-menu">
<li>
<a href="mailto:shunjiey@hotmail.com" target="_blank" title="Email Me">
<i class="material-icons sidebar-material-icons sidebar-indent-left1pc-element">email</i>
Email Me
</a>
</li>
</ul>
</li>
<!-- Homepage -->
<li id="sidebar-first-li">
<a href="/">
<i class="material-icons sidebar-material-icons">home</i>
主页
</a>
</li>
<!-- Archives -->
<li class="dropdown">
<a href="#" class="ripple-effect dropdown-toggle" data-toggle="dropdown">
<i class="material-icons sidebar-material-icons">inbox</i>
归档
<b class="caret"></b>
</a>
<ul class="dropdown-menu">
<li>
<a class="sidebar_archives-link" href="/archives/2017/12/">十二月 2017<span class="sidebar_archives-count">1</span></a></li><li><a class="sidebar_archives-link" href="/archives/2017/11/">十一月 2017<span class="sidebar_archives-count">4</span></a></li><li><a class="sidebar_archives-link" href="/archives/2017/09/">九月 2017<span class="sidebar_archives-count">5</span></a></li><li><a class="sidebar_archives-link" href="/archives/2017/08/">八月 2017<span class="sidebar_archives-count">3</span></a></li><li><a class="sidebar_archives-link" href="/archives/2017/07/">七月 2017<span class="sidebar_archives-count">1</span></a></li><li><a class="sidebar_archives-link" href="/archives/2017/03/">三月 2017<span class="sidebar_archives-count">1</span></a></li><li><a class="sidebar_archives-link" href="/archives/2016/09/">九月 2016<span class="sidebar_archives-count">2</span></a></li><li><a class="sidebar_archives-link" href="/archives/2016/07/">七月 2016<span class="sidebar_archives-count">6</span></a></li><li><a class="sidebar_archives-link" href="/archives/2016/06/">六月 2016<span class="sidebar_archives-count">1</span></a></li><li><a class="sidebar_archives-link" href="/archives/2016/03/">三月 2016<span class="sidebar_archives-count">4</span></a></li><li><a class="sidebar_archives-link" href="/archives/2015/12/">十二月 2015<span class="sidebar_archives-count">1</span></a></li><li><a class="sidebar_archives-link" href="/archives/2015/11/">十一月 2015<span class="sidebar_archives-count">1</span></a></li><li><a class="sidebar_archives-link" href="/archives/2015/10/">十月 2015<span class="sidebar_archives-count">4</span></a>
</ul>
</li>
<!-- Categories -->
<li class="dropdown">
<a href="#" class="ripple-effect dropdown-toggle" data-toggle="dropdown">
<i class="material-icons sidebar-material-icons">chrome_reader_mode</i>
分类
<b class="caret"></b>
</a>
<ul class="dropdown-menu">
<li>
<a class="sidebar_archives-link" href="/categories/NET-Core/">.NET Core<span class="sidebar_archives-count">9</span></a></li><li><a class="sidebar_archives-link" href="/categories/DDD/">DDD<span class="sidebar_archives-count">1</span></a></li><li><a class="sidebar_archives-link" href="/categories/Docker/">Docker<span class="sidebar_archives-count">1</span></a></li><li><a class="sidebar_archives-link" href="/categories/Github-Pages/">Github Pages<span class="sidebar_archives-count">1</span></a></li><li><a class="sidebar_archives-link" href="/categories/Hexo/">Hexo<span class="sidebar_archives-count">2</span></a></li><li><a class="sidebar_archives-link" href="/categories/树莓派/">树莓派<span class="sidebar_archives-count">1</span></a>
</ul>
</li>
<!-- Pages -->
<li>
<a href="/tags.html" title="标签云">
<i class="material-icons sidebar-material-icons">local_offer</i>
标签云
</a>
</li>
<li>
<a href="/timeline.html" title="时间轴">
<i class="material-icons sidebar-material-icons">list</i>
时间轴
</a>
</li>
<li>
<a href="/contact.html" title="留言板">
<i class="material-icons sidebar-material-icons">forum</i>
留言板
</a>
</li>
<li>
<a href="/about.html" title="关于我">
<i class="material-icons sidebar-material-icons">face</i>
关于我
</a>
</li>
<li>
<a href="/gallery.html" title="相册">
<i class="material-icons sidebar-material-icons">image</i>
相册
</a>
</li>
<li>
<a href="/friends.html" title="朋友">
<i class="material-icons sidebar-material-icons">people</i>
朋友
</a>
</li>
<!-- Article Number -->
<li>
<a href="/archives">
文章总数
<span class="sidebar-badge">34</span>
</a>
</li>
</ul>
<!-- Sidebar Footer -->
<!--
I'm glad you use this theme, the development is no so easy, I hope you can keep the copyright, I will thank you so much.
If you still want to delete the copyrights, could you still retain the first one? Which namely "Theme Material"
It will not impact the appearance and can give developers a lot of support :)
很高兴您使用并喜欢该主题,开发不易 十分谢谢与希望您可以保留一下版权声明。
如果您仍然想删除的话 能否只保留第一项呢?即 "Theme Material"
它不会影响美观并可以给开发者很大的支持和动力。 :)
-->
<!-- Sidebar Divider -->
<!-- Theme Material -->
<!-- Help & Support -->
<!--
-->
<!-- Feedback -->
<!--
-->
<!-- About Theme -->
<!--
-->
</div>
<!-- Sidebar Image -->
<span id="footer-image">
<a href="https://ci.appveyor.com/project/ElderJames/elderjames-github-io" target="_blank" title="AppVeyor">
<img src="https://ci.appveyor.com/api/projects/status/b0wack7uxrvifijj?svg=true" alt="AppVeyor"><!--
--></a>
</span>
</aside>
<!-- Footer Top Button -->
<div id="back-to-top" class="toTop-wrap">
<a href="#top" class="toTop">
<i class="material-icons footer_top-i">expand_less</i>
</a>
</div>
<!--Footer-->
<footer class="mdl-mini-footer" id="bottom" >
<!-- Paradox Footer Left Section -->
<div class="mdl-mini-footer--left-section sns-list">
<!-- Twitter -->
<!-- Facebook -->
<!-- Google + -->
<!-- Weibo -->
<!-- Instagram -->
<!-- Tumblr -->
<!-- Github -->
<a href="ElderJames" target="_blank">
<button class="mdl-mini-footer--social-btn social-btn footer-sns-github">
<span class="visuallyhidden">Github</span>
</button><!--
--></a>
<!-- LinkedIn -->
<a href="杨舜杰" target="_blank">
<button class="mdl-mini-footer--social-btn social-btn footer-sns-linkedin">
<span class="visuallyhidden">LinkedIn</span>
</button><!--
--></a>
<!-- Zhihu -->
<a href="ElderJames" target="_blank">
<button class="mdl-mini-footer--social-btn social-btn footer-sns-zhihu">
<span class="visuallyhidden">Zhihu</span>
</button><!--
--></a>
<!-- Bilibili -->
<!-- Telegram -->
<!-- V2EX -->
</div>
<!--Copyright-->
<div id="copyright">
Copyright © 2015 -<script type="text/javascript">var fd = new Date();document.write(" " + fd.getFullYear() + " ");</script>ElderJames' Blog
<br>
学习/创作/分享<br /><a href="http://icp.chinaz.com/info?q=yangshunjie.com" rel="nofollow">粤ICP备15021181号-1</a>
</div>
<!-- Paradox Footer Right Section -->
<!--
I am glad you use this theme, the development is no so easy, I hope you can keep the copyright.
It will not impact the appearance and can give developers a lot of support :)
很高兴您使用该主题,开发不易,希望您可以保留一下版权声明。
它不会影响美观并可以给开发者很大的支持。 :)
-->
<div class="mdl-mini-footer--right-section">
<div>
<div class="footer-develop-div">Powered by <a href="https://hexo.io" target="_blank" class="footer-develop-a">Hexo</a></div>
<div class="footer-develop-div">Theme - <a href="https://github.com/viosey/hexo-theme-material" target="_blank" class="footer-develop-a">Material</a></div>
</div>
</div>
</footer>
<!-- Import JS File -->
<script>lsloader.load("lazyload_js","/js/lazyload.min.js?1BcfzuNXqV+ntF6gq+5X3Q==", true)</script>
<script>lsloader.load("js_js","/js/js.min.js?V/53wGualMuiPM3xoetD5Q==", true)</script>
<script>lsloader.load("np_js","//cdn.bootcss.com/nprogress/0.2.0/nprogress.min.js", true)</script>
<script type="text/ls-javascript" id="NProgress-script">
NProgress.configure({
showSpinner: true
});
NProgress.start();
$('#nprogress .bar').css({
'background': '#29d'
});
$('#nprogress .peg').css({
'box-shadow': '0 0 10px #29d, 0 0 15px #29d'
});
$('#nprogress .spinner-icon').css({
'border-top-color': '#29d',
'border-left-color': '#29d'
});
setTimeout(function() {
NProgress.done();
$('.fade').removeClass('out');
}, 800);
</script>
<script>lsloader.load("sm_js","/js/smoothscroll.js?lOy/ACj5suSNi7ZVFVbpFQ==", true)</script>
<!-- Busuanzi -->
<script src="https://dn-lbstatics.qbox.me/busuanzi/2.3/busuanzi.pure.mini.js"></script>
<!-- CommentBox -->
<!-- GitTalk -->
<!-- UC Browser Compatible -->
<script>
var agent = navigator.userAgent.toLowerCase();
if(agent.indexOf('ucbrowser')>0) {
document.write('<link rel="stylesheet" href="/css/uc.css">');
alert('由于 UC 浏览器使用极旧的内核,而本网站使用了一些新的特性。\n为了您能更好的浏览,推荐使用 Chrome 或 Firefox 浏览器。');
}
</script>
<!-- Import prettify js -->
<script>lsloader.load("prettify_js","//cdn.bootcss.com/prettify/r298/prettify.min.js", true)</script>
<!-- Window Load -->
<!-- add class for prettify -->
<script type="text/ls-javascript" id="window-load">
$(window).on('load', function() {
// Post_Toc parent position fixed
$('.post-toc-wrap').parent('.mdl-menu__container').css('position', 'fixed');
});
$(function() {
$('pre').addClass('prettyprint linenums').attr('style', 'overflow:auto;');
prettyPrint();
})
</script>
<!-- MathJax Load-->
<!-- Bing Background -->
<script type="text/ls-javascript" id="Bing-Background-script">
queue.offer(function(){
$('body').attr('data-original', 'https://api.i-meto.com/bing?type=S');
});
</script>
<script type = "text/ls-javascript" id= "title-script">
//网页当前状态判断
var hidden, state, visibilityChange,timer;
var leaveTitle='(●-●) 我奔溃啦~';
var stayTitle='(*´∇`*) 被发现啦~';
var difaultTitle = document.title;
var resetTime=1000
leaveTitle += document.title;
stayTitle += document.title;
if (typeof document.hidden !== "undefined") {
hidden = "hidden";
visibilityChange = "visibilitychange";
state = "visibilityState";
} else if (typeof document.mozHidden !== "undefined") {
hidden = "mozHidden";
visibilityChange = "mozvisibilitychange";
state = "mozVisibilityState";
} else if (typeof document.msHidden !== "undefined") {
hidden = "msHidden";
visibilityChange = "msvisibilitychange";
state = "msVisibilityState";
} else if (typeof document.webkitHidden !== "undefined") {
hidden = "webkitHidden";
visibilityChange = "webkitvisibilitychange";
state = "webkitVisibilityState";
}
// 添加监听器,在title里显示状态变化
document.addEventListener(visibilityChange, function () {
// document.title = document[state] =='visible'?stayTitle:leaveTitle ;
if (timer!=null) clearTimeout(timer);
if (document[state] =='visible'){
document.title = stayTitle;
timer=setTimeout(function(){
document.title=difaultTitle;
},resetTime)
}
else{
document.title = leaveTitle;
}
}, false);
//初始化页面状态
document.title = document[state] =='visible'?stayTitle:leaveTitle ;
</script>
<script type="text/ls-javascript" id="lazy-load">
// Offer LazyLoad
queue.offer(function(){
$('.lazy').lazyload({
effect : 'show'
});
});
// Start Queue
$(document).ready(function(){
setInterval(function(){
queue.execNext();
},200);
});
</script>
<!-- Custom Footer -->
<script>
(function(){
var scriptList = document.querySelectorAll('script[type="text/ls-javascript"]')
for (var i = 0; i < scriptList.length; ++i) {
var item = scriptList[i];
lsloader.runInlineScript(item.id,item.id);
}
})()
console.log('\n %c © Material Theme | Version: 1.5.0 | https://github.com/viosey/hexo-theme-material %c \n', 'color:#455a64;background:#e0e0e0;padding:5px 0;border-top-left-radius:5px;border-bottom-left-radius:5px;', 'color:#455a64;background:#e0e0e0;padding:5px 0;border-top-right-radius:5px;border-bottom-right-radius:5px;');
</script>
</main>
</div>
<div id="hexo-helper-live2d">
<canvas id="live2dcanvas" width="150" height="300"></canvas>
</div>
<style>
#live2dcanvas{
position: fixed;
width: 150px;
height: 300px;
opacity:0.7;
right: 0px;
z-index: 999;
pointer-events: none;
bottom: 60px;
}
</style>
<script type="text/javascript" src="/live2d/device.min.js"></script>
<script type="text/javascript">
const loadScript = function loadScript(c,b){var a=document.createElement("script");a.type="text/javascript";"undefined"!=typeof b&&(a.readyState?a.onreadystatechange=function(){if("loaded"==a.readyState||"complete"==a.readyState)a.onreadystatechange=null,b()}:a.onload=function(){b()});a.src=c;document.body.appendChild(a)};
(function(){
if((typeof(device) != 'undefined') && (device.mobile())){
document.getElementById("live2dcanvas").style.width = '75px';
document.getElementById("live2dcanvas").style.height = '150px';
}else
if (typeof(device) === 'undefined') console.error('Cannot find current-device script.');
loadScript("/live2d/script.js", function(){loadlive2d("live2dcanvas", "/live2d/assets/tororo.model.json", 0.5);});
})();
</script>
</body>
</html>
此处可能存在不合适展示的内容,页面不予展示。您可通过相关编辑功能自查并修改。
如您确认内容无涉及 不当用语 / 纯广告导流 / 暴力 / 低俗色情 / 侵权 / 盗版 / 虚假 / 无价值内容或违法国家有关法律法规的内容,可点击提交进行申诉,我们将尽快为您处理。