当前位置: 首页 > news >正文

网站加地图标记银川网站公司

网站加地图标记,银川网站公司,现在的网络怎么做网站,移动电子商务的概念在 ASP.NET Core 里扩展 Razor 查找视图目录不是什么新鲜和困难的事情#xff0c;但 _ViewStart 和 _ViewImports 这2个视图比较特殊#xff0c;如果想让 Razor 在我们指定的目录中查找它们#xff0c;则需要耗费一点额外的精力。本文将提供一种方法做到这一点。注意#x…在 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 CustomizedViewLocationcd CustomizedViewLocationdotnet new web # 创建一个空的 ASP.NET Core 应用 接下来稍微调整下 Startup.cs 文件的内容引入 MVC // Startup.csusing 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 是 Homestring 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.cspublic 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 可以发现如下对应关系 命名空间视图路径ViewLocationFormatCustomizedViewLocation项目根路径/Reports.AdHocReportsReports/AdHocReports把整个命名空间以“.”为分割点掐头去尾然后把“.”替换为“”EmployeeReportEmployeeReportController 名称Views固定目录Index.cshtml视图名称.cshtml 所以我们 IViewLocationExpander 的实现类型主要是获取和处理 Controller 的命名空间。且看下面的代码。 // NamespaceViewLocationExpander.csusing 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 IEnumerablestring ExpandViewLocations(ViewLocationExpanderContext context, IEnumerablestring 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 Liststring locations){locations.Add(viewLocation);                             return locations;}            // it turns out the viewLocations from ASP.NET Core is Liststring, so the code path should not go here.Liststring 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.cspublic void ConfigureServices(IServiceCollection services){IMvcBuilder mvcBuilder services.AddMvc();mvcBuilder.AddRazorOptions(options {        // options.ViewLocationFormats.Add(/{1}/Views/{0}.cshtml); we dont 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.cspublic 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.cspublic class RazorTemplateEngine{    public virtual IEnumerableRazorProjectItem GetImportItems(RazorProjectItem projectItem)    {         var importsFileName Options.ImportsFileName;              if (!string.IsNullOrEmpty(importsFileName)){                      return Project.FindHierarchicalItems(projectItem.FilePath, importsFileName);}               return Enumerable.EmptyRazorProjectItem();} } FindHierarchicalItems 方法会返回一个路径集合其中包括从视图当前目录一路到根目录的每一级目录下的 _ViewImports.cshtml 路径。换句话说如果从根目录开始到视图所在目录的每一层目录都有 _ViewImports.cshtml 文件的话那么它们都会起作用。这也是为什么通常我们在 根目录下的 Views 目录里放一个 _ViewImports.cshtml 文件就会被所有视图文件所引用因为 Views 目录是是所有视图文件的父祖父目录。那么如果我们的 _ViewImports.cshtml 文件不在视图的目录层次结构中呢 在这个 DI 为王的 ASP.NET Core 世界里RazorTemplateEngine 也被注册为 DI 里的服务因此我目前的做法继承 MvcRazorTemplateEngine 类微调 GetImportItems 方法的逻辑加入我们的特定路径然后注册到 DI 取代原来的实现类型。代码如下 // ModuleRazorTemplateEngine.csusing 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 IEnumerableRazorProjectItem GetImportItems(RazorProjectItem projectItem)        {IEnumerableRazorProjectItem 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.AddSingletonRazorTemplateEngine, 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.cspublic class RazorViewEngine : IRazorViewEngine{    private const string ViewStartFileName _ViewStart.cshtml;    internal ViewLocationCacheResult CreateCacheResult(        HashSetIChangeToken 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.EmptyViewLocationCacheItem();                  if (viewDescriptor.IsPrecompiled){_logger.PrecompiledViewFound(relativePath);}                        return new ViewLocationCacheResult(                             new ViewLocationCacheItem(factoryResult.RazorPageFactory, relativePath),viewStartPages);}                           return null;}        private IReadOnlyListViewLocationCacheItem GetViewStartPages(        string path,        HashSetIChangeToken expirationTokens)    {            var viewStartPages new ListViewLocationCacheItem();        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 IEnumerableRazorProjectItem FindHierarchicalItems(string basePath, string path, string fileName)        {IEnumerableRazorProjectItem 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.AddSingletonRazorTemplateEngine, ModuleRazorTemplateEngine(); // we dont need this any more if we make use of ModuleBasedRazorProjectservices.AddSingletonRazorProject, 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组件 NPOIASP.NET Core Razor页面 vs MVCRazor 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 HelpersASP.NET Core MVC – Form Tag HelpersASP.NET Core MVC – 自定义 Tag HelpersASP.NET Core MVC – Tag Helper 组件ASP.Net Core Razor 页面路由粗略使用.NetCore2.0自带授权登陆Authorize 原文地址http://www.cnblogs.com/Ricky81317/p/7483222.html .NET社区新闻深度好文微信中搜索dotNET跨平台或扫描二维码关注
http://www.zqtcl.cn/news/222648/

相关文章:

  • 遵义建设厅官方网站 元丰兰州网站设计有限公司
  • 芜湖做网站的公司排名贵阳好的网站建设公司
  • 网站建设 骏域网站建设专家最有效的15个营销方法
  • 大连品牌官网建站为什么有些网站更新的信息看不到
  • 富阳市网站域名申请好了怎么做网站
  • 做药物分析必须知道的网站网站攻击一般有那些
  • 一般网站做哪些端口映射那个网站做境外自由行便宜
  • 网站的建站过程公司seo是什么意思
  • 胜利油田局域网主页入口seo自学网官网
  • 阜阳网站是网站开发与设计专业
  • 网站建设哪个品牌好网站新备案不能访问
  • 网站备案号申请流程华为企业文化
  • 服装网站目标互联网舆情报告
  • 1.网站开发的详细流程电商网站开发文档
  • 域名估价网站制作网站需要注意什么
  • 新浪云虚拟主机做电影网站用什么l软件做网站了
  • 方城网站建设猴痘的治疗方法
  • 做响应式网站有什么插件哔哩哔哩免费安装
  • 织梦网站默认密码wordpress菜单页和文章页路径不同
  • 那些网站可以做兼职网站建设与维护 东博
  • 快速建站的模板建设银行嘉兴分行官方网站
  • 江西智能网站建设wordpress三栏博客主题
  • 怎么做网站账号注册机sem竞价
  • 吕梁建设机械网站怎么让网站排名上去
  • 网站建设的需要分析龙岗招聘网
  • 如何制作企业的网站网站开发答辩ppt
  • 大连中山网站建设网站在线qq代码
  • 南昌seo网站微商城网站建设如何
  • anker 网站建设手机可以做网站的服务器吗
  • 门户网站建设 报价没有网页快照对网站有什么影响