配置静态文件路径_.NetCore一周集训(四):应用配置、日志、路由和静态文件...

04 应用配置、日志、路由和静态文件

应用配置

在开发过程中,有些时候我们都会有配置应用的需求。

在 ASP.NET 中,我们一般使用 Web.config 来进行配置。但是在 ASP.NET Core 中 ,你们会发现 Web.config 已经没了,因为它被 appsettings.json 这个配置文件取代了。

基本用法

如果你还记得前两节课内容的话,你应该知道在主机创建后,服务容器里就已经为我们默认注册了一些服务,其中一个就是 IConfiguration 服务。

这个服务可以被注入到Startup类的构造函数中,它为我们提供了应用配置相关的服务。

假设有如下配置项:

// 键不区分大小写。例如,`ConnectionString` 和 `connectionstring` 被视为等效键。"ConnectionString": "data source=.;initial catalog=db;user id=sa","WebSetting": {    "WebName": "ASP.NET Core",    "Title": "Hello Title",    "Behavior": {        "IsCheckIp": true,        "MaxConnection":  300      }}

首先,创建Startup类的构造函数,并注入  IConfiguration

private readonly IConfiguration _configuration;public Startup(IConfiguration configuration){    _configuration = configuration;}

之后,就可以在任何一个方法中使用它了

app.Run(async context =>        {            var connStrDefault = _configuration.GetConnectionString("default");            var connStr = _configuration["connectionString"];            var title = _configuration["WebSetting:Title"];            var isCheckIp = _configuration["WebSetting:Behavior.IsCheckIp"];            await context.Response.WriteAsync($"{connStrDefault}\r connStr \r title \r isCheckIp");        });
绑定配置模型对象

使用字符串键名获取配置值很不优雅,也容易出错。我们可以把配置项绑定到对象。

首先,创建配置项结构对应的配置模型。

public class Behavior{    public bool IsCheckIp { get; set; }    public int MaxConnection { get; set; }}public class WebSetting{    public string WebName { get; set; }    public string Title { get; set; }    public Behavior Behavior { get; set; }}public class AppSetting{    public string ConnectionString { get; set; }    public WebSetting WebSetting { get; set; }}

然后,创建配置模型对象,并通过 IConfiguration 服务绑定

// 全部绑定var appSetting = new AppSetting();_configuration.Bind(appSetting);// 部分绑定var behavior = new Behavior();_configuration.GetSection("Behavior").Bind(behavior);app.Run(async context =>        {            var connStrDefault = appSetting.ConnectionString;            var title = appSetting.WebSetting.Title;            var isCheckIp = appSetting.WebSetting.Behavior.IsCheckIp;            var maxConnection = appSetting.WebSetting.Behavior.MaxConnection;            await context.Response.WriteAsync($"{connStrDefault} \r {title} \r {isCheckIp} \r {maxConnection}");        });
注册配置选项

首先,在 ConfigureServices 方法中,注册AppSetting绑定的配置服务

services.Configure<AppSetting>(_configuration);

然后,在需要的地方利用参数把IOptions注入进来:

public void Configure(IApplicationBuilder app, IWebHostEnvironment env, IOptions<AppSetting> appOptions){    app.Run(async context =>            {                var connStrDefault = appOptions.Value.ConnectionString;                var title = appOptions.Value.WebSetting.Title;                var isCheckIp = appOptions.Value.WebSetting.Behavior.IsCheckIp;                var maxConnection = appOptions.Value.WebSetting.Behavior.MaxConnection;                await context.Response.WriteAsync($"{connStrDefault} \r {title} \r {isCheckIp} \r {maxConnection}");            });}
自定义配置文件

有的时候配置参数可能会比较很多,想放在单独的文件中进行配置。

创建customSetting.json配置文件,假设有如下配置:

{  "Name": "Rick",  "Age": 99}

首先,在 ConfigureServices 方法中,创建配置生成器,添加customSetting.json文件,注册CustomSetting绑定的配置服务

var config = new ConfigurationBuilder()
.AddJsonFile("customSetting.json")
.Build();
services.Configure(config);

然后,在需要的地方利用参数把IOptions注入进来:

