ASP.NET Core教程-Routing(路由)

news2024/10/6 20:33:07

更新记录
转载请注明出处:
2022年11月21日 发布。
2022年11月20日 从笔记迁移到博客。

Route Basic(路由基础)

路由说明

请求URL映射到控制器方法的过程,这个映射过程由路由规则定义。

路由功能

跟据预先配置的路由信息对客户端传来的请求进行路由映射,映射完成后再将请求传给对应的模块处理,比如:指定的Controller处理。 ASP.NET Core 提供创建路由及路由处理器的接口,要创建路由,首先要先添加路由中间件,然后配置路由相关的服务。

路由的类型

ASP.NET Core中两种路由

  • 常规路由
  • 特性路由

常规路由特性路由 对比:

  • 特性路由修饰在Controller和Action上,特性路由有更多的灵活性。

  • 常规路由一般用于设置HTML控制器的映射。

  • 特性路由一般用于设置RESTful API控制器的映射。

  • 常规路由和特性路由可以混用。

默认路由规则

在Startup.cs文件中的Startup类中Configure()方法中,可以看到UseMvcWithDefaultRoute()中间件,这是启动默认MVC路由的功能。这会给ASP.NET Core添加默认路由规则。

{controller}/{action}/{id?}
//默认映射规则
// {controller}映射到控制器
// {action}映射到控制器的方法
// {id?}映射到控制器方法的参数,称为模型绑

Configure()方法:

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

如果需要自定义映射规则,可以使用UseEndpoints()中间件来设置端点,然后在端点中设置如何映射

public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
    app.UseMvcWithDefaultRoute();
    app.UseEndpoints(endpoints =>
    {
        endpoints.MapControllerRoute(
            name: "default",
            pattern: "{controller=Home}/{action=Index}/{id?}");
    });
}

Route Middleware(路由中间件)

UseRouting()中间件

使用UseRouting()中间件启用路由功能。然后使用UseEndpoints()中间件配置路由功能。

UseRouting注册了路由中间件,负责根据请求信息匹配路由定义。路由信息定义包含了路由的处理程序信息,这些信息会在UseEndpoints方法中预先注册生成。当一个请求到达时,路由中间件匹配到MvcEndpointInfo后,后续的中间件就可以根据这些信息进行处理。例如,身份认证中间件可以判断Endpoint对应的处理程序是否要求身份认证,进而进行认证操作。当这些中间件处理完毕后,如果请求未被返回,则由EndpointMiddleware直接调用Endpoint对应的处理程序,从而完成整个请求的处理。基于终结点路由的设计,理论上可以定义任意的路由匹配规则和处理程序。

image

实例:

public class Startup
{

    public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
    {
        //启用路由功能
        app.UseRouting();
        ...
        //配置路由端点
        app.UseEndpoints(endpoints =>
        {
            //具体的路由配置项
            endpoints.MapControllers();
        });
    }
}

UseEndpoints()中间件

使用UseRouting()中间件启用路由功能。然后使用UseEndpoints()中间件配置路由功能。路由中间件UseEndpoints()是ASP.NET Core新增功能。
路由中间件UseEndpoints()的核心点是:EndpointRouting(终结点路由)。路由中间件UseEndpoints()会代替原有的路由规则和模板,可以跨越不同中间件系统,所以可以用在MVC、Razor Pages、Blazor、SignalR、gRPC中。推荐使用路由中间件UseEndpoints()来设置路由。

app.UseEndpoints(endpoints =>{
                     //注册Web API Controller
                     endpoints.MapControllers();
                     //注册MVC Controller模板 {controller=Home}/{action=Index}/{id?}
                     endpoints.MapDefaultControllerRoute();
                     //注册RazorPages
                     endpoints.MapRazorPages();
                     //注册Blazor Hub
                     endpoints.MapBlazorHub();
                     //注册SignalR Hub
                     endpoints.MapHub<MySignalHub>();
                     //注册Grpc服务终结点
                     endpoints.MapGrpcService<OrderService>();
                     //注册健康检查
                     endpoints.MapHealthChecks("/ready");
                 });

实例:自定义配置

