日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > asp.net >内容正文

asp.net

ASP.NET Core 2.0 自定义 _ViewStart 和 _ViewImports 的目录位置

發布時間:2023/12/4 asp.net 27 豆豆
生活随笔 收集整理的這篇文章主要介紹了 ASP.NET Core 2.0 自定义 _ViewStart 和 _ViewImports 的目录位置 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

在 ASP.NET Core 里擴展 Razor 查找視圖目錄不是什么新鮮和困難的事情,但?_ViewStart?和?_ViewImports?這2個視圖比較特殊,如果想讓 Razor 在我們指定的目錄中查找它們,則需要耗費一點額外的精力。本文將提供一種方法做到這一點。注意,文本僅適用于 ASP.NET Core 2.0+, 因為 Razor 在 2.0 版本里的內部實現有較大重構,因此這里提供的方法并不適用于 ASP.NET Core 1.x

為了全面描述 ASP.NET Core 2.0 中擴展 Razor 查找視圖目錄的能力,我們還是由淺入深,從最簡單的擴展方式著手吧。

準備工作

首先,我們可以創建一個新的 ASP.NET Core 項目用于演示。

mkdir CustomizedViewLocation
cd CustomizedViewLocationdotnet new web # 創建一個空的 ASP.NET Core 應用

接下來稍微調整下 Startup.cs 文件的內容,引入 MVC:

// Startup.cs
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.DependencyInjection;

namespace CustomizedViewLocation{ ?

public class Startup{ ? ? ?
? ? ?public void ConfigureServices(IServiceCollection services) ? ? ? ?{services.AddMvc();} ? ? ?
? ? ?
? ? ?public void Configure(IApplicationBuilder app, IHostingEnvironment env) ? ? ? ?{app.UseMvcWithDefaultRoute();}} }

好了我們的演示項目已經搭好了架子。

我們的目標

在我們的示例項目中,我們希望我們的目錄組織方式是按照功能模塊組織的,即同一個功能模塊的所有 Controller 和 View 都放在同一個目錄下。對于多個功能模塊共享、通用的內容,比如?_Layout,?_Footer,?_ViewStart?和?_ViewImports?則單獨放在根目錄下的一個叫 Shared 的子目錄中。

最簡單的方式: ViewLocationFormats

假設我們現在有2個功能模塊 Home 和 About,分別需要?HomeController?和它的?Index?view,以及?AboutMeController?和它的?Index?view. 因為一個 Controller 可能會包含多個 view,因此我選擇為每一個功能模塊目錄下再增加一個?Views?目錄,集中這個功能模塊下的所有 View. 整個目錄結構看起來是這樣的:

從目錄結構中我們可以發現我們的視圖目錄為?/{controller}/Views/{viewName}.cshtml, 比如?HomeController?的?Index?視圖所在的位置就是?/Home/Views/Index.cshtml,這跟 MVC 默認的視圖位置?/Views/{Controller}/{viewName}.cshtml?很相似(/Views/Home/Index.cshtml),共同的特點是路徑中的 Controller 部分和 View 部分是動態的,其它的都是固定不變的。其實 MVC 默認的尋找視圖位置的方式一點都不高端,類似于這樣:

string controllerName = "Home"; // “我”知道當前 Controller 是 Home
string viewName = "Index"; // "我“知道當前需要解析的 View 的名字// 把 viewName 和 controllerName 帶入一個代表視圖路徑的格式化字符串得到最終的視圖路徑。
string viewPath = string.Format("/Views/{1}/{0}.cshtml", viewName, controllerName);// 根據 viewPath 找到視圖文件做后續處理

如果我們可以構建另一個格式字符串,其中?{0}?代表 View 名稱,?{1}?代表 Controller 名稱,然后替換掉默認的?/Views/{1}/{0}.cshtml,那我們就可以讓 Razor 到我們設定的路徑去檢索視圖。而要做到這點非常容易,利用?ViewLocationFormats,代碼如下:

// Startup.cs
public void ConfigureServices(IServiceCollection services){IMvcBuilder mvcBuilder = services.AddMvc();mvcBuilder.AddRazorOptions(options => options.ViewLocationFormats.Add("/{1}/Views/{0}.cshtml")); }