public void Configure(IApplicationBuilder app, IWebHostEnvironment env, IOptions appOptions, IOptions customOptions)
{
var name = customOptions.Value.Name;
var age = customOptions.Value.Age;
}

多环境

ASP.NET Core 在应用启动时读取环境变量 ASPNETCORE_ENVIRONMENT,并将该值存储在 IWebHostEnvironment.EnvironmentName 中。

ASPNETCORE_ENVIRONMENT 可设置为任意值,但框架提供三个值:

  • Development (开发)

  • Staging(演示、预览)

  • Production(生产)

// 可以获取IWebHostEnvironment,判断不同的环境
if (env.IsProduction() || env.IsStaging() || env.IsEnvironment("Demo"))
{
// 要加载的中间件
}

Startup方法多环境

ConfigureServices方法和Configure方法,可以为不同的环境单独定义单独方法。

运行时会优先调用方法中环境名与当前环境匹配的方法。如果找不到匹配的方法,就会使用调用默认方法。

www.public void ConfigureDemoServices(IServiceCollection services)
{
}
public void ConfigureDemo(IApplicationBuilder app, IWebHostEnvironment env)
{
app.Run(async context => { await context.Response.WriteAsync("ConfigureDemo"); });
}

Startup类多环境

还可以为不同的环境定义单独的 Startup 类(例如 StartupDevelopment)。

运行时会选择Startup类名后缀与当前环境名称匹配的Startup类。如果找不到匹配的 Startup{EnvironmentName},就会使用 Startup 类。

当应用需要为各环境之间存在许多代码差异的多个环境配置启动时,这种方法非常有用。

 public class StartupDevelopment
{
public void ConfigureServices(IServiceCollection services)
{
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
app.Run(async context => { await context.Response.WriteAsync("StartupDevelopment"); });
}
}
public class StartupProduction
{
public void ConfigureServices(IServiceCollection services)
{
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
app.Run(async context => { await context.Response.WriteAsync("StartupProduction"); });
}
}

修改主机配置启动类

        public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureWebHostDefaults(webBuilder =>
{
//webBuilder.UseStartup();
webBuilder.UseStartup(Assembly.GetExecutingAssembly().FullName);
});

日志

日志是使用频率最高的东西了,给我们开发调试程序提供了必要的信息。

ASP.NET Core中内置了一个通用日志接口ILogger,虽然实现了多种内置的日志提供程序,例如

  • Console

  • Debug

  • EventSource

  • EventLog

但内置的日志提供程序不支持记录到文件(只有Linux下才会)和数据库。

我们可以在ASP.Net Core中自由的指定日志提供程序,并将日志发送到指定的位置。

在我们创建主机时, WebHost.CreateDefaultBuilder方法默认添加了2个日志提供器(控制台和DEBUG输出),并且默认读取appsetting.json配置文件中的配置。

日志级别

ASP.NET Core中提供了6种日志级别(按严重性从低到高排列)。

  • 跟踪 = 0

    有关通常仅用于调试的信息。这些消息可能包含敏感应用程序数据,因此不得在生产环境中启用它们。默认情况下禁用。

  • 调试 = 1

    有关在开发和调试中可能有用的信息。示例:Entering method Configure with flag set to true. 由于日志数量过多,因此仅当执行故障排除时,才在生产中启用 Debug 级别日志。

  • 信息 = 2

    用于跟踪应用的常规流。这些日志通常有长期价值。示例:Request received for path /api/todo

  • 警告 = 3

    表示应用流中的异常或意外事件。可能包括不会中断应用运行但仍需调查的错误或其他条件。Warning 日志级别常用于已处理的异常。示例:FileNotFoundException for file quotes.txt.

  • 错误 = 4

    表示无法处理的错误和异常。这些消息指示的是当前活动或操作(例如当前 HTTP 请求)中的失败,而不是整个应用中的失败。日志消息示例:Cannot insert record due to duplicate key violation.

  • 严重 = 5

    需要立即关注的失败。例如数据丢失、磁盘空间不足。

创建日志