public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
    app.UseEndpoints(endpoints =>
    {
        endpoints.MapControllerRoute(
            //路由名称
            name: "default",
            //路由规则
            pattern: "{controller=Home}/{action=Index}/{id?}",
		   //默认值(方式二)
        	defaults: new{ controller = "Home", action = "Index" , id = 888 },
        	//路由约束
            constraints: new{ id = new IntRouteConstraint() }
        );
        
        endpoints.MapControllerRoute(
            name: "panda",
            pattern: "{Panda}/{action}/{id?}");
    	});
}

实例:配置默认路由规则

public class Startup
{
    ...
    
    public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
    {
        //启用路由功能
        app.UseRouting();
        ...
        //配置路由端点
        app.UseEndpoints(endpoints =>
        {
            //配置默认的路由规则
            endpoints.MapControllerRoute("default", "{controller}/{action}/{id?}");
        });
    }
}

Rote Match(路由匹配)

URL 段变量

URL 段变量基本使用

在URL中可以直接使用固定的字符匹配,也称为静态段,也称为路由参数,比如:

/PandaController/PandaAction/PandaArgument

也可以使用称为段变量,使用指定的模式进行匹配

/{first}/{second}/{third}

实例:

app.UseEndpoints(endpoints =>
{
    endpoints.MapGet("{first}/{second}/{third}", async context =>
    {
        await context.Response.WriteAsync("开始-路由信息");
        foreach (var keyValuePair in context.Request.RouteValues)
        {
            await context.Response.WriteAsync($"{keyValuePair.Key}-{keyValuePair.Value}\n");
        }
        await context.Response.WriteAsync("结束-路由信息");
    });
});

URL 段变量设置默认值

在段变量中直接指定默认值即可

{Key=defaultValue}

实例:

app.UseEndpoints(endpoints =>
{
    //设置映射
    endpoints.MapGet("/Panda/{Key=defaultValue}", async context =>
    {
        await context.Response.WriteAsync("Panda666");
    });
});

URL 段变量设置可选段

在段变量中加上?即可。

{Key?}

实例:

app.UseEndpoints(endpoints =>
{
    //设置映射
    endpoints.MapGet("/Panda/{Key?}", async context =>
    {
        await context.Response.WriteAsync("Panda666");
    });
});

默认情况下可选段匹配较短的URL路径。如果需要匹配更多的URL。可以加上catchall段。

app.UseEndpoints(endpoints =>
{
    //设置映射
    endpoints.MapGet("/Panda/{*catchall}", async context =>
    {
        await context.Response.WriteAsync("Panda666");
    });
});

路由约束(Routing constraints)

路由约束说明

路由约可以使用:常规路由的Constraints参数方式、行内简写方式。

常规路由的Constraints参数方式

使用constraints参数即可。配置起来比较麻烦,一般使用行内简写。

public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
    app.UseEndpoints(endpoints =>
    {
        endpoints.MapControllerRoute(
            //路由名称
            name: "default",
            //路由规则
            pattern: "{controller=Home}/{action=Index}/{id?}",
		   //默认值(方式二)
        	defaults: new{ controller = "Home", action = "Index" , id = 888 },
        	//路由约束
            constraints: new{ id = new IntRouteConstraint() }
        );
        
        endpoints.MapControllerRoute(
            name: "panda",
            pattern: "{Panda}/{action}/{id?}");
    	});
}

行内简写方式路由匹配约束

应用约束的方式是使用冒号(😃,在段变量名称后加上即可。可以组合多个约束进行处理路由约束。

/{first:int}/{second:bool}

官方文档:https://docs.microsoft.com/en-us/aspnet/core/fundamentals/routing?view=aspnetcore-6.0#route-constraints

ConstraintDescription
alphaThis constraint matches the letters a to z (and is case-insensitive).
boolThis constraint matches true and false (and is case-insensitive).
datetimeThis constraint matches DateTime values, expressed in the nonlocalized invariant culture format.
decimalThis constraint matches decimal values, formatted in the nonlocalized invariant culture.
doubleThis constraint matches double values, formatted in the nonlocalized invariant culture.
fileThis constraint matches segments whose content represents a file name, in the form name.ext. The existence of the file is not validated.
floatThis constraint matches float values, formatted in the nonlocalized invariant culture. guid This constraint matches GUID values.
intThis constraint matches int values.
length(len)This constraint matches path segments that have the specified number of characters.
length(min, max)This constraint matches path segments whose length falls between the lower and upper values specified.
longThis constraint matches long values.
max(val)This constraint matches path segments that can be parsed to an int value that is less than or equal to the specified value.
maxlength(len)This constraint matches path segments whose length is equal to or less than the specified value.
min(val)This constraint matches path segments that can be parsed to an int value that is more than or equal to the specified value.
minlength(len)This constraint matches path segments whose length is equal to or more than the specified value. nonfile This constraint matches segments that do not represent a file name, i.e., values that would not be matched by the file constraint.
range(min, max)This constraint matches path segments that can be parsed to an int value that falls between the inclusive range specified.
regex(expression)This constraint applies a regular expression to match path segments.

实例:基本约束

app.UseEndpoints(endpoints =>
{
    //设置映射
    endpoints.MapGet("/Panda/{arg:bool}", async context =>
    {
        await context.Response.WriteAsync("Panda666");
    });
});

实例:组合约束

app.UseEndpoints(endpoints =>
{
    //设置映射
    endpoints.MapGet("/Panda/{arg:alpha:length(3)}", async context =>
    {
        await context.Response.WriteAsync("Panda666");
    });
});

实例:匹配正则表达式

app.UseEndpoints(endpoints =>
{
    //设置映射
    endpoints.MapGet("/Panda/{arg:regex(^panda|dog|cat$)}", async context =>
    {
        await context.Response.WriteAsync("Panda666");
    });
});

自定义路由约束(Custom constraints)

通过实现 IRouteConstraint 接口来实现自定义约束。然后通过 Match 方法来设置是否匹配路由。

using System;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Routing;

namespace PandaTest.RouteConstraint
{
    public class PandaRouteConstraint : IRouteConstraint
    {
        public bool Match(HttpContext? httpContext, IRouter? route, string routeKey, RouteValueDictionary values, RouteDirection routeDirection)
        {
            switch (values[routeKey])
            {
                case "v1":
                    return true;
                case "v2":
                    return true;
            }

            return false;
        }
    }
}

在服务中加入自定义路由约束

builder.Services.Configure<RouteOptions>(options => {
    options.ConstraintMap.Add("Panda", typeof(PandaRouteConstraint));
});

使用自定义约束

app.UseEndpoints(endpoints =>
{
    //设置映射
    endpoints.MapGet("/Test/{arg:Panda}", async context =>
    {
        await context.Response.WriteAsync("Matched");
    });
});

路由优先级

说明

默认情况下,特性路由的优先级高于常规路由。

常规路由按从上到下(优先级从高到低),先匹配则优先。

修改优先级-常规路由

路由中间件为每个路由分配一个分数。如果两条路由的分数相同,就会出现歧义。这是就要设置路由优先级。

比如:

app.UseEndpoints(endpoints => {
    endpoints.Map("{number:int}", async context => {
        await context.Response.WriteAsync("Routed to the int endpoint");
    });
    endpoints.Map("{number:double}", async context => {
        await context.Response
        .WriteAsync("Routed to the double endpoint");
    });
});

加入优先级后:

app.UseEndpoints(endpoints => {
    endpoints.Map("{number:int}", async context => {
        await context.Response.WriteAsync("Routed to the int endpoint");
    }).Add(b => ((RouteEndpointBuilder)b).Order = 1);

    endpoints.Map("{number:double}", async context => {
        await context.Response.WriteAsync("Routed to the double endpoint");
    }).Add(b => ((RouteEndpointBuilder)b).Order = 2);
});

修改优先级-特性路由

[Route("api/[Controller]")]
public class PandaController: Controller
{
    //Get api/[Controller]/{id}
    [HttpGet("{id:guid}")]
    [HttpGet("{id:guid}", Order = -1)]
    public string Get(Guid id)
    {
        
    }
}

Attribute routing(特性路由)

说明

使用[Route]特性修饰 Controller 以及 Controller 的方法,即可实现路由的功能。

注意:

  • 使用了特性路由特性修饰后,常规路由将不适用当前被修饰的控制器或方法。
  • 特性路由会被继承。

特性路由修饰Controller

[Route("")]         //任何URL
[Route("Panda")]    //Panda
[Route("Tiger")]    //Tiger
public class PandaController : Controller
{
    [Route("")]             //任何URL
    [Route("Panda")]        //Panda/
	[Route("Panda/Index")]  //Panda/Index
	[Route("Tiger/Index", Name = "PandaRoute")]  //Tiger/Index ,还可以像传统路由那样设置路由名称
    public ActionResult Index()
    {
        return View();
    }
}

特性路由修饰Controller的方法

public class PandaController : Controller
{
    [Route("")]             //任何URL
    [Route("Panda")]        //Panda/
    [Route("Panda/Index")]  //Panda/Index
    public ActionResult Index()
    {
        return View();
    }
}

堆叠修饰

多个修饰器,可以实现,既可以用Panda访问,也可以用Tiger访问。

[Route("Panda")]    //Panda
[Route("Tiger")]    //Tiger
public class PandaController : Controller
{
    [Route("Index")]  			//Panda/Index 或者 Tiger/Index
    public ActionResult Index()
    {
        return View();
    }
}

模板参数|模型绑定

[Route("Panda/Index/{id}")]
public ActionResult Index(int id)
{
    return View();
}

模板可选参数

[Route("Panda/Index/{id?}")]
public ActionResult Index(int? id)
{
    return View();
}

使用预定义标记实现自定义路由

在特性路由[Route]中使用[Controller]和[Action]即可实现自定义映射,而无需每个方法都去定义一遍路由。

using Microsoft.AspNetCore.Mvc;

namespace WebApplication2.Controllers
{
    [Route("[controller]/[action]")]
    public class PandaController : Controller
    {
        [Route("")]
        public IActionResult Index(int? id)
        {
            return View();
        }

        public IActionResult Detail(int? id)
        {
            return View();
        }
    }
}

HTTP动词修饰

[Route("api/[Controller]")]
public class PandaController: Controller
{
    //Get api/[Controller]
    [HttpGet]
    public IEnumerable<string> Get()
    {
        
    }
    
    //Get api/[Controller]/{id}
    [HttpGet("{id:guid}")]
    public string Get(Guid id)
    {
        
    }
    
    //Post api/[Controller]
    [HttpPost]
    public void Post([FromBody]string value)
    {
        
    }
}

自定义特性路由(Custom attribute routing)

引入using Microsoft.AspNetCore.Mvc.Routing;命名空间,然后继承 IRouteTemplateProvider 接口即可。

using System;
//引入命名空间
using Microsoft.AspNetCore.Mvc.Routing;

namespace SampleAPI.CustomRouting
{
    //实现接口 IRouteTemplateProvider、Attribute
    public class CustomOrdersRoute : Attribute, IRouteTemplateProvider
    {
        public string Template => "api/orders";

        public int? Order { get; set; }

        public string Name => "Orders_route";
    }
}

使用自定义特性路由

[CustomOrdersRoute]
[ApiController]
public class OrderController : ControllerBase
{

添加路由(常规路由)(Conventional routing)

最基本使用

使用UseRouting()中间件启用路由功能。然后使用UseEndpoints()中间件配置路由功能。路由中间件UseEndpoints()是ASP.NET Core新增功能。
路由中间件UseEndpoints()的核心点是:EndpointRouting(终结点路由)。路由中间件UseEndpoints()会代替原有的路由规则和模板,可以跨越不同中间件系统,所以可以用在MVC、Razor Pages、Blazor、SignalR、gRPC中。推荐使用路由中间件UseEndpoints()来设置路由。

public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
    app.UseEndpoints(endpoints =>
    {
        endpoints.MapControllerRoute(
            //路由名称
            name: "default",
            //路由规则
            pattern: "{controller=Home}/{action=Index}/{id?}",
		   //默认值(方式二)
        	defaults: new{ controller = "Home", action = "Index" , id = 888 },
        	//路由约束
            constraints: new{ id = new IntRouteConstraint() }
        );
        
        endpoints.MapControllerRoute(
            name: "panda",
            pattern: "{Panda}/{action}/{id?}");
    	});
}

添加普通路由

添加普通路由(固定字符串)

app.UseEndpoints(endpoints =>
{
    endpoints.MapGet("/Panda/", async context => {
        await context.Response.WriteAsync("Panda666");
    });
});

添加普通路由(路由参数)

app.UseEndpoints(endpoints =>
{
    endpoints.MapGet("/{arg1}/{arg2}", async context => {
        await context.Response.WriteAsync("Panda666");
    });
});

添加普通路由(路由参数)

app.UseEndpoints(endpoints =>
{
    endpoints.MapGet("/{arg1}/{arg2}/{arg3}", async context => {
        await context.Response.WriteAsync("Panda666");
    });
});

添加普通路由(不规则)

映射指定的文件名和文件后缀

app.UseEndpoints(endpoints =>
{
    //设置映射
    endpoints.MapGet("/file/{FileName}.{Extension}", async context =>
    {
        await context.Response.WriteAsync("Panda666");
    });
});

添加路由并获得路由信息

app.UseEndpoints(endpoints =>
{
    endpoints.MapGet("{first}/{second}/{third}", async context =>
    {
        await context.Response.WriteAsync("开始-路由信息");
        foreach (var keyValuePair in context.Request.RouteValues)
        {
            await context.Response.WriteAsync($"{keyValuePair.Key}-{keyValuePair.Value}\n");
        }
        await context.Response.WriteAsync("结束-路由信息");
    });
});

添加路由并根据指定参数做出反应

app.UseEndpoints(endpoints =>
{
    endpoints.MapGet("{first}/{second}/{third}", async context =>
    {
        //获得指定的路由参数
        context.Request.RouteValues.TryGetValue("first", out object? value);
        string firstValue = value as string ?? "";
        //根据路由参数做出反应
        switch(firstValue)
        {
            case "Panda":
                await context.Response.WriteAsync("Panda\n");
                break;
            case "Dog":
                await context.Response.WriteAsync("Dog\n");
                break;
        }
    });
});

添加路由并将路由匹配放入单独的类中

自定义路由处理类,本质就是将路由处理代码放入单独的静态类和静态方法。

静态类和静态方法:

namespace PandaTest.Route
{
    public static class PandaRoute
    {
        /// <summary>
        /// 路由端点处理
        /// </summary>
        /// <param name="httpContext"></param>
        /// <returns></returns>
        public static async Task Endpoint(HttpContext httpContext)
        {
            //模拟具体的任务
            await httpContext.Response.WriteAsync("Panda666\n");
        }
    }
}

设置静态映射:

app.UseEndpoints(endpoints =>
{
    //设置映射
    endpoints.MapGet("/Panda", PandaRoute.Endpoint);
});

只映射指定的HTTP方法

使用Map+HTTP方法即可。

实例:

app.UseEndpoints(endpoints =>
{
    //映射GET
    endpoints.MapGet("order", context => context.Response.WriteAsync("Panda Get"));
    //映射Post
    endpoints.MapPost("order", context => context.Response.WriteAsync("Panda Post"));
    //映射Put
    endpoints.MapPut("/abc/def", context => context.Response.WriteAsync("Panda Put"));
    //映射Delete
    endpoints.MapDelete("/abc/def", context => context.Response.WriteAsync("Panda Delete"));
});

回退路由

当没有其他路由与请求匹配时,可以使用回退路由定义将请求定向到指定端点。这让任何路由都有相应。也可以避免请求沿着请求管道继续传递。

使用以下2个方法定义回退路由。

MapFallback(endpoint) 		//This method creates a fallback that routes requests to an endpoint.
MapFallbackToFile(path) 	//This method creates a fallback that routes requests to a file.

实例:自定义回退路由

app.UseEndpoints(endpoints =>
{
    //设置映射
    endpoints.MapFallback(async context => {
        await context.Response.WriteAsync("FallBack");
    });

    //设置映射到文件
    //endpoints.MapFallbackToFile("filePath");
});

实例:自定义回退文件

app.UseEndpoints(endpoints =>
{
    //设置映射到文件
    endpoints.MapFallbackToFile("filePath");
});

获得路由端点

并不是所有的中间件都有相应,有时候我们需要去获得路由端点(endpoint),比如:处理会话中间件、状态代码中间件。直接使用上下文对象的 GetEndpoint() 方法获得端点。

app.Use(async (context, next) => {
    //获得路由端点
    Endpoint? endpoint = context.GetEndpoint();
    if (endpoint != null)
    {
        //使用端点的代码
        //......
        await context.Response.WriteAsync("get endpoint");
    }
    else
    {
        await context.Response.WriteAsync("No endpoint");
    }

    //调用下一个中间件
    await next();
});

代合并-添加路由服务 和 其底层原理

配置路由服务中间件

public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
    var trackPackageRouteHandler = new RouteHandler(context =>{
        var routeValues = context.GetRouteData().Values;
        return context.Response.WriteAsync($"Hello! Route values: {string.Join(", ",routeValues)}");
    });
    var routeBuilder = new RouteBuilder(app,trackPackageRouteHandler);
    routeBuilder.MapRoute("Track Package Route","package/{operation}/{id:int}");
    routeBuilder.MapGet("hello/{name}", context =>{
        var name = context.GetRouteValue("name");
        return context.Response.WriteAsync($"Hi, {name}!");
    });
    var routes = routeBuilder.Build();
    app.UseRouter(routes);
}

在服务中添加路由服务

public void ConfigureServices(IServiceCollection services)
{
    services.AddRouting();
}

首先创建了一个RouteHandler,即路由处理器
它会从请求的URL中获取路由信息,并将其输出;接着创建了一个RouteBuilder
并使用它的MapRoute方法来添加路由信息
这些信息包括路由名称以及要匹配URL模板
在上面的示例中,URL模板的值为package/{operation}/{id:int}
除了调用MapRoute外,后面还可以使用MapGet方法添加仅匹配GET方法的请求
最后调用IApplicationBuilder的UseRouter扩展方法来添加路由中间件
以上是在ASP.NET Core中底层路由的创建方式
通常情况下并不需要这么做,这种方式比较复杂,更主要的原因则是当使用MVC后
就只需将对应的U RL路由到Controller与Action,这简化了路由规则
并且MVC中间件也封装了相关的逻辑,使基于MVC的路由更易于配置

待合并-自定义路由

对于ASP.NET Core MVC,定义路由的方法有以下两种
基于约定的路由:
基于约定的路由会根据一些约定来创建路由
它要在应用程序的Startup类中来定义
要使用基本约定的路由,首先定义一个或若干个路由约定
同时只要保证所有定义的路由约定能够尽可能地满足不同形式的映射即可
特性路由:
使用C#特性对Controller和Action指定其路由信息