收工,就這么簡單。順便說一句,還有一個參數?{2},代表 Area 名稱。

這種做法是不是已經很完美了呢?No, No, No. 誰能看出來這種做法有什么缺點?

這種做法有2個缺點。

  • 所有的功能模塊目錄必須在根目錄下創建,無法建立層級目錄關系。且看下面的目錄結構截圖:

  • 注意 Reports 目錄,因為我們有種類繁多的報表,因此我們希望可以把各種報表分門別類放入各自的目錄。但是這么做之后,我們之前設置的?ViewLocationFormats?就無效了。例如我們訪問 URL?/EmployeeReport/Index, Razor 會試圖尋找?/EmployeeReport/Views/Index.cshtml,但其真正的位置是?/Reports/AdHocReports/EmployeeReport/Views/Index.cshtml。前面還有好幾層目錄呢~

  • 因為所有的 View 文件不再位于同一個父級目錄之下,因此?_ViewStart.cshtml?和?_ViewImports.cshtml?的作用將受到極大限制。原因后面細表。

  • 下面我們來分別解決這2個問題。

    最靈活的方式: IViewLocationExpander

    有時候,我們的視圖目錄除了 controller 名稱 和 view 名稱2個變量外,還涉及到別的動態部分,比如上面的 Reports 相關 Controller,視圖路徑有更深的目錄結構,而 controller 名稱僅代表末級的目錄。此時,我們需要一種更靈活的方式來處理:?IViewLocationExpander,通過實現?IViewLocationExpander,我們可以得到一個?ViewLocationExpanderContext,然后據此更靈活地創建 view location formats。

    對于我們要解決的目錄層次問題,我們首先需要觀察,然后會發現目錄層次結構和 Controller 類型的命名空間是有對應關系的。例如如下定義:

    using Microsoft.AspNetCore.Mvc;

    namespace CustomizedViewLocation.Reports.AdHocReports.EmployeeReport{ ?

    ?public class EmployeeReportController : Controller{ ? ? ? ?public IActionResult Index() => View();} }

    觀察?EmployeeReportController?的命名空間?CustomizedViewLocation.Reports.AdHocReports.EmployeeReport以及 Index 視圖對應的目錄?/Reports/AdHocReports/EmployeeReport/Views/Index.cshtml?可以發現如下對應關系:

    命名空間視圖路徑ViewLocationFormat
    CustomizedViewLocation項目根路徑/
    Reports.AdHocReportsReports/AdHocReports把整個命名空間以“.”為分割點掐頭去尾,然后把“.”替換為“/”
    EmployeeReportEmployeeReportController 名稱

    Views固定目錄

    Index.cshtml視圖名稱.cshtml

    所以我們?IViewLocationExpander?的實現類型主要是獲取和處理 Controller 的命名空間。且看下面的代碼。

    // NamespaceViewLocationExpander.cs
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.IO;
    using Microsoft.Extensions.DependencyInjection;
    using Microsoft.AspNetCore.Mvc.Razor;
    using Microsoft.AspNetCore.Hosting;
    using Microsoft.AspNetCore.Mvc;
    using Microsoft.AspNetCore.Mvc.Controllers;

    namespace CustomizedViewLocation{ ?

    ?public class NamespaceViewLocationExpander : IViewLocationExpander{ ? ? ?
    ??private const string VIEWS_FOLDER_NAME = "Views"; ? ?
    ??? ?public IEnumerable<string> ExpandViewLocations(ViewLocationExpanderContext context, IEnumerable<string> viewLocations) ? ? ? ?{ControllerActionDescriptor cad = context.ActionContext.ActionDescriptor as ControllerActionDescriptor; ? ? ? ? ? ?string controllerNamespace = cad.ControllerTypeInfo.Namespace; ? ? ? ? ? ?int firstDotIndex = controllerNamespace.IndexOf('.'); ? ? ? ? ? ?int lastDotIndex = controllerNamespace.LastIndexOf('.'); ? ? ? ? ? ?if (firstDotIndex < 0) ? ? ? ? ?
    ??? ? ? ? ?return viewLocations; ? ? ? ? ?
    ??? ? ? ? ??string viewLocation; ? ? ? ? ?
    ??? ? ? ? ??if (firstDotIndex == lastDotIndex){ ? ? ? ? ? ? ? ?// controller folder is the first level sub folder of root folderviewLocation = "/{1}/Views/{0}.cshtml";} ? ? ? ? ?
    ??? ? ? ? ???else{ ? ? ? ? ? ? ?
    ??? ? ? ? ??? ?string viewPath = controllerNamespace.Substring(firstDotIndex + 1, lastDotIndex - firstDotIndex - 1).Replace(".", "/");viewLocation = $"/{viewPath}/{{1}}/Views/{{0}}.cshtml";} ? ? ? ?
    ??? ? ? ?? ?if (viewLocations.Any(l => l.Equals(viewLocation, StringComparison.InvariantCultureIgnoreCase))) ? ? ? ? ? ?
    ??? ? ? ??? ?return viewLocations; ? ? ? ? ?
    ??? ? ? ??? ?if (viewLocations is List<string> locations){locations.Add(viewLocation); ? ? ?
    ??? ? ? ??? ?? ? ? ? ?return locations;} ? ? ? ? ? ?// it turns out the viewLocations from ASP.NET Core is List<string>, so the code path should not go here.List<string> newViewLocations = viewLocations.ToList();newViewLocations.Add(viewLocation); ? ? ?
    ??? ? ? ??? ?? ? ? ? ? ? ? ?return newViewLocations;} ?
    ??? ? ? ?
    ??? ? ? ?? ? ?public void PopulateValues(ViewLocationExpanderContext context) ? ? ? ?{}} }

    上面對命名空間的處理略顯繁瑣。其實你可以不用管,重點是我們可以得到?ViewLocationExpanderContext,并據此構建新的 view location format 然后與現有的?viewLocations?合并并返回給 ASP.NET Core。

    細心的同學可能還注意到一個空的方法?PopulateValues,這玩意兒有什么用?具體作用可以參照這個 StackOverflow 的問題,基本上來說,一旦某個 Controller 及其某個 View 找到視圖位置之后,這個對應關系就會緩存下來,以后就不會再調用?ExpandViewLocations方法了。但是,如果你有這種情況,就是同一個 Controller, 同一個視圖名稱但是還應該依據某些特別條件去找不同的視圖位置,那么就可以利用?PopulateValues?方法填充一些特定的 Value, 這些 Value 會參與到緩存鍵的創建, 從而控制到視圖位置緩存的創建。

    下一步,把我們的?NamespaceViewLocationExpander?注冊一下:

    // Startup.cs
    public void ConfigureServices(IServiceCollection services){IMvcBuilder mvcBuilder = services.AddMvc();mvcBuilder.AddRazorOptions(options => { ? ? ? ?// options.ViewLocationFormats.Add("/{1}/Views/{0}.cshtml"); we don't need this any more if we make use of NamespaceViewLocationExpanderoptions.ViewLocationExpanders.Add(new NamespaceViewLocationExpander());}); }

    另外,有了?NamespaceViewLocationExpander, 我們就不需要前面對?ViewLocationFormats?的追加了,因為那種情況作為一種特例已經在?NamespaceViewLocationExpander?中處理了。
    至此,目錄分層的問題解決了。

    _ViewStart.cshtml 和 _ViewImports 的起效機制與調整

    對這2個特別的視圖,我們并不陌生,通常在 _ViewStart.cshtml 里面設置 Layout 視圖,然后每個視圖就自動地啟用了那個 Layout 視圖,在 _ViewImports.cshtml 里引入的命名空間和 TagHelper 也會自動包含在所有視圖里。它們為什么會起作用呢?

    _ViewImports 的秘密藏在?RazorTemplateEngine 類?和?MvcRazorTemplateEngine 類中。

    MvcRazorTemplateEngine 類指明了 "_ViewImports.cshtml" 作為默認的名字。

    // MvcRazorTemplateEngine.cs 部分代碼// 完整代碼: https://github.com/aspnet/Razor/blob/rel/2.0.0/src/Microsoft.AspNetCore.Mvc.Razor.Extensions/MvcRazorTemplateEngine.cs

    public class MvcRazorTemplateEngine : RazorTemplateEngine{ ?

    ?public MvcRazorTemplateEngine(RazorEngine engine, RazorProject project) ? ? ? ?: base(engine, project) ? ?{Options.ImportsFileName = "_ViewImports.cshtml";Options.DefaultImports = GetDefaultImports();} }

    RazorTemplateEngine 類則表明了 Razor 是如何去尋找 _ViewImports.cshtml 文件的。

    // RazorTemplateEngine.cs 部分代碼// 完整代碼:https://github.com/aspnet/Razor/blob/rel/2.0.0/src/Microsoft.AspNetCore.Razor.Language/RazorTemplateEngine.cs
    public class RazorTemplateEngine{ ?

    ?public virtual IEnumerable<RazorProjectItem> GetImportItems(RazorProjectItem projectItem) ? ?{ ?
    ?? ? ?var importsFileName = Options.ImportsFileName; ? ?
    ?? ? ? ? ?if (!string.IsNullOrEmpty(importsFileName)){ ? ? ? ? ?
    ?? ? ? ? ??return Project.FindHierarchicalItems(projectItem.FilePath, importsFileName);} ? ? ?
    ?? ? ? ?return Enumerable.Empty<RazorProjectItem>();} }

    FindHierarchicalItems?方法會返回一個路徑集合,其中包括從視圖當前目錄一路到根目錄的每一級目錄下的 _ViewImports.cshtml 路徑。換句話說,如果從根目錄開始,到視圖所在目錄的每一層目錄都有 _ViewImports.cshtml 文件的話,那么它們都會起作用。這也是為什么通常我們在 根目錄下的 Views 目錄里放一個 _ViewImports.cshtml 文件就會被所有視圖文件所引用,因為 Views 目錄是是所有視圖文件的父/祖父目錄。那么如果我們的 _ViewImports.cshtml 文件不在視圖的目錄層次結構中呢?

    在這個 DI 為王的 ASP.NET Core 世界里,RazorTemplateEngine 也被注冊為 DI 里的服務,因此我目前的做法繼承?MvcRazorTemplateEngine?類,微調?GetImportItems?方法的邏輯,加入我們的特定路徑,然后注冊到 DI 取代原來的實現類型。代碼如下:

    // ModuleRazorTemplateEngine.cs
    using System.Collections.Generic;
    using System.Linq;
    using Microsoft.AspNetCore.Mvc.Razor.Extensions;
    using Microsoft.AspNetCore.Razor.Language;

    namespace CustomizedViewLocation{ ? ?

    public class ModuleRazorTemplateEngine : MvcRazorTemplateEngine{ ? ? ?
    ?public ModuleRazorTemplateEngine(RazorEngine engine, RazorProject project) : base(engine, project) ? ? ? ?{} ? ? ? ?
    ?
    ?public override IEnumerable<RazorProjectItem> GetImportItems(RazorProjectItem projectItem) ? ? ? ?{IEnumerable<RazorProjectItem> importItems = base.GetImportItems(projectItem); ? ? ? ? ?
    ??return importItems.Append(Project.GetItem($"/Shared/Views/{Options.ImportsFileName}"));}} }

    然后在 Startup 類里把它注冊到 DI 取代默認的實現類型。

    // Startup.cs//
    using Microsoft.AspNetCore.Razor.Language;

    public void ConfigureServices(IServiceCollection services){services.AddSingleton<RazorTemplateEngine, ModuleRazorTemplateEngine>();IMvcBuilder mvcBuilder = services.AddMvc(); ? ?// 其它代碼省略}

    下面是 _ViewStart.cshtml 的問題了。不幸的是,Razor 對 _ViewStart.cshtml 的處理并沒有那么“靈活”,看代碼就知道了。

    // RazorViewEngine.cs 部分代碼// 完整代碼:https://github.com/aspnet/Mvc/blob/rel/2.0.0/src/Microsoft.AspNetCore.Mvc.Razor/RazorViewEngine.cs
    public class RazorViewEngine : IRazorViewEngine{ ?

    ?private const string ViewStartFileName = "_ViewStart.cshtml"; ? ?internal ViewLocationCacheResult CreateCacheResult( ? ? ? ?HashSet<IChangeToken> expirationTokens, ? ? ?
    ? ? ? ? ?string relativePath, ? ?
    ? ? ? ? ?? ?bool isMainPage
    ) ? ?
    { ? ?
    ?? ?var factoryResult = _pageFactory.CreateFactory(relativePath); ? ? ? ?var viewDescriptor = factoryResult.ViewDescriptor; ? ?
    ?? ? ? ?if (viewDescriptor?.ExpirationTokens != null){ ? ? ? ? ?
    ?? ? ? ? ?for (var i = 0; i < viewDescriptor.ExpirationTokens.Count; i++){expirationTokens.Add(viewDescriptor.ExpirationTokens[i]);}} ? ? ?
    ?? ? ? ?if (factoryResult.Success){ ? ? ? ? ? ?// Only need to lookup _ViewStarts for the main page.var viewStartPages = isMainPage ?GetViewStartPages(viewDescriptor.RelativePath, expirationTokens) :Array.Empty<ViewLocationCacheItem>(); ? ? ?
    ?? ? ? ? ? ?if (viewDescriptor.IsPrecompiled){_logger.PrecompiledViewFound(relativePath);} ? ? ? ? ?
    ?? ? ? ? ? ??return new ViewLocationCacheResult( ? ? ? ? ?
    ?? ? ? ? ? ?? ? ? ?new ViewLocationCacheItem(factoryResult.RazorPageFactory, relativePath),viewStartPages);} ? ? ?
    ?? ? ? ? ? ?? ? ? ? ?return null;} ?
    ??
    ?? ?private IReadOnlyList<ViewLocationCacheItem> GetViewStartPages( ? ? ? ?string path, ? ? ? ?HashSet<IChangeToken> expirationTokens) ? ?{ ? ?
    ?? ?? ?var viewStartPages = new List<ViewLocationCacheItem>(); ? ? ? ?foreach (var viewStartProjectItem in _razorProject.FindHierarchicalItems(path, ViewStartFileName)){ ? ? ? ? ?
    ?? ?? ? ?var result = _pageFactory.CreateFactory(viewStartProjectItem.FilePath); ? ? ? ? ? ?var viewDescriptor = result.ViewDescriptor; ? ? ? ?
    ?? ?? ? ?? ?if (viewDescriptor?.ExpirationTokens != null){ ? ? ? ? ? ?
    ?? ?? ? ?? ?? ?for (var i = 0; i < viewDescriptor.ExpirationTokens.Count; i++){expirationTokens.Add(viewDescriptor.ExpirationTokens[i]);}} ? ? ? ? ?
    ?? ?? ? ?? ?if (result.Success){ ? ? ? ? ? ? ? ?// Populate the viewStartPages list so that _ViewStarts appear in the order the need to be// executed (closest last, furthest first). This is the reverse order in which// ViewHierarchyUtility.GetViewStartLocations returns _ViewStarts.viewStartPages.Insert(0, new ViewLocationCacheItem(result.RazorPageFactory, viewStartProjectItem.FilePath));}} ? ? ?
    ?? ?? ? ?return viewStartPages;} }

    上面的代碼里?GetViewStartPages?方法是個?private,沒有什么機會讓我們加入自己的邏輯。看了又看,好像只能從?_razorProject.FindHierarchicalItems(path, ViewStartFileName)?這里著手。這個方法同樣在處理 _ViewImports.cshtml時用到過,因此和 _ViewImports.cshtml 一樣,從根目錄到視圖當前目錄之間的每一層目錄的 _ViewStarts.cshtml 都會被引入。如果我們可以調整一下?FindHierarchicalItems?方法,除了完成它原本的邏輯之外,再加入我們對我們?/Shared/Views?目錄的引用就好了。而?FindHierarchicalItems?這個方法是在?Microsoft.AspNetCore.Razor.Language.RazorProject?類型里定義的,而且是個?virtual?方法,而且它是注冊在 DI 里的,不過在 DI 中的實現類型是?Microsoft.AspNetCore.Mvc.Razor.Internal.FileProviderRazorProject。我們所要做的就是創建一個繼承自?FileProviderRazorProject?的類型,然后調整?FindHierarchicalItems?方法。

    using System.Linq;
    using System.Collections.Generic;
    using Microsoft.AspNetCore.Mvc.Razor.Internal;
    using Microsoft.AspNetCore.Razor.Language;

    namespace CustomizedViewLocation{ ?

    ?public class ModuleBasedRazorProject : FileProviderRazorProject{ ? ?
    ?
    ?? ?public ModuleBasedRazorProject(IRazorViewEngineFileProviderAccessor accessor) ? ? ? ? ? ?: base(accessor) ? ? ? ?{} ? ? ?
    ?? ?
    ?? ??public override IEnumerable<RazorProjectItem> FindHierarchicalItems(string basePath, string path, string fileName) ? ? ? ?{IEnumerable<RazorProjectItem> items = base.FindHierarchicalItems(basePath, path, fileName); ? ? ? ? ? ?// the items are in the order of closest first, furthest last, therefore we append our item to be the last item.return items.Append(GetItem("/Shared/Views/" + fileName));}} }

    完成之后再注冊到 DI。

    // Startup.cs// using Microsoft.AspNetCore.Razor.Language;
    public void ConfigureServices(IServiceCollection services){ ? ?// services.AddSingleton<RazorTemplateEngine, ModuleRazorTemplateEngine>(); // we don't need this any more if we make use of ModuleBasedRazorProjectservices.AddSingleton<RazorProject, ModuleBasedRazorProject>();IMvcBuilder mvcBuilder = services.AddMvc(); ? ?// 其它代碼省略}

    有了?ModuleBasedRazorProject?我們甚至可以去掉之前我們寫的?ModuleRazorTemplateEngine?類型了,因為 Razor 采用相同的邏輯 —— 使用?RazorProject?的?FindHierarchicalItems?方法 —— 來構建應用 _ViewImports.cshtml 和 _ViewStart.cshtml 的目錄層次結構。所以最終,我們只需要一個類型來解決問題 ——?ModuleBasedRazorProject。

    回顧這整個思考和嘗試的過程,很有意思,最終解決方案是自定義一個?RazorProject。是啊,畢竟我們的需求只是一個不同目錄結構的 Razor Project,所以去實現一個我們自己的?RazorProject?類型真是再自然不過的了。

    文本中的示例代碼在這里?https://github.com/RickyLin/Demos/tree/master/CustomizedViewLocation?

    相關文章:?

    • .NET Core 2.0 正式發布信息匯總

    • .NET Standard 2.0 特性介紹和使用指南

    • .NET Core 2.0 的dll實時更新、https、依賴包變更問題及解決

    • .NET Core 2.0 特性介紹和使用指南

    • Entity Framework Core 2.0 新特性

    • 體驗 PHP under .NET Core

    • .NET Core 2.0使用NLog

    • 升級項目到.NET Core 2.0,在Linux上安裝Docker,并成功部署

    • 解決Visual Studio For Mac Restore失敗的問題

    • ASP.NET Core 2.0 特性介紹和使用指南

    • .Net Core下通過Proxy 模式 使用 WCF

    • .NET Core 2.0 開源Office組件 NPOI

    • ASP.NET Core Razor頁面 vs MVC

    • Razor Page–Asp.Net Core 2.0新功能 ?Razor Page介紹

    • MySql 使用 EF Core 2.0 CodeFirst、DbFirst、數據庫遷移(Migration)介紹及示例

    • .NET Core 2.0遷移技巧之web.config配置文件

    • asp.net core MVC 過濾器之ExceptionFilter過濾器(一)

    • ASP.NET Core 使用Cookie驗證身份

    • ASP.NET Core MVC – Tag Helpers 介紹

    • ASP.NET Core MVC – Caching Tag Helpers

    • ASP.NET Core MVC – Form Tag Helpers

    • ASP.NET Core MVC – 自定義 Tag Helpers

    • ASP.NET Core MVC – Tag Helper 組件

    • ASP.Net Core Razor 頁面路由

    • 粗略使用.NetCore2.0自帶授權登陸Authorize

    原文地址:http://www.cnblogs.com/Ricky81317/p/7483222.html


    .NET社區新聞,深度好文,微信中搜索dotNET跨平臺或掃描二維碼關注

    總結

    以上是生活随笔為你收集整理的ASP.NET Core 2.0 自定义 _ViewStart 和 _ViewImports 的目录位置的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。