.NET 中对所有类添加 IgnoreExtraElements 属性
在将 mongodb 中的数据映射到类的时候,当 mongodb
中的字段与定义的实体类的字段不一样时,会报错,此时只需要在类上添加
BsonIgnoreExtraElements
特性,即可解决。
在将 mongodb 中的数据映射到类的时候,当 mongodb
中的字段与定义的实体类的字段不一样时,会报错,此时只需要在类上添加
BsonIgnoreExtraElements
特性,即可解决。
ASP.NET Core 控制器使用路由中间件来匹配传入请求的 URL 并将它们映射到操作。本文以使用者的角度,对路由的使用进行概括说明,方便知识回顾与使用。
ASP.NET Core 控制器使用路由中间件来匹配传入请求的 URL 并将它们映射到操作。它支持传统路由,也支持属性路由。如果感觉到陌生,不要着急,继续向下看,下面会一一道来。
传统路由通常在 MVC 框架中使用。
它在 program.cs
中定义,如下:
完整方法:
1 | app.MapControllerRoute( |
简化使用:
1 | app.MapDefaultControllerRoute(); |
说明:
上面的完整路由定义中:
第一个路径段 {controller=Home}
映射到控制器名称。
如 UserController
中的控制器名为
User
。
第二段 {action=Index}
映射到操作名称。
action
就是 Controller 类中的方法名。
第三段 {id?}
用于可选 id
。
{id?}
中的 ?
使其成为可选。 id
用于映射到模型实体。
1 | public class HomeController : Controller |
可以多次调用 MapControllerRoute
来设置多个传统路由,如下:
1 | app.MapControllerRoute(name: "blog", |
上述代码中的 blog 路由是专用的传统路由。 之所以称为专用传统路由是因为
controller 和 action 不会以参数形式出现在路由模板 "blog/{*article}"
中,它们只能具有默认值 { controller = "Blog", action = "Article"
}。因此,此路由将会始终映射到操作
BlogController.Article
。
按定义顺序匹配
具体的路由在可变路由之前匹配
比如 users/demo
会在 users/{userId}
之前进行匹配
Attribute 本应翻译成属性,但为了与 .NET 中的属性字段区分,本文称之为特性。
特性路由通常在 REST API 中使用。
1 | var builder = WebApplication.CreateBuilder(args); |
属性路由通过调用 MapControllers
来映射属性路由控制器。
下面的示例中,HomeController
匹配一组类似于默认传统路由
{controller=Home}/{action=Index}/{id?}
匹配的 URL。
1 | public class HomeController : Controller |
action
area
controller
handler
page
这些关键词是保留的路由参数名,在定义路由时,不能使用这些关键词。
路由模板用于定义路由匹配的模板,它分为
假设如下控制器:
1 | [Route("api/[controller]")] |
在上述代码中:
每个操作都包含 [HttpGet]
属性,该属性仅将匹配限制为
HTTP GET 请求。
GetProduct
操作包含 "{id}"
模板,因此
id
被附加到控制器上的 "api/[controller]"
模板中。 方法模板为 "api/[controller]/"{id}""
。
因此,此操作仅匹配
/api/test2/xyz
、/api/test2/123
、/api/test2/{any string}
等形式的 GET 请求。
1 | [HttpGet("{id}")] // GET /api/test2/xyz |
GetIntProduct
操作包含 "int/{id:int}")
模板。 模板的 :int
部分将 id
路由值限制为可以转换为整数的字符串。
1 | [HttpGet("int/{id:int}")] // GET /api/test2/int/3 |
对于 /api/test2/int/abc
的 GET
请求,将会无法匹配到路由,并返回 404 Not Found
错误
GetInt2Product
操作在模板中包含
{id}
,但不将 id
限制为可以转换为整数的值。
对于 /api/test2/int2/abc
的 GET 请求,处理如下:
与此路由匹配。
模型绑定无法将 abc
转换为整数。 该方法的
id
参数是整数。
返回 400 Bad
Request,因为模型绑定未能将 abc
转换为整数。
1 | [HttpGet("int2/{id}")] // GET /api/test2/int2/3 |
生成 REST API 时,很少需要在 操作方法
上使用
[Route(...)]
,因为该操作接受所有 HTTP 方法。
建议使用更具体的 HTTP 谓词属性来明确 API 所支持的操作。 API 的 REST
客户端应知道哪些路径和 HTTP 谓词映射到特定的逻辑操作。
REST API 应使用属性路由将应用的功能建模为一组资源,其中操作由 HTTP 谓词表示。 也就是说,对同一逻辑资源执行的许多操作(例如,GET 和 POST)都使用相同 URL。
1 | [ApiController] |
上述代码中的 URL 路径为 /products3
:
GET
时,调用
MyProductsController.ListProducts
。POST
时,调用
MyProductsController.CreateProduct
。在控制器上定义的所有路由模板均作为操作上路由模板的前缀。在控制器上放置的路由特性会使控制器中的所有操作都使用该特性路由。
1 | [ApiController] |
在上面的示例中:
/products
可以匹配
ProductsApi.ListProducts
/products/5
可以匹配
ProductsApi.GetProduct(int)
。这两项操作仅匹配 HTTP GET
,因为它们标记了
[HttpGet]
。
操作上以 /
或 ~/
开头的路由模板不与控制器的路由模板合并。
Attribute | 与 [Route("Home")] 结合 |
定义路由模板 |
---|---|---|
[Route("")] |
是 | "Home" |
[Route("Index")] |
是 | "Home/Index" |
[Route("/")] |
否 | "" |
[Route("About")] |
是 | "Home/About" |
在父类控制器上定义的路由特性会继承给子类,可以在父类中定义一个通用的路由特性,减少在子类的控制器上重复定义。
例如:
1 | [ApiController] |
特性路由支持标记替换,将标记用方括号([
、]
)括起来即可。
标记 [action]
、[area]
和
[controller]
会替换成定义了路由的操作中的操作名称、区域名称和控制器名称。
1 | // Products0:控制器名称 |
[controller]
,[action]
等会默认使用定义的名称作用 URL,而在实际开发中,我们可能需要将
PascalCase 命名转换成 hyphenCase 命名,如将 FindAll
变成
find-all
。
可以通过实现 IOutboundParameterTransformer 接口来自定义。
接口实现:
1 | using System.Text.RegularExpressions; |
使用:
1 | builder.Services.AddControllersWithViews(options => |
RouteTokenTransformerConvention 是应用程序的模型约定,可以:
将参数转换程序应用到程序中的所有特性路由中。
在替换特性路由标记值时对其进行自定义
同一个控制器或者路由上,可以同时添加多个路由特性标记。
1 | [Route("Store")] |
一般不要使用多个路由特性,会让 URL 看起来不易于理解,且容易冲突。
特性路由支持使用与传统路由相同的内联语法,来指定可选参数、默认值和约束。
1 | public class Products14Controller : Controller |
使用说明:
=
赋予默认值:
进行约束,可以同时使用多个约束?
表示可选参数内置路由约束:
约束 | 示例 | 匹配项示例 | 说明 |
---|---|---|---|
int |
{id:int} |
123456789 ,
-123456789 |
匹配任何整数 |
bool |
{active:bool} |
true , FALSE |
匹配 true 或
false 。 不区分大小写 |
datetime |
{dob:datetime} |
2016-12-31 ,
2016-12-31 7:32pm |
在固定区域性中匹配有效的
DateTime 值。 请参阅前面的警告。 |
decimal |
{price:decimal} |
49.99 ,
-1,000.01 |
在固定区域性中匹配有效的
decimal 值。 请参阅前面的警告。 |
double |
{weight:double} |
1.234 ,
-1,001.01e8 |
在固定区域性中匹配有效的
double 值。 请参阅前面的警告。 |
float |
{weight:float} |
1.234 ,
-1,001.01e8 |
在固定区域性中匹配有效的
float 值。 请参阅前面的警告。 |
guid |
{id:guid} |
CD2C1638-1638-72D5-1638-DEADBEEF1638 |
匹配有效的 Guid 值 |
long |
{ticks:long} |
123456789 ,
-123456789 |
匹配有效的 long 值 |
minlength(value) |
{username:minlength(4)} |
Rick |
字符串必须至少为 4 个字符 |
maxlength(value) |
{filename:maxlength(8)} |
MyFile |
字符串不得超过 8 个字符 |
length(length) |
{filename:length(12)} |
somefile.txt |
字符串必须正好为 12 个字符 |
length(min,max) |
{filename:length(8,16)} |
somefile.txt |
字符串必须至少为 8 个字符,且不得超过 16 个字符 |
min(value) |
{age:min(18)} |
19 |
整数值必须至少为 18 |
max(value) |
{age:max(120)} |
91 |
整数值不得超过 120 |
range(min,max) |
{age:range(18,120)} |
91 |
整数值必须至少为 18,且不得超过 120 |
alpha |
{name:alpha} |
Rick |
字符串必须由一个或多个字母字符组成,a -z ,并区分大小写。 |
regex(expression) |
{ssn:regex(^\\d{{3}}-\\d{{2}}-\\d{{4}}$)} |
123-45-6789 |
字符串必须与正则表达式匹配。 请参阅有关定义正则表达式的提示。 |
required |
{name:required} |
Rick |
用于强制在 URL 生成过程中存在非参数值 |
所有路由属性都实现 IRouteTemplateProvider
。 ASP.NET Core
运行时:
IRouteTemplateProvider
的属性来构建初始路由集。每个 IRouteTemplateProvider
都允许定义一个包含自定义路由模板、顺序和名称的路由:
1 | public class MyApiControllerAttribute : Attribute, IRouteTemplateProvider |
上述 Get
方法返回
Order = 2, Template = api/MyTestApi
。
ASP.NET Core 使用以下类型作为 Web API 控制器的操作返回类型:
请点击 ASP.NET Core Web API 中控制器操作的返回类型 进行详细阅读
类型 | 传统路由 | 特性路由 |
---|---|---|
定义方式 | 在 Program.cs 中调用 MapControllerRoute
建立 URL 映射 |
在每个 Controller 中通过特性来定义 URL 映射 |
操作性 | 更简洁 | 要对每个 action 进行定义 |
当理解了路由相关知识后,需要可以快速应用到实际项目中,本节记录一些快速配置代码,方便进行初始化。
1 | // ... |
增加 SlugifyParameterTransformer
类
1 | using System.Text.RegularExpressions; |
Program.cs
中配置
1 | builder.Services.AddControllersWithViews(options => |
所有子类都继承自这个基类
1 | [Route("api/v1/[controller]")] |
在 ASP.NET Core 中路由到控制器操作 | Microsoft Learn
ASP.NET Core 中的路由 | Microsoft Learn
Navicat 是一款非常流行的数据库管理软件,可以通过 GUI 界面进行数据库管理,也可以通过编写代码来操作数据库。
在使用 Navicat 进行 MongoDB 查询时,我们不仅可以使用 MongoDB 中的基础查询语句,还可以使用使用其内置的 JavaScript 引擎执行代码段,进行各种数据库操作。
准备静心理解一下 JS 中的原型,仔细一查,网上各有各的理解,各有各的缺点,让人眼花缭乱,看不通透。本文将从原理手,由浅入深地理解原型的概念。
在 vue 自定义事件中,子组件会通过 emit
向父组件传递参数,父组件执行回调函数。但是有时候父组件再执行回调时也需要传入参数,如果直接给父组件回调函数传入参数会覆盖掉子组件的参数。我们有三种解决办法。
1 | // 子组件中 Child.vue |
当子组件有参数返回时,在父组件中使用 $event 作为占位符,这里 $event 就代表了子组件返回的参数。这里 $event 位置没有限制,可以在第一位,也可以在最后一位。
局限性: 只适合子组件返回一个参数的情况,如果子组件有多个参数返回,只能接收到第一个参数
1 | // 子组件中 Child.vue |
这种方法利用了一个箭头函数先把子模块返回的参数接收,然后再传递到回调函数中。
使用是注意先接收子模块返回的参数,此方法对参数个数没有限制
此方法类似于方法一,只不过是用 arguments 作为占位符,这里 argument 是一个数组
1 | // 父组件接收参数 |
本文摘抄至以下文章,在此表示诚挚感谢!
ventoy 是一款超级方便的系统安装软件。在利用 ventoy 给一些老电脑安装系统时,发现无法选择安装盘符,提示无法安装在 MBR 分区上。
本文记录了如何向私有镜像管理器(verdaccio)中新建用户并发布本地包的方法。
echarts 是百度开源的一个绘制图表库,号称是百度最良心的作品。本文将主要介绍 echarts 配置的相关概念,在使用时,可以按需去查找相关 api。
通过 nrm(npmregistry manager) 可以很方面的管理和切换 npm 的镜像源。