以下的学习笔记是在asp.net core web应用程序里面进行的,为了避免不必要的问题,首先明确建立项目的过程:
在这里我选择的是web应用程序,不是后面那个,这两个很明显是不同的。
一、静态文件的显示
在asp.net framework的网站项目中,如果想在视图中显示一张静态图片,按照下面的代码是没问题的
但是在asp.net core中就不行,它显示不出来。需要进行一些配置才能提供这些文件。静态文件存储在项目的 Web 根目录中。 默认目录是 <content_root>/wwwroot。在不做任何配置的情况下,将wwwroot中的图片直接放到视图中是可以正常显示的,比如:
但是如果在wwwroot的同级目录下建立MyStaticFiles文件夹,然后在里面放下用于显示的图片,像上面那样直接在标签img里面就没法显示出来。
这是因为在Startup类的Configure方法中,app.UseStaticFiles()这条语句将Web 根目录中的文件标记为可用(如果创建的core项目是空项目,系统是不会为你添加这条语句的)。所以为了让其他目录下的静态文件可用,需要按照如下方式配置:要注意的是下面的语句不是要覆盖掉没有参数的app.UseStaticFiles(),要不要覆盖根据自己的需要来处理。
app.UseStaticFiles(new StaticFileOptions { FileProvider= new PhysicalFileProvider( Path.Combine(Directory.GetCurrentDirectory(), "MyStaticFiles")), RequestPath = "/MyStaticFiles" });
代码里的第一个MyStaticFiles表示目录中文件夹的名字
第二个MyStaticFiles根据自己的需要写,然后可以在视图中用<img src="~/MyStaticFiles/images/TBn.jpg" />来引用文件(注意标签img中,src里面的MyStaticFiles就是上面代码中的第二个MyStaticFiles。其他的文件比如js,css文件也是类似的处理)
二、默认文档
在没有做任何关于默认文档的配置的情况下,对于新建的core网站项目,直接运行的时候,网站地址类似:https://localhost:44300,然后显示的首页是pages下面的index.cshtml这个视图。但是在项目里面却找不到有关的路由配置或者其他的配置。不喜欢这种不能掌控的感觉。所以需要自己配置默认的首页。若要在用户不完全限定 URI 的情况下提供默认页面,请调用 Startup.Configure
中的 UseDefaultFiles 方法。
public void Configure(IApplicationBuilder app) { app.UseDefaultFiles(); app.UseStaticFiles(); }
必须在 UseStaticFiles
前调用 UseDefaultFiles
。 UseDefaultFiles
实际上用于重写 URL,不提供文件。 通过 UseStaticFiles
启用静态文件中间件来提供文件。无参的UseDefaultFiles方法会在Web 根目录(即wwwroot)中搜索default.htm,default.html,index.htm,index.html这四个文件。如果找不到,就会跟之前一样显示index.cshtml。一定要确保这四个静态网页在wwwroot目录下。
以下代码将默认文件名更改为 abs.html:
DefaultFilesOptions options = new DefaultFilesOptions(); options.DefaultFileNames.Clear(); options.DefaultFileNames.Add("abs.html"); app.UseDefaultFiles(options);
注意:abs.html也必须在wwwroot目录下,即使你已经通过UseStaticFiles定义了其他目录(比如上面的MyStaticFiles)。否则你自定义的默认文件其实没有用。
当UseDefaultFiles的无参调用和有参调用同时存在的时候,如上面的代码,运行程序的时候,出现的默认页是default.html,(即使index.html也同时存在)。但如果将上面的UseDefaultFiles的无参调用放在有参调用的后面,那出现的默认页就是abs.html。
三、UseFileServer
UseFileServer 结合了 UseStaticFiles
、UseDefaultFiles
和 UseDirectoryBrowser
的功能。当无参调用的时候,相当于 UseStaticFiles
、UseDefaultFiles
的无参调用。以下代码启用静态文件、默认文件和及 My
StaticFiles
的目录浏览:
app.UseFileServer(new FileServerOptions { FileProvider = new PhysicalFileProvider( Path.Combine(Directory.GetCurrentDirectory(), "MyStaticFiles")), RequestPath = "/StaticFiles", EnableDirectoryBrowsing = true//属性值为 true 时必须调用 AddDirectoryBrowser });
EnableDirectoryBrowsing
属性值为 true
时必须调用 AddDirectoryBrowser
:
public void ConfigureServices(IServiceCollection services) { services.AddDirectoryBrowser(); }
四、读取配置文件
1、读取json配置文件
在项目建好后,里面有个配置文件appsettings.json,读取里面的内容的代码如下:
public IConfiguration Configuration { get; set; }
var builder = new ConfigurationBuilder() .SetBasePath(Directory.GetCurrentDirectory()) .AddJsonFile("appsettings.json"); Configuration = builder.Build();
这段代码是定义了要读取那个json文件里的内容。在这个项目里,这段代码我放到了IndexModel类里面,先定义属性Configuration,然后在OnGet方法中创建ConfigurationBuilder。在index.cshtml中用@Model.Configuration["wizards:0:Age"]来获取json中的内容。appsettings.json:
{ "Logging": { "LogLevel": { "Default": "Warning" } }, "option1": "value1_from_json", "option2": 2, "subsection": { "suboption1": "subvalue1_from_json" }, "wizards": [ { "Name": "Gandalf", "Age": "1000" }, { "Name": "Harry", "Age": "17" } ] }
获取json中各个节点的值:Configuration["Option1"],Configuration["subsection:suboption1"],Configuration["wizards:0:Name"]
2、xml配置
若要在 XML 格式的配置源中使用数组,请向每个元素提供一个 name
索引。
var builder = new ConfigurationBuilder() .SetBasePath(Directory.GetCurrentDirectory()) .AddXmlFile("XMLFile.xml"); Configuration = builder.Build();
如xml文档内容:
<wizards>
<wizard name="Gandalf">
<age>1000</age>
</wizard>
<wizard name="Harry">
<age>17</age>
</wizard>
</wizards>
访问的时候:Configuration["wizard:Harry:age"]
五、标记帮助程序
什么是标记帮助程序,官方解释是:使服务器端代码可以在 Razor 文件中参与创建和呈现 HTML 元素。我的理解就是在后台代码中决定前端HTML元素,然后在前端显示。这个功能也只能对现有的HTML标签进行操作,通过包装创造出你自己风格的标签来,暂时还不清楚用这个优势在哪里
要实现标记帮助程序,首先得定义一个类,实现 ITagHelper
接口的任何类。 但是,在创作标记帮助程序时,通常从 TagHelper
派生,这样可以访问 Process
方法。
1、在asp.net core项目中创建一个文件夹TagHelpers。 “TagHelpers”文件夹不是必需的,但它是合理的约定。下图中的models文件夹是项目自动创建的。
2、在models文件夹中创建一个类ATag,这个类包含了我等会要创建的a标签的标记帮助程序的一些属性。在这里我把这个类放在了WebsiteContext文件里面(当然可以单独的一个文件,这都不重要)
public class ATag { public string Href { set; get; } public string Class { set; get; } public string Style { set; get; } public string Content { set; get; } }
3、在TagHelpers文件夹中创建一个类MyHtmlTagHelper。类名可以按自己的要求来,但最好后缀为TagHelper,这不是必需的,但被认为是最佳做法约定。在这里我把这个类放在了WebsiteInformationTagHelper文件中(当然可以单独的一个文件,这都不重要)。
public class MyHtmlTagHelper : TagHelper { public ATag Info { set; get; } public override void Process(TagHelperContext context, TagHelperOutput output) { output.TagName = "div"; output.Content.SetHtmlContent( $"<a class='{Info.Class}' style='{Info.Style}' href='{Info.Href}'>{Info.Content}</a>" ); //output.TagMode = TagMode.StartTagAndEndTag; } }
在这里主要看方法process,这里我主要的目的是设置a标签,我设置tagname为div,其目的是为了方便。否则如果将tagname直接设置为a,将不好设置a标签的属性了。SetHtmlContent函数里面具体定义了a标签的属性。最后注释的语句是设置标签的开头和结尾的,这里是针对div标签的开头和结尾,谁叫TagName 是div呢。再次说明,从语法上来讲,将TagName 设置为div,则这个标记帮助程序的目标就是div标签,但我的本意是a标签,为了要设置a标签的属性,所以才用了这个方法(当然有更专业的方式来设置属性,这个后面会提到,这里暂时用简单点的方式)。你要愿意,也可以将TagName 设置为span,你高兴就好。所以TagMode 属性针对的就是TagName 里指定的div标签。由于div标签在HTML中必然是<div></div>这样成对出现的,因此TagMode 必须是TagMode.StartTagAndEndTag(这也是默认值),否则会导致在使用了这个标记帮助程序后,页面上没有显示出你想象中的效果。感觉废话说了一大堆,不知道理解了我的意思没。
4、将标记帮助程序应用到视图中。在做好上面3步后(最主要是2,3这两步),先编译一下项目,记住一定要编译,不然让你在写代码的时候没有提示。要使 MyHtmlTagHelper类可用于所有 Razor 视图,请将 addTagHelper
指令添加到 Views/_ViewImports.cshtml 文件。
上面的代码使用通配符语法来指定程序集中的所有标记帮助程序都将可用。@addTagHelper
之后的第一个字符串指定要加载的标记帮助程序(对所有标记帮助程序使用“*”),第二个字符串“AspNetCoreMVC”指定标记帮助程序所在的程序集。 第3行的代码引入了系统提供的标记帮助程序。如果不想将自定义的所有的标记帮助程序引入,那么第4行代码就该是@addTagHelper AspNetCoreMVC.TagHelpers.MyHtmlTagHelper, AspNetCoreMVC
现在我在about.cshtml中来使用这个标记帮助程序。
注意标签my-html,这个标签绝对不是系统默认的,而是根据MyHtmlTagHelper而来的,至于为什么变成了my-html,有兴趣了可以去了解。info是MyHtmlTagHelper中的属性。看看运行后的效果。运行后,my-html标签变成了div标签
单就这个例子来看,似乎标记帮助程序没什么鸟用,还不如直接在视图中写a标签。那就再多看几个例子,也许会明白什么时候可以考虑用这个了。
例二:
public class MyPTagHelper : TagHelper { //ProcessAsync是Process方法的异步版本 public override async Task ProcessAsync(TagHelperContext context, TagHelperOutput output) { output.TagName = "p";//这里要操作p标签 //这里获取的txt不是output.Content,而是视图中的<my-p>标签。而output.Content是因<my-p>标签而输出的p标签,能理解吗 var txt = await output.GetChildContentAsync(); var target = txt.GetContent() + "+++++"; //设置标签的属性,两种方式都可以 output.Attributes.SetAttribute("style", "color: red"); output.Attributes.Add("class", "p-css-class"); output.Content.SetContent(target); //下面的这条注释的语句和上面的语句的结果不一样,如果用下面的语句,不会影响到最终的输出结果 //txt.SetContent(target); } //public string Content { set; get; } //public override void Process(TagHelperContext context, TagHelperOutput output) //{ // output.TagName = "p"; // output.Attributes.SetAttribute("style", "color: red"); // output.Attributes.Add("class", "p-css-class"); // output.Content.SetContent(Content+"++++"); //} }
在视图中:
<my-p content="这里是自定义标记帮助程序,用同步版本,操作P标签"></my-p>
<my-p>这里是自定义标记帮助程序,用异步版本,操作P标签</my-p>
使用异步版本ProcessAsync的结果:
使用同步版本Process的结果
能看懂这两个版本的区别了吧。
例三:
public class MyTableTagHelper : TagHelper { public IList<Student> datas { set; get; } public override void Process(TagHelperContext context, TagHelperOutput output) { output.TagName = "table"; StringBuilder sb = new StringBuilder("<thead><tr><th>姓名</th><th>年龄</th><th>性别</th><th>地址</th><th>电话</th></tr></thead>"); sb.Append("<tbody>"); foreach (Student s in datas) { sb.Append($"<tr><td>{s.Name}</td><td>{s.Age}</td><td>{s.Sex}</td><td>{s.Address}</td><td>{s.Tel}</td></tr>"); } sb.Append("</tbody>"); output.Content.SetHtmlContent(sb.ToString()); } }
public class Student { public string Name { set; get; } public int Age { set; get; } public int Sex { set; get; } public string Address { set; get; } public string Tel { set; get; } }
控制器:
public IActionResult About() { ViewData["Message"] = "Your application description page."; IList<Student> stus = new List<Student>() { new Student(){Name="张三",Age=30,Sex=1,Address="ajd反对我问我",Tel="151521561"}, new Student(){Name="李四",Age=31,Sex=1,Address="ajd反对我问我",Tel="151521561"}, new Student(){Name="王五",Age=32,Sex=0,Address="ajd反对我问我",Tel="151521561"}, new Student(){Name="周六",Age=33,Sex=1,Address="ajd反对我问我",Tel="151521561"}, new Student(){Name="陈七",Age=34,Sex=0,Address="ajd反对我问我",Tel="151521561"}, new Student(){Name="甄八",Age=35,Sex=1,Address="ajd反对我问我",Tel="151521561"}, new Student(){Name="陆九",Age=36,Sex=1,Address="ajd反对我问我",Tel="151521561"} }; return View(stus); }
视图:
运行结果: