ASP.Net Core -核心组件2
静态文件 js 图片 css等 有三个中间件处理
使用 UseStaticFiles 中间件
public static class Sample01
{
public static void Run()
{
Host.CreateDefaultBuilder()
.ConfigureWebHostDefaults(builder => builder.Configure(
app=>app.UseStaticFiles()))
.Build()
.Run();
}
}
如果不在wwwroot 在其他目录的情况:
public static class Sample02
{
public static void Run()
{
var path = Path.Combine(Directory.GetCurrentDirectory(), "content");
// 静态文件中间件配置
var options = new StaticFileOptions
{
FileProvider = new PhysicalFileProvider(path),
RequestPath = "/content"
};
Host.CreateDefaultBuilder()
.ConfigureWebHostDefaults(builder => builder.Configure(
app=>app
// 静态文件中间件
.UseStaticFiles()
.UseStaticFiles(options)))
.Build()
.Run();
}
}
如何在浏览器中访问某个目录可以出现目录出来?使用目录浏览的中间件 UseDirectoryBrowser
public static class Sample03
{
public static void Run()
{
var path = Path.Combine(Directory.GetCurrentDirectory(), "content");
var fileProvider = new PhysicalFileProvider(path);
var staticFileOptions = new StaticFileOptions
{
FileProvider = fileProvider,
RequestPath = "/content"
};
// 目录浏览中间件配置
var directoryBrowserOptions = new DirectoryBrowserOptions
{
FileProvider = fileProvider,
RequestPath = "/content"
};
Host.CreateDefaultBuilder()
.ConfigureWebHostDefaults(builder => builder.Configure(
app=>app
// 目录浏览中间件
.UseStaticFiles()
.UseStaticFiles(staticFileOptions)
.UseDirectoryBrowser()
.UseDirectoryBrowser(directoryBrowserOptions)))
.Build()
.Run();
}
}
默认页面中间件:
public class Sample04
{
public static void Run()
{
var path = Path.Combine(Directory.GetCurrentDirectory(), "content");
var fileProvider = new PhysicalFileProvider(path);
var staticFileOptions = new StaticFileOptions
{
FileProvider = fileProvider,
RequestPath = "/content"
};
var directoryBrowserOptions = new DirectoryBrowserOptions
{
FileProvider = fileProvider,
RequestPath = "/content"
};
// 默认页面中间件配置
var defaultFilesOptions = new DefaultFilesOptions
{
FileProvider = fileProvider,
RequestPath = "/content"
};
defaultFilesOptions.DefaultFileNames.Add("readme.html");
Host.CreateDefaultBuilder()
.ConfigureWebHostDefaults(builder => builder.Configure(
app => app
// 默认页面中间件,中间件注册时有顺序的 必须要有在前面默认页面中间件
.UseDefaultFiles()
.UseDefaultFiles(defaultFilesOptions)
.UseStaticFiles()
.UseStaticFiles(staticFileOptions)
.UseDirectoryBrowser()
.UseDirectoryBrowser(directoryBrowserOptions)))
.Build()
.Run();
}
}
响应报文能正常被浏览器解析的话需要,终结点路由中间件和终结点中间件
有两种不同的路由方案:传统的路由系统 和 新的路由系统(终结点映射策略)
public static class Sample01 { private static readonly Dictionary<string, string> Cities = new Dictionary<string, string> { ["010"] = "北京", ["027"] = "武汉" }; public static void Run() { // const string template = @"weather/{city:regex(^{0\d{{2,3}}$)}/{days:int:range(1,4)}"; const string template = @"weather/{city}/{days}"; Host.CreateDefaultBuilder() .ConfigureWebHostDefaults(builder => builder //添加路由服务 .ConfigureServices(csv => csv.AddRouting()) //添加路由中间件 .Configure(app => app .UseRouting()//终结点路由中间 .UseEndpoints(endpoints => endpoints.MapGet(template, WeatherForecast))))//终结点中间件 路由模板template映射到WeatherForecast的方法上 MapGet代表使用get方法才能路由到 .Build() .Run(); } /// <summary> /// 请求委托 /// </summary> /// <param name="context"></param> /// <returns></returns> public static async Task WeatherForecast(HttpContext context) { //提取路由中间件,路由解析中涉及的参数 var city = (string) context.GetRouteData().Values["city"]; city = Cities[city]; var days = int.Parse(context.GetRouteData().Values["days"].ToString() ?? string.Empty); var report = new WeatherReport(city, days); await RendWeatherAsync(context, report); } /// <summary> /// 第二个请求委托 /// </summary> /// <param name="context"></param> /// <param name="report"></param> /// <returns></returns> private static async Task RendWeatherAsync(HttpContext context, WeatherReport report) { context.Response.ContentType = "text/html;charset=utf-8"; await context.Response.WriteAsync("<html><head><title>天气</title></head><body>"); await context.Response.WriteAsync($"<h3>{report.City}</h3>"); foreach (var (key, value) in report.WeatherInfos) { await context.Response.WriteAsync($"{key:yyyy-MM-dd}:"); await context.Response.WriteAsync( $"{value.Condition}({value.LowTemperature}℃ ~ {value.HighTemperature}℃)<br/><br/> "); } await context.Response.WriteAsync("</body></html>"); } }
异常处理中间件
因为Asp.net core 同时处理多个请求的web应用框架,纠错误的难度就会加大,就出现了出现了定制化错误消息,呈现出来
开发者提倡页面,500的响应页面,这个时候就会得到一个很笼统的错误提示
public static class Sample01
{
public static void Run()
{
Host.CreateDefaultBuilder()
.ConfigureWebHostDefaults(builder => builder
//这里任何请求都会提示这个异常 提示500,这样不知道绝体原因
.Configure(app => app
.Run(context => Task.FromException(new InvalidOperationException("这是一个异常")))
))
.Build()
.Run();
}
}
直接显示错误页面,一般是给开发者看 ,叫做开发者异常页面中间件
public static class Sample02
{
public static void Run()
{
Host.CreateDefaultBuilder()
.ConfigureWebHostDefaults(builder => builder
.ConfigureServices(services => services.AddRouting())//路由
.Configure(app => app
.UseDeveloperExceptionPage()//开发者异常页面中间件
.UseRouting()
.UseEndpoints(routeBuilder => routeBuilder.MapGet("/", HandleAsync))//终结点中间件 模板是根目录,HandleAsync这个方法是请求处理器
))
.Build()
.Run();
}
private static Task HandleAsync(HttpContext context)
{
return Task.FromException(new InvalidOperationException("This is Exception"));
}
}
但是在给用户的情况下不应该像上面这样,
public static class Sample03
{
public static void Run()
{
//异常处理配置
var options = new ExceptionHandlerOptions
{
ExceptionHandler = context => context.Response.WriteAsync("Hello Exception!")
};
Host.CreateDefaultBuilder()
.ConfigureWebHostDefaults(builder => builder
.Configure(app => app
.UseExceptionHandler(options)//异常处理
.Run(context => Task.FromException(new InvalidOperationException("Throw Exception")))
))
.Build()
.Run();
}
}
直接回提示 Hello Exception! 用户屏蔽敏感信息
public static class Sample04
{
public static void Run()
{
Host.CreateDefaultBuilder()
.ConfigureWebHostDefaults(builder => builder
.Configure(app => app
//使用另外一个重载 ,用于配置一个特有的中间件
.UseExceptionHandler(applicationBuilder => applicationBuilder
.Run(context => context.Response.WriteAsync("Hello Exception!"))
)
.Run(context => Task.FromException(new InvalidOperationException("这是一个异常")))
))
.Build()
.Run();
}
}
public static class Sample05
{
public static void Run()
{
Host.CreateDefaultBuilder()
.ConfigureWebHostDefaults(builder => builder
.ConfigureServices(services => services.AddRouting())
.Configure(app => app
//又是另外一个重载
.UseExceptionHandler("/error")
.UseRouting()
.UseEndpoints(routeBuilder => routeBuilder.MapGet("error", HandleAsync))
//这个是正常的直接设置为报错,然后重定向到/error ===》HandleAsync
.Run(context => Task.FromException(new InvalidOperationException("Throw Exception")))
))
.Build()
.Run();
}
private static Task HandleAsync(HttpContext context)
{
return context.Response.WriteAsync("Hello Exception");
}
}
注意:http通先的错误大体分为两种类型
客户端错误:400~499
服务端错误:表示服务器处理自身问题出现的错误 500~599
所以可以使用状态码页面中间件,后续请求的过程中,产生了一个错误响应状态码,根据不同的状态码显示不同的页面
以下是所有的错误都显示500的情况
public static class Sample06
{
public static void Run()
{
Host.CreateDefaultBuilder()
.ConfigureWebHostDefaults(builder => builder
.Configure(app => app
//响应状态码
.UseStatusCodePages("text/plain", "Error ({0})")
.Run(context => Task.Run(() => context.Response.StatusCode = 500))
))
.Build()
.Run();
}
}
如果我们需要根据不同的状态码设置为不同的页面的时候
public static class Sample07 { private static readonly Random Random = new Random(); public static void Run() { Host.CreateDefaultBuilder() .ConfigureWebHostDefaults(builder => builder .Configure(app => app .UseStatusCodePages(Handler) .Run(context => Task.Run(() => context.Response.StatusCode = Random.Next(400,599))) )) .Build() .Run(); } private static async Task Handler(StatusCodeContext context) { var response = context.HttpContext.Response; if (response.StatusCode < 500) { await response.WriteAsync($"Client Error ({response.StatusCode})"); } else { await response.WriteAsync($"Server Error ({response.StatusCode})"); } } }
客户端重定向方式和服务端重定向
public static class Sample08 { private static readonly Random Random = new Random(); public static void Run() { Host.CreateDefaultBuilder() .ConfigureWebHostDefaults(builder => builder .ConfigureServices(collection => collection.AddRouting())//路由 .Configure(app => app .UseStatusCodePagesWithRedirects("/error/{0}")//带有重定向的状态码中间件 .UseRouting() .UseEndpoints(routeBuilder => routeBuilder.MapGet("error/{status_code}", HandlerError))//通过这个模板获取状态码 .Run(context => Task.Run(() => context.Response.StatusCode = Random.Next(400,599))) )) .Build() .Run(); } private static async Task HandlerError(HttpContext context) { var code = context.GetRouteData().Values["status_code"]; await context.Response.WriteAsync($"Error ({code})"); } }
public static class Sample09 { private static readonly Random Random = new Random(); public static void Run() { Host.CreateDefaultBuilder() .ConfigureWebHostDefaults(builder => builder .ConfigureServices(collection => collection.AddRouting()) .Configure(app => app .UseStatusCodePagesWithReExecute("/error/{0}")//UseStatusCodePagesWithRedirects改为UseStatusCodePagesWithReExecute 就变成服务端重定向 .UseRouting() .UseEndpoints(routeBuilder => routeBuilder.MapGet("error/{status_code}", HandlerError)) .Run(context => Task.Run(() => context.Response.StatusCode = Random.Next(400,599))) )) .Build() .Run(); } private static async Task HandlerError(HttpContext context) { var code = context.GetRouteData().Values["status_code"]; await context.Response.WriteAsync($"Error ({code})"); } }
编译异常信息:在mvc试图文件时可以动态编译的 直接部署视图的,所以由于试图文件是可以动态编译的 ,所以需要编译异常信息
MVC项目中需要添加包 Microsoft.AspNetCore.Mvc.Razor.RuntimeCompilation 同时设置被配表示使用动态编译视图
namespace ConsoleApp4 { class Program { static void Main(string[] args) { var options = new DeveloperExceptionPageOptions { SourceCodeLineCount = 3 }; Host.CreateDefaultBuilder() .ConfigureWebHostDefaults(builder => builder .ConfigureServices(collection => collection .AddRouting() .AddControllersWithViews()//mvc .AddRazorRuntimeCompilation())//启用视图图文件运行时编译的 .Configure(app=>app .UseDeveloperExceptionPage(options) .UseRouting() .UseEndpoints(routeBuilder => routeBuilder.MapControllers())) ) .Build() .Run(); } } public class HomeController : Controller { [HttpGet("/")] public IActionResult Index() => View(); } }
总结 :静态文件中间件(目录浏览,默认页面)
路由 (终结点路由中间件,总结点中间件)
异常中间件 (开发者异常页面,异常处理中间件,响应状态码中间件(客户端重定向,服务器端重定向))
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 提示词工程——AI应用必不可少的技术
· 地球OL攻略 —— 某应届生求职总结
· 字符编码:从基础到乱码解决
· SpringCloud带你走进微服务的世界