【Asp.Net.Core】【Routing】

129 阅读2分钟

概述

这里可以和JAVA中的路径映射进行对应,将对应的HTTP请求和要执行的方法进行映射。

image.png 使用方式如下:

image.png

Map(),MapGet(),MapPost()

var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();

//enable routing
app.UseRouting();
app.UseEndpoints(endpoints =>{
    //add your endpoints
    
    endpoints.Map("/map1",async (context) =>
    {
        await context.Response.WriteAsync("in map 1");
    });
    endpoints.MapPost("/map2", async (context) =>
    {
        await context.Response.WriteAsync("in map 2");
    });
    endpoints.MapGet("/map3", async (context) =>
    {
        await context.Response.WriteAsync("in map 3");
    });
});

app.Run(async context =>
{
    await context.Response.WriteAsync($"Request received at{context.Request.Path}");
});

app.Run();

当请求路径与设定的URL相同时,Map()方法可以接收到GetPost请求方法,但是MapGet()只能接收到get请求方法,同理,MapPost()只能接收post请求方法。

GetEndpoint

只有在使用了UseRouting()方法之后,GetEndPoint()才会有对象,EndPoint对象中包含了DisplayName,也就是URL,RequestDelegate是要执行的EndPoint方法。

image.png

using Microsoft.AspNetCore.Http;

var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();

app.Use(async (context, next) =>
{
    Endpoint? endpoint = context.GetEndpoint();   //得到的是null
    if(endpoint != null)
    {
        await context.Response.WriteAsync($"Endpoint: " +
           $"{endpoint.DisplayName}\n");
    }
    
    await next(context);
});

//enable routing
app.UseRouting();

app.Use(async (context, next) =>
{
    Endpoint? endpoint = context.GetEndpoint();
    if (endpoint != null)
    {
        await context.Response.WriteAsync($"Endpoint: " +
           $"{endpoint.DisplayName}\n");
        //URL中请求map1, 得到的输出是:
        //Endpoint: /map1
        //in map 1
    }

    await next(context);
});
app.UseEndpoints(endpoints =>{
    //add your endpoints
    
    endpoints.Map("/map1",async (context) =>
    {
        await context.Response.WriteAsync("in map 1");
    });
    endpoints.MapPost("/map2", async (context) =>
    {
        await context.Response.WriteAsync("in map 2");
    });
    endpoints.MapGet("/map3", async (context) =>
    {
        await context.Response.WriteAsync("in map 3");
    });
});
app.Run(async context =>
{
    await context.Response.WriteAsync($"Request received at{context.Request.Path}");
});


app.Run();

请求路径参数

真实请求路径如下:

/files/sample.txt
/employee/profile/john

在请求路径中,有一些部分是fixed 不变的,可变的部分我们称为路径参数,因此,上边请求路径可以改写为:

/files/{filename}.{extention}
/employee/profile/{employeeName}

代码中可以这样写

using Microsoft.AspNetCore.Http;

var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();

//enable routing
app.UseRouting();

//creating endpoints
app.UseEndpoints(endpoints =>
{
    //add your endpoints
    endpoints.Map("file/{filename}.{extention}", async context =>
    {
        string? fileName = Convert.ToString(context.Request.RouteValues["filename"]);
        string? extention = Convert.ToString(context.Request.RouteValues["extention"]);
        await context.Response.WriteAsync($"In file:{fileName}-{extention}");
    });
    
    //给默认值
    endpoints.Map("employee/profile/{employeeName=harsha}", async context =>
    {
        string? employeeName = Convert.ToString(context.Request.RouteValues["employeeName"]);
        await context.Response.WriteAsync($"employeeName: {employeeName}");
    });
    
    //id项可有可无
    endpoints.Map("products/details/{id?}", async context =>
    {
        if (context.Request.RouteValues.ContainsKey("id"))
        {
            int? id = Convert.ToInt32(context.Request.RouteValues["id"]);
            await context.Response.WriteAsync($"products details -: {id}");
        }
        else
        {
            await context.Response.WriteAsync($"products details -: id is not supplied");
        }
        
    });
});
app.Run(async context =>
{
    await context.Response.WriteAsync($"Request received at{context.Request.Path}");
});


app.Run();

如果想要给默认值,参考代码中profile那一行,如果参数可以有,也可以没有,参考product那一行。

请求路径参数的一些限制

例如 id值我们只想要接收int类型;employeeName我们只想要接收string类型。请求路径后边加上类型限制。

image.png

image.png

image.png

image.png

image.png

image.png

代码示例

using Microsoft.AspNetCore.Http;

var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();

//enable routing
app.UseRouting();