我们需要通过依赖注入获取一个实现ILogger的泛型接口对象,我们可以用刚才创建的中间件试验。

 public async Task InvokeAsync(HttpContext httpContext, ILogger logger)
{
// ILogger为了提供了6个可用的输出日志方法,分别对应了6个不同的日志级别
logger.LogDebug($"Path:{httpContext.Request.Path}");
await httpContext.Response.WriteAsync($"Path:{httpContext.Request.Path}");
await _next(httpContext);
}
手动添加日志提供器

我们只需要在Program.cs中使用ConfigureLogging方法就可以配置我们需要的日志提供程序了。

public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureLogging(builder => builder.AddEventLog())
.ConfigureWebHostDefaults(webBuilder =>
{
webBuilder.UseStartup();
});

除了在Program.cs添加日志提供器之外,我们还可以在Startup.cs中添加日志提供器。

在Startup.cs中,我们可以为Configure方法添加第三个参数ILoggerFactory loggerFactory, 并使用该参数添加日志提供器。

public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
loggerFactory.AddConsole();
loggerFactory.AddDebug();
}
集成NLog
  1. 使用Nuget安装NLog和NLog.Web.AspNetCore

  2. 创建 nlog.config 配置文件

    <?xml version="1.0" encoding="utf-8" ?>      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    autoReload="true"
    internalLogLevel="Info"
    internalLogFile="c:\temp\internal-nlog.txt"> layout="${longdate}|${event-properties:item=EventId_Id}|${uppercase:${level}}|${logger}|${message} ${exception:format=tostring}" /> layout="${longdate}|${event-properties:item=EventId_Id}|${uppercase:${level}}|${logger}|${message} ${exception:format=tostring}|url: ${aspnet-request-url}|action: ${aspnet-mvc-action}" />
  3. 更改 program.cs

    using System;
    using NLog.Web;
    using Microsoft.AspNetCore.Hosting;
    using Microsoft.Extensions.Logging;
    using Microsoft.Extensions.Hosting;
    public static void Main(string[] args)
    {
    var logger = NLog.Web.NLogBuilder.ConfigureNLog("nlog.config").GetCurrentClassLogger();
    try
    {
    logger.Debug("init main");
    CreateHostBuilder(args).Build().Run();
    }
    catch (Exception exception)
    {
    //NLog: catch setup errors
    logger.Error(exception, "Stopped program because of exception");
    throw;
    }
    finally
    {
    // Ensure to flush and stop internal timers/threads before application-exit (Avoid segmentation fault on Linux)
    NLog.LogManager.Shutdown();
    }
    }
    public static IHostBuilder CreateHostBuilder(string[] args) =>
    Host.CreateDefaultBuilder(args)
    .ConfigureWebHostDefaults(webBuilder =>
    {
    webBuilder.UseStartup();
    })
    .UseNLog(); // NLog: Setup NLog for Dependency injection

异常处理

ASP.NET Core 默认提供了一个DeveloperExceptionPage中间件,由于它的异常信息比较敏感,所以只适合在开发环境下;如果再生产环境下,我们可能想自定义异常处理,比如显示一个异常友好页面,那我们可以这么做。

			// 检查当前环境名称是不是Development
if (env.IsDevelopment())
{
// 开发人员异常页面中间件
app.UseDeveloperExceptionPage();
}
else
{
// 自定义异常页面
app.UseExceptionHandler("/Error");
app.Map("/Error", ErrorHandle);
}
if (env.IsProduction() || env.IsStaging() || env.IsEnvironment("Demo"))
{
app.UseExceptionHandler("/Error");
app.Map("/Error", ErrorHandle);
}
// 测试异常页面
app.Run(context =>
{
throw new Exception("Error");
});

还可以封装一个异常处理中间件,这样就可以统一处理异常,比如记录日志,发送告警邮件什么的

ASP.NET Core 约定中间件类必须包括:

  • 具有类型为 RequestDelegate 的参数的公共构造函数

    • RequestDelegate 就是请求委托

  • 名为 Invoke 或 InvokeAsync 的公共方法,此方法必须满足两个条件

    • 返回 Task;

    • 接受类型 HttpContext 的第一个参数

public class CustomExceptionMiddleware
{
private readonly RequestDelegate _next;
public CustomExceptionMiddleware(RequestDelegate next)
{
_next = next;
}
public Task InvokeAsync(HttpContext context, ILogger logger)
{
try
{
return _next(context);
}
catch (Exception e)
{
// 异常处理
logger.LogError(e.Message);
context.Response.StatusCode = (int)HttpStatusCode.InternalServerError;
return context.Response.WriteAsync(e.Message);
}
}
}

创建添加中间件扩展方法

public static class CustomMiddlewareExtensions
{
public static IApplicationBuilder UseCustomException(this IApplicationBuilder app)
{
return app.UseMiddleware();
}
}

路由

路由负责将请求地址映射到终结点。并向这些终结点传入的请求,可以把终结点理解为MVC 控制器中的Action。

路由还能根据配置好的路由信息,生成映射到某个终结点的地址。

路由中间件

ASP.NET Core 3.0 使用了更加完善的终结点(端点)路由,以便对应用程序内的路由提供更多的控制。

端点就是HTTP请求根地址后面的那部分,

两个中间件之间,是可以设置其他中间件的,在这之间的中间件可以利用来自端点路由中间件的路由信息,处理一些其它逻辑,比如授权。

在ASP.NET Core 2.x 中是没有这两个东西的,3.0 版本把路由部分独立了出来,这是因为不管是MVC、Web API、Razor Pages、SingelR,本就可以使用同一套路由逻辑,它们不同的只是端点。分成两个部分,就可以达到复用统一的目的,只需要为不同的框架设置不同的端点即可。

 			// 负责匹配请求和配置的路由,并把解析出来的路由信息写进请求,以供下一个中间件使用
app.UseRouting();
app.UseAuthorization();
// 负责配置路由端点和中间件,根据路由信息调用相应的中间件
app.UseEndpoints(endpoints =>
{
endpoints.MapGet("/", async context =>
{
await context.Response.WriteAsync("Hello World!");
});
});

在UseEndpoints中,是可以配置多种路由端点,ASP.NET Core 提供了一组用于创建端点的扩展方法

		   app.UseEndpoints(endpoints =>
{
// MVC
endpoints.MapControllerRoute(
name: "default",
pattern: "{controller=Home}/{action=Index}/{id?}");
// Web API
endpoints.MapControllers();
});

静态文件

ASP.NET Core Web应用中,静态文件的功能需要静态文件中间件提供支持。

静态文件存储在项目的 Web 根目录中。默认目录是 {content root}/wwwroot,但可通过 UseWebRoot 方法更改目录 。

public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
app.UseStaticFiles();
}
libman

库管理器 (LibMan) 是一个轻量型客户端(前端)库获取工具。LibMan 可从文件系统或从内容分发网络 (CDN) 下载前端库和框架。支持的 CDN 包括 CDNJS、jsDelivr 和 unpkg。

LibMan 提供以下优势:

  • 只会下载所需的库文件。

  • 无需使用其他工具(例如 Node.js、npm 和 WebPack),即可获取库中文件的子集。

  • 可将文件放置在特定位置,无需执行生成任务,也不需手动进行文件复制。

捆绑和压缩

绑定和压缩指的是Web应用的静态文件,它们起到了性能优化的功能。

捆绑

绑定就是将多个静态文件合并到一个静态文件中,绑定可减少请求数量。

压缩

压缩就是在不影响静态文件提供的功能的情况下,删除其中不必要的字符。

配置捆绑和压缩

使用 Nuget 添加 BuildBundlerMinifier 包,然后,创建bundleconfig.json配置文件

[
{
"outputFileName": "wwwroot/css/site.min.css",
"inputFiles": [
"wwwroot/css/site.css"
]
},
{
"outputFileName": "wwwroot/js/site.min.js",
"inputFiles": [
"wwwroot/js/site.js"
],
"minify": {
"enabled": true
}
}
]

outputFileName:要输出的绑定文件的名称。inputFiles:要捆绑在一起的文件的数组。minify:压缩选项。可选,默认值minify: { enabled: true }

7305671d7325443d44869579308d3827.gif

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值