public void Configure(IApplicationBuilder app,IHostingEnvironment env)
{
    app.UseMvc(routes =>
    {
        routes.MapRoute(template: "{controller}/{action}");
    });
}

注意:一个URL模板中只能有一个可选参数,并且只能放在最后

在指定参数的同时,也可以为参数添加一些约束或限制
例如,参数id的值为一个整型的数字,则应该这样定义路由
routes.MapRoute(template: "{controller}/{action}/{id:int}");

另一种实现路由的方法是使用特性路由
即RouteAttribute。它能够为每个Controller
甚至每个Action显式地设置路由信息
只要在Controller类或Action方法上添加[Route]特性即可,因此它要更为灵活

public class HomeController: Controller
{
    [Route("")]
    [Route("Home/Index")]
    [Route("AnotherOne")]
    public IActionResult Index()
    {
        return Ok("Hello from Index method of Home Controller");
    }
}

实例:

[Route("Home")]
public class HomeController : Controller
{
    [Route("")]
    [Route("Index")]
    public IActionResult Index()
    {
    }
    
    [Route("Welcome")]
    public IActionResult Welcome()
    {
    }
}

实例:使用[controller]与[action]来分别代替固定的值

[Route("[controller]")]
public class HomeController : Controller
{
    [Route("")]
    [Route("[action]")]
    public IActionResult Index()
    {
    }
    