//creating endpoints
app.UseEndpoints(endpoints =>
{
    //add your endpoints
    endpoints.Map("file/{filename}.{extention}", async context =>
    {
        string? fileName = Convert.ToString(context.Request.RouteValues["filename"]);
        string? extention = Convert.ToString(context.Request.RouteValues["extention"]);
        await context.Response.WriteAsync($"In file:{fileName}-{extention}");
    });

    endpoints.Map("employee/profile/{employeeName:length(4,7)=harsha}", async context =>
    {
        string? employeeName = Convert.ToString(context.Request.RouteValues["employeeName"]);
        await context.Response.WriteAsync($"employeeName: {employeeName}");
    });

    endpoints.Map("products/details/{id:int:range(1,1000)?}", async context =>
    {
        if (context.Request.RouteValues.ContainsKey("id"))
        {
            int? id = Convert.ToInt32(context.Request.RouteValues["id"]);
            await context.Response.WriteAsync($"products details -: {id}");
        }
        else
        {
            await context.Response.WriteAsync($"products details -: id is not supplied");
        }
        
    });

    endpoints.Map("/daily-digest-report/{reportdate:datetime}", async context =>
    {
       DateTime reportDate = Convert.ToDateTime(context.Request.RouteValues["reportdate"]);
       await context.Response.WriteAsync($"dateTime - {reportDate}");
    });

    endpoints.Map("/cities/{cityid:guid}", async context =>
    {
         Guid cityid = Guid.Parse(Convert.ToString(context.Request.RouteValues["cityid"])!);
        await context.Response.WriteAsync($"cityId - {cityid}");
    });

    endpoints.Map("sales-report/{year:int:min(1900)}/month:regex(^(apr|jul|oct|jan)$)", async context =>
    {
        int year = Convert.ToInt32(context.Request.RouteValues["year"]);
        string? month = Convert.ToString(context.Request.RouteValues["month"]);

        await context.Response.WriteAsync($"sales report - {year} - {month}");

    });

});
app.Run(async context =>
{
    await context.Response.WriteAsync($"Request received at{context.Request.Path}");
});


app.Run();

在真实工程项目中,可以不适用参数限制,对于输错的信息,可以给用户提示输入的信息是错误的。

当一个限制条件在项目中被多次使用,可以创建一个类。

image.png

image.png

  1. 创建类
using System.Text.RegularExpressions;

namespace RoutingExample.customConstraint
{
    //sales-report/2020/apr
    public class MonthCustomConstraint : IRouteConstraint
    {
        public bool Match(HttpContext? httpContext, IRouter? route, string routeKey, RouteValueDictionary values, RouteDirection routeDirection)
        {
            //check whether the value exists
            if (!values.ContainsKey(routeKey))  //month
            {
                return false;
            }

            Regex regex = new Regex("^(apr|jul|oct|jan)$");
            string? monthValue = Convert.ToString(values[routeKey]);
            if (monthValue != null && regex.IsMatch(monthValue))
            {
                return true;  //it is a Match
            }
            return false;

        }
    }
}
  1. 添加服务
//添加限制类
builder.Services.AddRouting(options =>
{
    options.ConstraintMap.Add("months", typeof(MonthCustomConstraint));
});

  1. 使用
 endpoints.Map("sales-report/{year:int:min(1900)}/{month:months}", async context =>
 {
     int year = Convert.ToInt32(context.Request.RouteValues["year"]);
     string? month = Convert.ToString(context.Request.RouteValues["month"]);

     await context.Response.WriteAsync($"sales report - {year} - {month}");

 });

Endpoint Selection Order

image.png

使用静态文件

image.png

  1. 创建文件夹

image.png

2.开启使用静态文件

r app = builder.Build();

app.UseStaticFiles();

app.UseRouting();
app.UseEndpoints(endpoints =>{
    endpoints.Map("/", async context =>{
        await context.Response.WriteAsync("Hello");
    });
});

app.Run();

3.浏览器直接访问静态资源,可以看到静态资源

image.png

若想修改wwwroot名字该怎么办?

  1. 修改名字:

image.png

  1. 添加配置
var builder = WebApplication.CreateBuilder(new
    WebApplicationOptions()
{
    WebRootPath = "myroot"
});

若想添加多个静态资源文件夹该怎么办?

  1. 添加文件夹 image.png

  2. 添加代码

using Microsoft.Extensions.FileProviders;

var builder = WebApplication.CreateBuilder(new
    WebApplicationOptions()
{
    WebRootPath = "myroot"
});
var app = builder.Build();
app.UseStaticFiles();  //works with web root path (myroot)
app.UseStaticFiles(new StaticFileOptions()
{
    FileProvider = new PhysicalFileProvider(Path.Combine(builder.Environment.ContentRootPath,"myWebroot"))
});  //works with "mywebroot"
  1. 访问静态资源

image.png