    [Route("[action]")]
    public IActionResult Welcome()
    {
    }
}

实例:传递参数

[Route("[action]/{name?}")]
public IActionResult Welcome(string name)
{
}

实例:多个路由映射到Controller

[Controller]
[Route("api/[controller]")]
public class Blogs
{
}

实例:Controller禁止映射

[NonController]
public class BooksController
{
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/23143.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Hbase Coprocessor 协处理器 与 JavaAPI

协处理器概念 一、协处理器有两种&#xff1a; observer 和 endpoint 1、observer协处理器 Observer 类似于传统数据库中的触发器&#xff0c;当发生某些事件的时候这类协处理器会被 Server 端调用。Observer Coprocessor 就是一些散布在 HBase Server 端代码中的 hook 钩子…

go使用grpc

protoc下载 protoc是protobuf的编译工具&#xff0c;能根据.proto文件生成为各种语言的文件。 原始的protoc集成了如下语言的转换&#xff1a; cc#javaobjectcphppythonruby 但是没有集成go的转换工具。go的转换工具是在protoc的基础上使用插件的方式运行。 protoc 的下载地址…

java面试强基(7)

hashCode() 有什么用&#xff1f; ​ hashCode() 的作用是获取哈希码&#xff08;int 整数&#xff09;&#xff0c;也称为散列码。这个哈希码的作用是确定该对象在哈希表中的索引位置。 ​ hashCode()定义在 JDK 的 Object 类中&#xff0c;这就意味着 Java 中的任何类都包含…

阿里架构师耗时1年,把P8所需要的整个Java体系,都整理到了一起

始末 有人调侃我们说&#xff1a; 程序员不如送外卖。送外卖是搬运食物&#xff0c;自己是搬运代码&#xff0c;都不产出新的东西……透支体力&#xff0c;又消耗健康&#xff0c;可替代性极强&#xff0c;30岁之后就要面临被优化的危险……想跳槽&#xff0c;但是更高的平台…

科技风杂志科技风杂志社科技风编辑部2022年第31期目录

科技创新《科技风》投稿&#xff1a;cnqikantg126.com 基于钢架网箱清理控制系统的研究 张浩;崔新忠;丁树兵;尹杰;卢佳乐;王隽屹;张津宁; 1-3 遥感技术在海洋区域地质调查中的应用——以岛礁区调查为例 韩艳飞; 4-6 医院电气工程智能自动化及PLC技术在医院电气设备…

mipi介绍

文章目录1.MIPI简介1-1&#xff1a;DSI layer2.D_PHY2-1&#xff1a;D_PHY介绍2-2&#xff1a;电平状态2-3&#xff1a;lane结构2-4&#xff1a;data lane操作模式2-4-1&#xff1a;escape mode和space one hot coding2-4-2&#xff1a;Low-Power Data Transmission&#xff08…

图书借阅管理系统的设计与实现/书籍借还管理系统

摘要 随着Internet的发展&#xff0c;人们的日常生活已经离不开网络。未来人们的生活与工作将变得越来越数字化、网络化和电子化。网上借阅一系列功能将成为人们最关注话题&#xff0c;本论文是以构建图书借阅为目标&#xff0c;使用 Java制作&#xff0c;由前台用户借阅图书、…

计算机网络4小时速成:网络安全,被动攻击,主动攻击,对称加密,公钥秘钥,数字签名,鉴别,网络层安全协议IPsec,传输层安全协议SSL,防火墙,入侵检测系统

计算机网络4小时速成&#xff1a;网络安全&#xff0c;被动攻击&#xff0c;主动攻击&#xff0c;对称加密&#xff0c;公钥秘钥&#xff0c;数字签名&#xff0c;鉴别&#xff0c;网络层安全协议IPsec&#xff0c;传输层安全协议SSL&#xff0c;防火墙&#xff0c;入侵检测系统…

PTA题目 计算分段函数[1]

本题目要求计算下列分段函数f(x)的值&#xff1a; 输入格式: 输入在一行中给出实数x。 输出格式: 在一行中按“f(x) result”的格式输出&#xff0c;其中x与result都保留一位小数。 输入样例1: 10输出样例1: f(10.0) 0.1输入样例2: 0输出样例2: f(0.0) 0.0 #includ…

公众号免费题库接口

公众号免费题库接口 本平台优点&#xff1a; 多题库查题、独立后台、响应速度快、全网平台可查、功能最全&#xff01; 1.想要给自己的公众号获得查题接口&#xff0c;只需要两步&#xff01; 2.题库&#xff1a; 查题校园题库&#xff1a;查题校园题库后台&#xff08;点击…

IDEA Windows下SPARK连接Hive

IDEA Windows下SPARK连接Hive 文章目录IDEA Windows下SPARK连接Hive一、本地Windows环境配置二、IDEA项目配置1. POM配置2. 资源文件配置3. 测试验证一、本地Windows环境配置 本地构建HADOOP客户端 将大数据平台的HAODOP环境打包拿到本地环境来&#xff1a; #压缩整个HADOOP…

特征选择技术总结

在本文中&#xff0c;我们将回顾特性选择技术并回答为什么它很重要以及如何使用python实现它。 本文还可以帮助你解答以下的面试问题: 什么是特征选择?说出特性选择的一些好处你知道哪些特征选择技巧?区分单变量、双变量和多变量分析。我们能用PCA来进行特征选择吗?前向特征…

如何打造一支专业的QA团队,至少要关注这5点

目录 第一、专职的QA人员 第二、关注QA的能力素质 第三、适度的量化指标 第四、增加QA工作的透明度 第五、 充分利用好评审这把“利剑” QA是Quality Assurance的缩写&#xff0c;直接翻译过来就是“质量保证”的意思。 QA也称为质量工程师&#xff0c;基本上每个产品型或…

指纹浏览器——为跨境电商打造的跨境卫士

“跨境卫士”这个词当然是保障跨境人账号安全的意思&#xff0c;为跨境电商打造的跨境卫士&#xff0c;说白了就是专门为跨境电商商家解决各种痛点的软件工具&#xff0c;那一说到这类软件工具&#xff0c;很多人脑海中第一时间想到的是什么&#xff1f;相信都会出现“指纹浏览…

zabbix日志监控:操作系统、业务系统、文件大小、多行日志

zabbix日志监控&#xff1a;操作系统、业务系统、文件大小、多行日志 目录1 监控操作系统日志2 监控业务系统日志具体要求&#xff1a;分析&#xff1a;操作&#xff1a;3 监控日志文件大小&#xff08;1&#xff09;在被管主机当中安装agent&#xff08;2&#xff09;在以下za…

第五天(渐变)

文章目录笔记第五章 ⻚⾯布局5.1弹性盒⼦练习题目&#xff08;使用实现学校官网的首页面&#xff09;效果截图项目反思&#xff1a;笔记 其他效果 渐变<!DOCTYPE html> <html><head><meta charset"utf-8"><title></title><s…

「JVS低代码开发平台」设备维保到期自动提醒配置介绍

配置需求 构建一个 对设备管理的界面&#xff0c;在新增设备时&#xff0c;能录入设备到期的时间&#xff0c;发起维保后&#xff0c;能修改下次设备到期的时间&#xff0c;维保的状态系统自动根据当前时间和维保到期时间&#xff0c;自动调整。 整体配置思路 1、配置设备管理…

leecode#x平方根#爬楼梯

题目描述&#xff1a; 给你一个非负整数 x &#xff0c;计算并返回 x 的 算术平方根 。 由于返回类型是整数&#xff0c;结果只保留 整数部分 &#xff0c;小数部分将被 舍去 。 注意&#xff1a;不允许使用任何内置指数函数和算符&#xff0c;例如 pow(x, 0.5) 或者 x ** 0…

stm32cubemx hal学习记录:FreeRTOS信号量

一、基本配置 1、配置RCC、USART1、时钟84MHz 2、配置SYS&#xff0c;将Timebase Source修改为除滴答定时器外的其他定时器。 3、初始化LED的两个引脚、两个按键引脚 4、开启FreeRTOS&#xff0c;v1与v2版本不同&#xff0c;一般选用v1即可 5、创建二值信号量Binary Semap…

IPv6通信实验

♥️作者&#xff1a;小刘在C站 ♥️每天分享云计算网络运维课堂笔记&#xff0c;一起努力&#xff0c;共赴美好人生&#xff01; ♥️夕阳下&#xff0c;是最美的&#xff0c;绽放。 目录 实验命令指南 1&#xff09;配置ip地址 在r2上&#xff1a; 在r3上&#xff1a;…