Asp.NetCoreWebApi - RESTful Api
目录
- 参考文章
- REST
- 常用http动词
- WebApi 在
Asp.NetCore 中的实现 - 支持https
- 支持HSTS
- 使用SerilLog
- Asp.NetCore配置文件
- 自定义一个异常处理,ExceptionHandler
- 实现数据接口类(Resource),使用AutoMapper在Resource和Entity中映射
- 9.1.为Entity类创建对应的Resource类
- 使用 AutoMapper
- 使用FluentValidation
- 实现Http
Get(翻页,过滤,排序) - 翻页
- 资源塑形(Resource
shaping) - HATEOAS
- Post添加资源
- Delete
- PUT & PATCH
- Http常用方法总结
参考文章
<blockquote>
<ul>
<li><a href="https://www.cnblogs.com/linezero/p/aspnetcorewebapi-restfulapi.html">ASP.NET Core Web API
开发-RESTful API实现</a></li>
<li><a
href="https://www.cnblogs.com/weidagang2046/archive/2011/06/04/idempotence.html">理解HTTP幂等性</a>
</li>
<li><a href="https://www.bilibili.com/video/av33344382">某站微软Mvp杨旭的Asp.NetCore
WebApi的视频</a></li>
</ul>
</blockquote>
<hr>
<h2 class="mume-header" id="rest">REST</h2>
<p><strong>REST</strong> : <strong>具象状态传输(Representational State
Transfer,简称REST)</strong>,是Roy Thomas
Fielding博士于2000年在他的博士论文
"Architectural Styles and the Design of Network-based Software Architectures"
中提出来的一种万维网软件架构风格。<br>
目前在三种主流的Web服务实现方案中,因为<strong>REST</strong>模式与复杂的<strong>SOAP</strong>和<strong>XML-RPC</strong>相比更加简洁,越来越多的web服务开始采用REST风格设计和实现。例如,Amazon.com提供接近REST风格的Web服务执行图书查询;
</p>
<p>符合REST设计风格的Web API称为RESTful
API。它从以下三个方面资源进行定义:
</p>
<ul>
<li>直观简短的资源地址:URI,比如:<a
href="http://example.com/resources/">http://example.com/resources/</a> .</li>
<li>传输的资源:Web服务接受与返回的互联网媒体类型,比如:JSON,XML,YAML等...
</li>
<li>对资源的操作:Web服务在该资源上所支持的一系列请求方法(比如:POST,GET,PUT或DELETE).
</li>
</ul>
<p>PUT和DELETE方法是幂等方法.GET方法是安全方法(不会对服务器端有修改,因此当然也是幂等的).
</p>
<p>ps 关于幂等方法 :<br>
看这篇 <a
href="https://www.cnblogs.com/weidagang2046/archive/2011/06/04/idempotence.html">理解HTTP幂等性</a>.<br>
简单说,客户端多次请求服务端返回的结果都相同,那么就说这个操作是幂等的.(个人理解,详细的看上面给的文章)
</p>
<p>不像基于SOAP的Web服务,RESTful
Web服务并没有“正式”的标准。这是因为REST是一种架构,而SOAP只是一个协议。虽然REST不是一个标准,但大部分RESTful
Web服务实现会使用HTTP、URI、JSON和XML等各种标准。
</p>
<h2 class="mume-header" id="%E5%B8%B8%E7%94%A8http%E5%8A%A8%E8%AF%8D">常用http动词</h2>
<p>括号中是相应的SQL命令.</p>
<ul>
<li><strong>GET(SELECT)</strong> :
从服务器取出资源(一项或多项).
</li>
<li><strong>POST(CREATE)</strong> :
在服务器新建一个资源.</li>
<li><strong>PUT(UPDATE)</strong> :
在服务器更新资源(客户端提供改变后的完整资源).
</li>
<li><strong>PATCH(UPDATE)</strong> :
在服务器更新资源(客户端提供改变的属性).
</li>
<li><strong>DELETE(DELETE)</strong> : 在服务器删除资源.</li>
</ul>
<h2 class="mume-header" id="webapi-%E5%9C%A8-aspnetcore-%E4%B8%AD%E7%9A%84%E5%AE%9E%E7%8E%B0">WebApi 在
Asp.NetCore 中的实现</h2>
<p>这里以用户增删改查为例.</p>
<h3 class="mume-header" id="%E5%88%9B%E5%BB%BAwebapi%E9%A1%B9%E7%9B%AE">创建WebApi项目.
</h3>
<p>参考<a href="https://www.cnblogs.com/linezero/p/5497472.html">ASP.NET Core WebAPI
开发-新建WebAPI项目</a>.</p>
<p>注意,本文建立的Asp.NetCore <a
href="http://xn--WebApi-177lr63kxhzcdwr.net">WebApi项目选择.net</a>
core版本是<strong>2.2</strong>,不建议使用其他版本,2.1版本下会遇到依赖文件冲突问题!<a
href="http://xn--2-zn6ao2a258ac7hc3a898qg6k.xn--2-856b314a6he.net">所以一定要选择2.2版本的.net</a>
core.</p>
<h3 class="mume-header" id="%E9%9B%86%E6%88%90entity-framework-core%E6%93%8D%E4%BD%9Cmysql">
集成Entity Framework Core操作Mysql</h3>
<h4 class="mume-header"
id="%E5%AE%89%E8%A3%85%E7%9B%B8%E5%85%B3%E7%9A%84%E5%8C%85%E4%B8%BAxxxxinfrastructure%E9%A1%B9%E7%9B%AE%E5%AE%89%E8%A3%85">
安装相关的包(为Xxxx.Infrastructure项目安装)
</h4>
<ul>
<li>Microsoft.EntityFrameworkCore.Design</li>
<li>Pomelo.EntityFrameworkCore.MySql</li>
</ul>
<p><strong>这里注意一下,Mysql官方的包是
<code>MySql.Data.EntityFrameworkCore</code>,但是这个包有bug,我在github上看到有人说有替代方案
-
<code>Pomelo.EntityFrameworkCore.MySql</code>,经过尝试,后者比前者好用.所有这里就选择后者了.使用前者的话可能会导致数据库迁移失败(Update的时候).</strong>
</p>
<p>PS: Mysql文档原文:</p>
<blockquote>
<p>Install the MySql.Data.EntityFrameworkCore NuGet package.<br>
<strong>For EF Core 1.1 only</strong>: If you plan to scaffold a database, install the
MySql.Data.EntityFrameworkCore.Design NuGet package as well.</p>
<p><a href="https://dev.mysql.com/doc/connector-net/en/connector-net-entityframework-core.html">EFCore -
MySql文档</a><br>
<strong>Mysql版本要求</strong>:<br>
Mysql版本要高于<strong>5.7</strong><br>
使用最新版本的Mysql Connector(2019 6/27
目前是8.x).</p>
</blockquote>
<p>为Xxxx.<strong>Infrastructure</strong>项目安装EFCore相关的包:<br>
<img src="https://img2018.cnblogs.com/blog/1596066/201906/1596066-20190628014058456-975150311.png" alt></p>
<p>为Xxxx.Api项目安装 <code>Pomelo.EntityFrameworkCore.MySql</code><br>
<img src="https://img2018.cnblogs.com/blog/1596066/201906/1596066-20190628014223270-1330094834.png" alt></p>
<h4 class="mume-header" id="%E5%BB%BA%E7%AB%8Bentity%E5%92%8Ccontext">建立Entity和Context</h4>
<p><img src="https://img2018.cnblogs.com/blog/1596066/201906/1596066-20190627231846020-1062185075.png" alt></p>
<details>
<summary>ApiUser</summary>
<pre data-role="codeBlock" data-info="CSharp" class="language-csharp"><span class="token keyword">namespace</span> ApiStudy<span class="token punctuation">.</span>Core<span class="token punctuation">.</span>Entities
{
using System;
<span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">ApiUser</span>
<span class="token punctuation">{</span>
<span class="token keyword">public</span> <span class="token class-name">Guid</span> Guid <span class="token punctuation">{</span> <span class="token keyword">get</span><span class="token punctuation">;</span> <span class="token keyword">set</span><span class="token punctuation">;</span> <span class="token punctuation">}</span>
<span class="token keyword">public</span> <span class="token keyword">string</span> Name <span class="token punctuation">{</span> <span class="token keyword">get</span><span class="token punctuation">;</span> <span class="token keyword">set</span><span class="token punctuation">;</span> <span class="token punctuation">}</span>
<span class="token keyword">public</span> <span class="token keyword">string</span> Passwd <span class="token punctuation">{</span> <span class="token keyword">get</span><span class="token punctuation">;</span> <span class="token keyword">set</span><span class="token punctuation">;</span> <span class="token punctuation">}</span>
<span class="token keyword">public</span> <span class="token class-name">DateTime</span> RegistrationDate <span class="token punctuation">{</span> <span class="token keyword">get</span><span class="token punctuation">;</span> <span class="token keyword">set</span><span class="token punctuation">;</span> <span class="token punctuation">}</span>
<span class="token keyword">public</span> <span class="token class-name">DateTime</span> Birth <span class="token punctuation">{</span> <span class="token keyword">get</span><span class="token punctuation">;</span> <span class="token keyword">set</span><span class="token punctuation">;</span> <span class="token punctuation">}</span>
<span class="token keyword">public</span> <span class="token keyword">string</span> ProfilePhotoUrl <span class="token punctuation">{</span> <span class="token keyword">get</span><span class="token punctuation">;</span> <span class="token keyword">set</span><span class="token punctuation">;</span> <span class="token punctuation">}</span>
<span class="token keyword">public</span> <span class="token keyword">string</span> PhoneNumber <span class="token punctuation">{</span> <span class="token keyword">get</span><span class="token punctuation">;</span> <span class="token keyword">set</span><span class="token punctuation">;</span> <span class="token punctuation">}</span>
<span class="token keyword">public</span> <span class="token keyword">string</span> Email <span class="token punctuation">{</span> <span class="token keyword">get</span><span class="token punctuation">;</span> <span class="token keyword">set</span><span class="token punctuation">;</span> <span class="token punctuation">}</span>
<span class="token punctuation">}</span>
}
namespace ApiStudy.Infrastructure.Database
{
using ApiStudy.Core.Entities;
using Microsoft.EntityFrameworkCore;<span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">UserContext</span><span class="token punctuation">:</span><span class="token class-name">DbContext</span>
<span class="token punctuation">{</span>
<span class="token keyword">public</span> <span class="token function">UserContext</span><span class="token punctuation">(</span>DbContextOptions<span class="token operator"><</span>UserContext<span class="token operator">></span> options<span class="token punctuation">)</span><span class="token punctuation">:</span> <span class="token keyword">base</span><span class="token punctuation">(</span>options<span class="token punctuation">)</span>
<span class="token punctuation">{</span>
<span class="token punctuation">}</span> <span class="token keyword">protected</span> <span class="token keyword">override</span> <span class="token keyword">void</span> <span class="token function">OnModelCreating</span><span class="token punctuation">(</span><span class="token class-name">ModelBuilder</span> modelBuilder<span class="token punctuation">)</span>
<span class="token punctuation">{</span>
modelBuilder<span class="token punctuation">.</span><span class="token generic-method"><span class="token function">Entity</span><span class="token punctuation"><</span><span class="token class-name">ApiUser</span><span class="token punctuation">></span></span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">HasKey</span><span class="token punctuation">(</span>u <span class="token operator">=></span> u<span class="token punctuation">.</span>Guid<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">base</span><span class="token punctuation">.</span><span class="token function">OnModelCreating</span><span class="token punctuation">(</span>modelBuilder<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span> <span class="token keyword">public</span> DbSet<span class="token operator"><</span>ApiUser<span class="token operator">></span> ApiUsers <span class="token punctuation">{</span> <span class="token keyword">get</span><span class="token punctuation">;</span> <span class="token keyword">set</span><span class="token punctuation">;</span> <span class="token punctuation">}</span>
<span class="token punctuation">}</span>
}
ConfigureService中注入EF服务
<pre data-role="codeBlock" data-info="CSharp" class="language-csharp">services<span class="token punctuation">.</span><span class="token generic-method"><span class="token function">AddDbContext</span><span class="token punctuation"><</span><span class="token class-name">UserContext</span><span class="token punctuation">></span></span><span class="token punctuation">(</span>options <span class="token operator">=></span>
<span class="token punctuation">{</span>
<span class="token keyword">string</span> connString <span class="token operator">=</span> <span class="token string">"Server=Xxx:xxx:xxx:xxx;Database=Xxxx;Uid=root;Pwd=Xxxxx; "</span><span class="token punctuation">;</span>
options<span class="token punctuation">.</span><span class="token function">UseMySQL</span><span class="token punctuation">(</span>connString<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
迁移数据库
<ul>
<li>在Tools > NuGet Package Manager > Package Manager Console输入命令.
</li>
<li>Add-Migration Xxx 添加迁移.<br>
PS : 如果迁移不想要,使用 Remove-Migration
命令删除迁移.</li>
<li>Update-Database 更新到数据库.</li>
</ul>
<h4 class="mume-header"
id="%E8%BF%81%E7%A7%BB%E6%95%B0%E6%8D%AE%E5%BA%93%E5%A4%B1%E8%B4%A5-%E6%8F%90%E7%A4%BA-unable-to-create-an-object-of-type-xxxxcontext-for-the-different-patterns-supported-at-design-time-see-httpsgomicrosoftcomfwlinklinkid851728">
迁移数据库失败, 提示 <code>Unable to create an object
of type '<Xxxx>Context'. For the different patterns supported at design time, see
https://go.microsoft.com/fwlink/?linkid=851728</code></h4>
<p>原因应该是EfCore迁移工具不知道如何创建
<strong><code>DbContext</code></strong> 导致的.</p>
<p><strong>解决方案</strong></p>
<p>在<code>DbContext</code>所在的项目下新建一个类:
</p>
<pre data-role="codeBlock" data-info="CSharp" class="language-csharp"><span class="token comment">/// <summary></span>
/// 设计时DbContext的创建, 告诉EF Core迁移工具如何创建DbContext
/// </summary>
public class <Xxxx>ContextFactory : IDesignTimeDbContextFactory<<Xxxx>Context>
{
public <Xxxx>Context CreateDbContext(string[] args)
{
var optionsBuilder = new DbContextOptionsBuilder<<Xxxx>Context>();
optionsBuilder.UseMySql(
@"Server=[服务器ip];Database=[数据库]];Uid=[用户名];Pwd=[密码];");
<span class="token keyword">return</span> <span class="token keyword">new</span> <span class="token operator"><</span>Xxxx<span class="token operator">></span><span class="token function">Context</span><span class="token punctuation">(</span>optionsBuilder<span class="token punctuation">.</span>Options<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
}
数据库迁移结果
<p><img src="https://img2018.cnblogs.com/blog/1596066/201906/1596066-20190628014343485-1030943357.png" alt></p>
<h4 class="mume-header"
id="326-a-name-1a%E4%B8%BA%E6%95%B0%E6%8D%AE%E5%BA%93%E5%88%9B%E5%BB%BA%E7%A7%8D%E5%AD%90%E6%95%B0%E6%8D%AE">
3.2.6. <a name="-1"
href></a>为数据库创建种子数据</h4>
<ul>
<li>
<p>写一个创建种子数据的类</p>
<details>
<summary>UserContextSeed</summary>
<pre data-role="codeBlock" data-info="CSharp" class="language-csharp"><span class="token keyword">namespace</span> ApiStudy<span class="token punctuation">.</span>Infrastructure<span class="token punctuation">.</span>Database
{
using ApiStudy.Core.Entities;
using Microsoft.Extensions.Logging;
using System;
using System.Linq;
using System.Threading.Tasks;
<span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">UserContextSeed</span>
<span class="token punctuation">{</span>
<span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token keyword">async</span> <span class="token class-name">Task</span> <span class="token function">SeedAsync</span><span class="token punctuation">(</span><span class="token class-name">UserContext</span> context<span class="token punctuation">,</span><span class="token class-name">ILoggerFactory</span> loggerFactory<span class="token punctuation">)</span>
<span class="token punctuation">{</span>
<span class="token keyword">try</span>
<span class="token punctuation">{</span>
<span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span>context<span class="token punctuation">.</span>ApiUsers<span class="token punctuation">.</span><span class="token function">Any</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
<span class="token punctuation">{</span>
context<span class="token punctuation">.</span>ApiUsers<span class="token punctuation">.</span><span class="token function">AddRange</span><span class="token punctuation">(</span>
<span class="token keyword">new</span> <span class="token class-name">ApiUser</span>
<span class="token punctuation">{</span>
Guid <span class="token operator">=</span> Guid<span class="token punctuation">.</span><span class="token function">NewGuid</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
Name <span class="token operator">=</span> <span class="token string">"la"</span><span class="token punctuation">,</span>
Birth <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">DateTime</span><span class="token punctuation">(</span><span class="token number">1998</span><span class="token punctuation">,</span> <span class="token number">11</span><span class="token punctuation">,</span> <span class="token number">29</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
RegistrationDate <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">DateTime</span><span class="token punctuation">(</span><span class="token number">2019</span><span class="token punctuation">,</span> <span class="token number">6</span><span class="token punctuation">,</span> <span class="token number">28</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
Passwd <span class="token operator">=</span> <span class="token string">"123587"</span><span class="token punctuation">,</span>
ProfilePhotoUrl <span class="token operator">=</span> <span class="token string">"https://www.laggage.top/"</span><span class="token punctuation">,</span>
PhoneNumber <span class="token operator">=</span> <span class="token string">"10086"</span><span class="token punctuation">,</span>
Email <span class="token operator">=</span> <span class="token string">"yu@outlook.com"</span>
<span class="token punctuation">}</span><span class="token punctuation">,</span>
<span class="token keyword">new</span> <span class="token class-name">ApiUser</span>
<span class="token punctuation">{</span>
Guid <span class="token operator">=</span> Guid<span class="token punctuation">.</span><span class="token function">NewGuid</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
Name <span class="token operator">=</span> <span class="token string">"David"</span><span class="token punctuation">,</span>
Birth <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">DateTime</span><span class="token punctuation">(</span><span class="token number">1995</span><span class="token punctuation">,</span> <span class="token number">8</span><span class="token punctuation">,</span> <span class="token number">29</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
RegistrationDate <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">DateTime</span><span class="token punctuation">(</span><span class="token number">2019</span><span class="token punctuation">,</span> <span class="token number">3</span><span class="token punctuation">,</span> <span class="token number">28</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
Passwd <span class="token operator">=</span> <span class="token string">"awt87495987"</span><span class="token punctuation">,</span>
ProfilePhotoUrl <span class="token operator">=</span> <span class="token string">"https://www.laggage.top/"</span><span class="token punctuation">,</span>
PhoneNumber <span class="token operator">=</span> <span class="token string">"1008611"</span><span class="token punctuation">,</span>
Email <span class="token operator">=</span> <span class="token string">"David@outlook.com"</span>
<span class="token punctuation">}</span><span class="token punctuation">,</span>
<span class="token keyword">new</span> <span class="token class-name">ApiUser</span>
<span class="token punctuation">{</span>
Guid <span class="token operator">=</span> Guid<span class="token punctuation">.</span><span class="token function">NewGuid</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
Name <span class="token operator">=</span> <span class="token string">"David"</span><span class="token punctuation">,</span>
Birth <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">DateTime</span><span class="token punctuation">(</span><span class="token number">2001</span><span class="token punctuation">,</span> <span class="token number">8</span><span class="token punctuation">,</span> <span class="token number">19</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
RegistrationDate <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">DateTime</span><span class="token punctuation">(</span><span class="token number">2019</span><span class="token punctuation">,</span> <span class="token number">4</span><span class="token punctuation">,</span> <span class="token number">25</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
Passwd <span class="token operator">=</span> <span class="token string">"awt87495987"</span><span class="token punctuation">,</span>
ProfilePhotoUrl <span class="token operator">=</span> <span class="token string">"https://www.laggage.top/"</span><span class="token punctuation">,</span>
PhoneNumber <span class="token operator">=</span> <span class="token string">"1008611"</span><span class="token punctuation">,</span>
Email <span class="token operator">=</span> <span class="token string">"David@outlook.com"</span>
<span class="token punctuation">}</span><span class="token punctuation">,</span>
<span class="token keyword">new</span> <span class="token class-name">ApiUser</span>
<span class="token punctuation">{</span>
Guid <span class="token operator">=</span> Guid<span class="token punctuation">.</span><span class="token function">NewGuid</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
Name <span class="token operator">=</span> <span class="token string">"Linus"</span><span class="token punctuation">,</span>
Birth <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">DateTime</span><span class="token punctuation">(</span><span class="token number">1999</span><span class="token punctuation">,</span> <span class="token number">10</span><span class="token punctuation">,</span> <span class="token number">26</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
RegistrationDate <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">DateTime</span><span class="token punctuation">(</span><span class="token number">2018</span><span class="token punctuation">,</span> <span class="token number">2</span><span class="token punctuation">,</span> <span class="token number">8</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
Passwd <span class="token operator">=</span> <span class="token string">"awt87495987"</span><span class="token punctuation">,</span>
ProfilePhotoUrl <span class="token operator">=</span> <span class="token string">"https://www.laggage.top/"</span><span class="token punctuation">,</span>
PhoneNumber <span class="token operator">=</span> <span class="token string">"17084759987"</span><span class="token punctuation">,</span>
Email <span class="token operator">=</span> <span class="token string">"Linus@outlook.com"</span>
<span class="token punctuation">}</span><span class="token punctuation">,</span>
<span class="token keyword">new</span> <span class="token class-name">ApiUser</span>
<span class="token punctuation">{</span>
Guid <span class="token operator">=</span> Guid<span class="token punctuation">.</span><span class="token function">NewGuid</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
Name <span class="token operator">=</span> <span class="token string">"YouYou"</span><span class="token punctuation">,</span>
Birth <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">DateTime</span><span class="token punctuation">(</span><span class="token number">1992</span><span class="token punctuation">,</span> <span class="token number">1</span><span class="token punctuation">,</span> <span class="token number">26</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
RegistrationDate <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">DateTime</span><span class="token punctuation">(</span><span class="token number">2015</span><span class="token punctuation">,</span> <span class="token number">7</span><span class="token punctuation">,</span> <span class="token number">8</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
Passwd <span class="token operator">=</span> <span class="token string">"grwe874864987"</span><span class="token punctuation">,</span>
ProfilePhotoUrl <span class="token operator">=</span> <span class="token string">"https://www.laggage.top/"</span><span class="token punctuation">,</span>
PhoneNumber <span class="token operator">=</span> <span class="token string">"17084759987"</span><span class="token punctuation">,</span>
Email <span class="token operator">=</span> <span class="token string">"YouYou@outlook.com"</span>
<span class="token punctuation">}</span><span class="token punctuation">,</span>
<span class="token keyword">new</span> <span class="token class-name">ApiUser</span>
<span class="token punctuation">{</span>
Guid <span class="token operator">=</span> Guid<span class="token punctuation">.</span><span class="token function">NewGuid</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
Name <span class="token operator">=</span> <span class="token string">"小白"</span><span class="token punctuation">,</span>
Birth <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">DateTime</span><span class="token punctuation">(</span><span class="token number">1997</span><span class="token punctuation">,</span> <span class="token number">9</span><span class="token punctuation">,</span> <span class="token number">30</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
RegistrationDate <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">DateTime</span><span class="token punctuation">(</span><span class="token number">2018</span><span class="token punctuation">,</span> <span class="token number">11</span><span class="token punctuation">,</span> <span class="token number">28</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
Passwd <span class="token operator">=</span> <span class="token string">"gewa749864"</span><span class="token punctuation">,</span>
ProfilePhotoUrl <span class="token operator">=</span> <span class="token string">"https://www.laggage.top/"</span><span class="token punctuation">,</span>
PhoneNumber <span class="token operator">=</span> <span class="token string">"17084759987"</span><span class="token punctuation">,</span>
Email <span class="token operator">=</span> <span class="token string">"BaiBai@outlook.com"</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">await</span> context<span class="token punctuation">.</span><span class="token function">SaveChangesAsync</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span>
<span class="token keyword">catch</span><span class="token punctuation">(</span><span class="token class-name">Exception</span> ex<span class="token punctuation">)</span>
<span class="token punctuation">{</span>
<span class="token class-name">ILogger</span> logger <span class="token operator">=</span> loggerFactory<span class="token punctuation">.</span><span class="token generic-method"><span class="token function">CreateLogger</span><span class="token punctuation"><</span><span class="token class-name">UserContextSeed</span><span class="token punctuation">></span></span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
logger<span class="token punctuation">.</span><span class="token function">LogError</span><span class="token punctuation">(</span>ex<span class="token punctuation">,</span> <span class="token string">"Error occurred while seeding database"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span>
}
修改Program.Main方法
Program.Main
IWebHost host = CreateWebHostBuilder(args).Build(); using (IServiceScope scope = host.Services.CreateScope())
{
IServiceProvider provider = scope.ServiceProvider;
UserContext userContext = provider.GetService<UserContext>();
ILoggerFactory loggerFactory = provider.GetService<ILoggerFactory>();
UserContextSeed.SeedAsync(userContext, loggerFactory).Wait();
} host.Run();
这个时候运行程序会出现异常,打断点看一下异常信息:Data
too long for column 'Guid' at row 1
可以猜到,Mysql的varbinary(16)放不下C#
Guid.NewGuid()方法生成的Guid,所以配置一下数据库Guid字段类型为varchar(256)可以解决问题.
解决方案:
修改 UserContext.OnModelCreating 方法
配置一下 ApiUser.Guid
属性到Mysql数据库的映射:
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<ApiUser>().Property(p => p.Guid)
.HasColumnType("nvarchar(256)");
modelBuilder.Entity<ApiUser>().HasKey(u => u.Guid);
base.OnModelCreating(modelBuilder);
}
支持https
<p>将所有http请求全部映射到https</p>
<p>Startup中:<br>
ConfigureServices方法注册,并配置端口和状态码等:<br>
services.AddHttpsRedirection(…)</p>
<pre data-role="codeBlock" data-info class="language-"><code>services.AddHttpsRedirection(options =>
{
options.RedirectStatusCode = StatusCodes.Status307TemporaryRedirect;
options.HttpsPort = 5001;
});
Configure方法使用该中间件:
app.UseHttpsRedirection()
支持HSTS
<p>ConfigureServices方法注册<br>
看<a
href="https://docs.microsoft.com/en-us/aspnet/core/security/enforcing-ssl?view=aspnetcore-2.1&tabs=visual-studio#http-strict-transport-security-protocol-hsts">官方文档</a>
</p>
<pre data-role="codeBlock" data-info="CSharp" class="language-csharp">services<span class="token punctuation">.</span><span class="token function">AddHsts</span><span class="token punctuation">(</span>options <span class="token operator">=></span>
{
options.Preload = true;
options.IncludeSubDomains = true;
options.MaxAge = TimeSpan.FromDays(60);
options.ExcludedHosts.Add("example.com");
options.ExcludedHosts.Add("www.example.com");
});
Configure方法配置中间件管道
app.UseHsts();
注意 app.UseHsts() 方法最好放在 app.UseHttps()
方法之后.
使用SerilLog
<p>有关日志的<a
href="https://docs.microsoft.com/en-us/aspnet/core/fundamentals/logging/?view=aspnetcore-2.1">微软官方文档</a>
</p>
<p>SerilLog <a href="https://github.com/serilog/serilog-aspnetcore">github仓库</a><br>
该github仓库上有详细的使用说明.</p>
<p>使用方法:</p>
<h3 class="mume-header" id="%E5%AE%89%E8%A3%85nuget%E5%8C%85">安装nuget包</h3>
<ul>
<li>Serilog.AspNetCore</li>
<li>Serilog.Sinks.Console</li>
</ul>
<h3 class="mume-header" id="%E6%B7%BB%E5%8A%A0%E4%BB%A3%E7%A0%81">添加代码</h3>
<p>Program.Main方法中:</p>
<pre data-role="codeBlock" data-info="CSharp" class="language-csharp">Log<span class="token punctuation">.</span>Logger <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">LoggerConfiguration</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
<span class="token punctuation">.</span>MinimumLevel<span class="token punctuation">.</span><span class="token function">Debug</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
<span class="token punctuation">.</span>MinimumLevel<span class="token punctuation">.</span><span class="token function">Override</span><span class="token punctuation">(</span><span class="token string">"Microsoft"</span><span class="token punctuation">,</span> LogEventLevel<span class="token punctuation">.</span>Information<span class="token punctuation">)</span>
<span class="token punctuation">.</span>Enrich<span class="token punctuation">.</span><span class="token function">FromLogContext</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
<span class="token punctuation">.</span>WriteTo<span class="token punctuation">.</span><span class="token function">Console</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
<span class="token punctuation">.</span><span class="token function">CreateLogger</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
修改Program.CreateWebHostBuilder(...)
public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
WebHost.CreateDefaultBuilder(args)
.UseStartup<Startup>()
.UseSerilog(); // <-- Add this line;
}
自行测试
<h2 class="mume-header" id="aspnetcore%E9%85%8D%E7%BD%AE%E6%96%87%E4%BB%B6">
Asp.NetCore配置文件</h2>
<h3 class="mume-header" id="%E9%BB%98%E8%AE%A4%E9%85%8D%E7%BD%AE%E6%96%87%E4%BB%B6">
默认配置文件</h3>
<p>默认 appsettings.json<br>
ConfigurationBuilder().AddJsonFile("appsettings.json").Build()-->IConfigurationRoot(IConfiguration)
</p>
<h3 class="mume-header" id="%E8%8E%B7%E5%BE%97%E9%85%8D%E7%BD%AE">获得配置</h3>
<p>IConfiguration[“Key:ChildKey”]<br>
针对”ConnectionStrings:xxx”,可以使用IConfiguration.GetConnectionString(“xxx”)
</p>
<pre data-role="codeBlock" data-info class="language-"><code>private static IConfiguration Configuration { get; set; }
public StartupDevelopment(IConfiguration config)
{
Configuration = config;
}
...
Configuration[“Key:ChildKey”]
自定义一个异常处理,ExceptionHandler
<h3 class="mume-header"
id="%E5%BC%84%E4%B8%80%E4%B8%AA%E7%B1%BB%E5%86%99%E4%B8%80%E4%B8%AA%E6%89%A9%E5%B1%95%E6%96%B9%E6%B3%95%E5%A4%84%E7%90%86%E5%BC%82%E5%B8%B8">
弄一个类,写一个扩展方法处理异常
</h3>
<pre data-role="codeBlock" data-info="CSharp" class="language-csharp"><span class="token keyword">namespace</span> ApiStudy<span class="token punctuation">.</span>Api<span class="token punctuation">.</span>Extensions
{
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Logging;
using System;
<span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token keyword">class</span> <span class="token class-name">ExceptionHandlingExtensions</span>
<span class="token punctuation">{</span>
<span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token keyword">void</span> <span class="token function">UseCustomExceptionHandler</span><span class="token punctuation">(</span><span class="token keyword">this</span> <span class="token class-name">IApplicationBuilder</span> app<span class="token punctuation">,</span><span class="token class-name">ILoggerFactory</span> loggerFactory<span class="token punctuation">)</span>
<span class="token punctuation">{</span>
app<span class="token punctuation">.</span><span class="token function">UseExceptionHandler</span><span class="token punctuation">(</span>
builder <span class="token operator">=></span> builder<span class="token punctuation">.</span><span class="token function">Run</span><span class="token punctuation">(</span><span class="token keyword">async</span> context <span class="token operator">=></span>
<span class="token punctuation">{</span>
context<span class="token punctuation">.</span>Response<span class="token punctuation">.</span>StatusCode <span class="token operator">=</span> StatusCodes<span class="token punctuation">.</span>Status500InternalServerError<span class="token punctuation">;</span>
context<span class="token punctuation">.</span>Response<span class="token punctuation">.</span>ContentType <span class="token operator">=</span> <span class="token string">"application/json"</span><span class="token punctuation">;</span>
<span class="token class-name">Exception</span> ex <span class="token operator">=</span> context<span class="token punctuation">.</span>Features<span class="token punctuation">.</span><span class="token generic-method"><span class="token function">Get</span><span class="token punctuation"><</span><span class="token class-name">Exception</span><span class="token punctuation">></span></span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span><span class="token punctuation">(</span>ex <span class="token keyword">is</span> <span class="token keyword">null</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
<span class="token punctuation">{</span>
<span class="token class-name">ILogger</span> logger <span class="token operator">=</span> loggerFactory<span class="token punctuation">.</span><span class="token function">CreateLogger</span><span class="token punctuation">(</span><span class="token string">"ApiStudy.Api.Extensions.ExceptionHandlingExtensions"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
logger<span class="token punctuation">.</span><span class="token function">LogError</span><span class="token punctuation">(</span>ex<span class="token punctuation">,</span> <span class="token string">"Error occurred."</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token keyword">await</span> context<span class="token punctuation">.</span>Response<span class="token punctuation">.</span><span class="token function">WriteAsync</span><span class="token punctuation">(</span>ex<span class="token punctuation">?.</span>Message <span class="token operator">??</span> <span class="token string">"Error occurred, but cannot get exception message.For more detail, go to see the log."</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span>
}
在Configuration中使用扩展方法
<pre data-role="codeBlock" data-info="CSharp" class="language-csharp"><span class="token comment">// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.</span>
public void Configure(IApplicationBuilder app, ILoggerFactory loggerFactory)
{
app.UseCustomExceptionHandler(loggerFactory); //modified code
<span class="token comment">//app.UseDeveloperExceptionPage();</span>
app<span class="token punctuation">.</span><span class="token function">UseHsts</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
app<span class="token punctuation">.</span><span class="token function">UseHttpsRedirection</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
app<span class="token punctuation">.</span><span class="token function">UseMvc</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">//使用默认路由</span>
}
实现数据接口类(Resource),使用AutoMapper在Resource和Entity中映射
<h3 class="mume-header"
id="91-a-nameentityresourcea%E4%B8%BAentity%E7%B1%BB%E5%88%9B%E5%BB%BA%E5%AF%B9%E5%BA%94%E7%9A%84resource%E7%B1%BB">
9.1. <a name="EntityResource"
href></a>为Entity类创建对应的Resource类</h3>
<details>
<summary>ApiUserResource</summary>
<pre data-role="codeBlock" data-info="CSharp" class="language-csharp"><span class="token keyword">namespace</span> ApiStudy<span class="token punctuation">.</span>Infrastructure<span class="token punctuation">.</span>Resources
{
using System;
<span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">ApiUserResource</span>
<span class="token punctuation">{</span>
<span class="token keyword">public</span> <span class="token class-name">Guid</span> Guid <span class="token punctuation">{</span> <span class="token keyword">get</span><span class="token punctuation">;</span> <span class="token keyword">set</span><span class="token punctuation">;</span> <span class="token punctuation">}</span>
<span class="token keyword">public</span> <span class="token keyword">string</span> Name <span class="token punctuation">{</span> <span class="token keyword">get</span><span class="token punctuation">;</span> <span class="token keyword">set</span><span class="token punctuation">;</span> <span class="token punctuation">}</span>
<span class="token comment">//public string Passwd { get; set; }</span>
<span class="token keyword">public</span> <span class="token class-name">DateTime</span> RegistrationDate <span class="token punctuation">{</span> <span class="token keyword">get</span><span class="token punctuation">;</span> <span class="token keyword">set</span><span class="token punctuation">;</span> <span class="token punctuation">}</span>
<span class="token keyword">public</span> <span class="token class-name">DateTime</span> Birth <span class="token punctuation">{</span> <span class="token keyword">get</span><span class="token punctuation">;</span> <span class="token keyword">set</span><span class="token punctuation">;</span> <span class="token punctuation">}</span>
<span class="token keyword">public</span> <span class="token keyword">string</span> ProfilePhotoUrl <span class="token punctuation">{</span> <span class="token keyword">get</span><span class="token punctuation">;</span> <span class="token keyword">set</span><span class="token punctuation">;</span> <span class="token punctuation">}</span>
<span class="token keyword">public</span> <span class="token keyword">string</span> PhoneNumber <span class="token punctuation">{</span> <span class="token keyword">get</span><span class="token punctuation">;</span> <span class="token keyword">set</span><span class="token punctuation">;</span> <span class="token punctuation">}</span>
<span class="token keyword">public</span> <span class="token keyword">string</span> Email <span class="token punctuation">{</span> <span class="token keyword">get</span><span class="token punctuation">;</span> <span class="token keyword">set</span><span class="token punctuation">;</span> <span class="token punctuation">}</span>
<span class="token punctuation">}</span>
}
使用 AutoMapper
<ul>
<li>
<p>添加nuget包<br>
<code>AutoMapper</code><br>
<code>AutoMapper.Extensions.Microsoft.DependencyInjection</code></p>
</li>
<li>
<p>配置映射<br>
可以创建Profile<br>
CreateMap<TSource,TDestination>()</p>
<details>
<summary>MappingProfile</summary>
<pre data-role="codeBlock" data-info="CSharp" class="language-csharp"><span class="token keyword">namespace</span> ApiStudy<span class="token punctuation">.</span>Api<span class="token punctuation">.</span>Extensions
{
using ApiStudy.Core.Entities;
using ApiStudy.Infrastructure.Resources;
using AutoMapper;
using System;
using System.Text;
<span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">MappingProfile</span> <span class="token punctuation">:</span> <span class="token class-name">Profile</span>
<span class="token punctuation">{</span>
<span class="token keyword">public</span> <span class="token function">MappingProfile</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
<span class="token punctuation">{</span>
<span class="token generic-method"><span class="token function">CreateMap</span><span class="token punctuation"><</span><span class="token class-name">ApiUser</span><span class="token punctuation">,</span> <span class="token class-name">ApiUserResource</span><span class="token punctuation">></span></span><span class="token punctuation">(</span><span class="token punctuation">)</span>
<span class="token punctuation">.</span><span class="token function">ForMember</span><span class="token punctuation">(</span>
d <span class="token operator">=></span> d<span class="token punctuation">.</span>Passwd<span class="token punctuation">,</span>
opt <span class="token operator">=></span> opt<span class="token punctuation">.</span><span class="token function">AddTransform</span><span class="token punctuation">(</span>s <span class="token operator">=></span> Convert<span class="token punctuation">.</span><span class="token function">ToBase64String</span><span class="token punctuation">(</span>Encoding<span class="token punctuation">.</span>Default<span class="token punctuation">.</span><span class="token function">GetBytes</span><span class="token punctuation">(</span>s<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token generic-method"><span class="token function">CreateMap</span><span class="token punctuation"><</span><span class="token class-name">ApiUserResource</span><span class="token punctuation">,</span> <span class="token class-name">ApiUser</span><span class="token punctuation">></span></span><span class="token punctuation">(</span><span class="token punctuation">)</span>
<span class="token punctuation">.</span><span class="token function">ForMember</span><span class="token punctuation">(</span>
d <span class="token operator">=></span> d<span class="token punctuation">.</span>Passwd<span class="token punctuation">,</span>
opt <span class="token operator">=></span> opt<span class="token punctuation">.</span><span class="token function">AddTransform</span><span class="token punctuation">(</span>s <span class="token operator">=></span> Encoding<span class="token punctuation">.</span>Default<span class="token punctuation">.</span><span class="token function">GetString</span><span class="token punctuation">(</span>Convert<span class="token punctuation">.</span><span class="token function">FromBase64String</span><span class="token punctuation">(</span>s<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span>
}
注入服务 -> services.AddAutoMapper()
使用FluentValidation
<p><a href="https://fluentvalidation.net/">FluentValidation官网</a></p>
<h3 class="mume-header" id="%E5%AE%89%E8%A3%85nuget%E5%8C%85-1">安装Nuget包</h3>
<ul>
<li>FluentValidation</li>
<li>FluentValidation.AspNetCore</li>
</ul>
<h3 class="mume-header"
id="%E4%B8%BA%E6%AF%8F%E4%B8%80%E4%B8%AAresource%E9%85%8D%E7%BD%AE%E9%AA%8C%E8%AF%81%E5%99%A8">
为每一个Resource配置验证器</h3>
<ul>
<li>
<p>继承于AbstractValidator</p>
<details>
<summary>ApiUserResourceValidator </summary>
<pre data-role="codeBlock" data-info="CSharp" class="language-csharp"><span class="token keyword">namespace</span> ApiStudy<span class="token punctuation">.</span>Infrastructure<span class="token punctuation">.</span>Resources
{
using FluentValidation;
<span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">ApiUserResourceValidator</span> <span class="token punctuation">:</span> <span class="token class-name">AbstractValidator</span><span class="token operator"><</span>ApiUserResource<span class="token operator">></span>
<span class="token punctuation">{</span>
<span class="token keyword">public</span> <span class="token function">ApiUserResourceValidator</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
<span class="token punctuation">{</span>
<span class="token function">RuleFor</span><span class="token punctuation">(</span>s <span class="token operator">=></span> s<span class="token punctuation">.</span>Name<span class="token punctuation">)</span>
<span class="token punctuation">.</span><span class="token function">MaximumLength</span><span class="token punctuation">(</span><span class="token number">80</span><span class="token punctuation">)</span>
<span class="token punctuation">.</span><span class="token function">WithName</span><span class="token punctuation">(</span><span class="token string">"用户名"</span><span class="token punctuation">)</span>
<span class="token punctuation">.</span><span class="token function">WithMessage</span><span class="token punctuation">(</span><span class="token string">"{PropertyName}的最大长度为80"</span><span class="token punctuation">)</span>
<span class="token punctuation">.</span><span class="token function">NotEmpty</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
<span class="token punctuation">.</span><span class="token function">WithMessage</span><span class="token punctuation">(</span><span class="token string">"{PropertyName}不能为空!"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span>
}
注册到容器:services.AddTransient<>()
services.AddTransient<IValidator<ApiUserResource>,
ApiUserResourceValidator>();
实现Http Get(翻页,过滤,排序)
<details>
<summary>基本的Get实现</summary>
<pre data-role="codeBlock" data-info="CSharp" class="language-csharp"><span class="token punctuation">[</span><span class="token class-name">HttpGet</span><span class="token punctuation">]</span>
public async Task<IActionResult> Get()
{
IEnumerable<ApiUser> apiUsers = await _apiUserRepository.GetAllApiUsersAsync();
IEnumerable<span class="token operator"><</span>ApiUserResource<span class="token operator">></span> apiUserResources <span class="token operator">=</span>
_mapper<span class="token punctuation">.</span>Map<span class="token operator"><</span>IEnumerable<span class="token operator"><</span>ApiUser<span class="token operator">></span><span class="token punctuation">,</span>IEnumerable<span class="token operator"><</span>ApiUserResource<span class="token operator">>></span><span class="token punctuation">(</span>apiUsers<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">return</span> <span class="token function">Ok</span><span class="token punctuation">(</span>apiUserResources<span class="token punctuation">)</span><span class="token punctuation">;</span>
}
[HttpGet("{guid}")]
public async Task<IActionResult> Get(string guid)
{
ApiUser apiUser = await _apiUserRepository.GetApiUserByGuidAsync(Guid.Parse(guid));
<span class="token keyword">if</span> <span class="token punctuation">(</span>apiUser <span class="token keyword">is</span> <span class="token keyword">null</span><span class="token punctuation">)</span> <span class="token keyword">return</span> <span class="token function">NotFound</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token class-name">ApiUserResource</span> apiUserResource <span class="token operator">=</span> _mapper<span class="token punctuation">.</span><span class="token generic-method"><span class="token function">Map</span><span class="token punctuation"><</span><span class="token class-name">ApiUser</span><span class="token punctuation">,</span><span class="token class-name">ApiUserResource</span><span class="token punctuation">></span></span><span class="token punctuation">(</span>apiUser<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">return</span> <span class="token function">Ok</span><span class="token punctuation">(</span>apiUserResource<span class="token punctuation">)</span><span class="token punctuation">;</span>
}
资源命名
<h4 class="mume-header" id="%E8%B5%84%E6%BA%90%E5%BA%94%E8%AF%A5%E4%BD%BF%E7%94%A8%E5%90%8D%E8%AF%8D%E4%BE%8B">
资源应该使用名词,例</h4>
<ul>
<li>api/getusers就是不正确的.</li>
<li><strong>GET api/users</strong>就是正确的</li>
</ul>
<h4 class="mume-header" id="%E8%B5%84%E6%BA%90%E5%91%BD%E5%90%8D%E5%B1%82%E6%AC%A1%E7%BB%93%E6%9E%84">
资源命名层次结构</h4>
<ul>
<li>例如<code>api/department/{departmentId}/emoloyees</code>,
这就表示了 <code>department</code>
(部门)和员工<br>
(<strong>employee</strong>)之前是主从关系.</li>
<li>而<code>api/department/{departmentId}/emoloyees/{employeeId}</code>,就表示了该部门下的某个员<br>
工.</li>
</ul>
<h3 class="mume-header" id="%E5%86%85%E5%AE%B9%E5%8D%8F%E5%95%86">内容协商</h3>
<p><a href="http://ASP.NET">ASP.NET</a>
Core支持输出和输入两种格式化器.
</p>
<ul>
<li>用于输出的media type放在<strong>Accept
Header</strong>里,表示客户端接受这种格式的输出.
</li>
<li>用于输入的media type放<strong>Content-Type</strong>
Header里,表示客户端传进来的数据是这种格式.
</li>
<li><strong>ReturnHttpNotAcceptable</strong>设为true,如果客户端请求不支持的数据格式,就会返回406.
<pre data-role="codeBlock" data-info class="language-"><code>services.AddMvc(options =>
{
options.ReturnHttpNotAcceptable = true;
});
options.OutputFormatters.Add(newXmlDataContractSerializerOutputFormatter());
翻页
<h3 class="mume-header" id="%E6%9E%84%E9%80%A0%E7%BF%BB%E9%A1%B5%E8%AF%B7%E6%B1%82%E5%8F%82%E6%95%B0%E7%B1%BB">
构造翻页请求参数类</h3>
<details>
<summary>QueryParameters</summary>
<pre data-role="codeBlock" data-info="CSharp" class="language-csharp"><span class="token keyword">namespace</span> ApiStudy<span class="token punctuation">.</span>Core<span class="token punctuation">.</span>Entities
{
using System.Collections.Generic;
using System.ComponentModel;
using System.Runtime.CompilerServices;
<span class="token keyword">public</span> <span class="token keyword">abstract</span> <span class="token keyword">class</span> <span class="token class-name">QueryParameters</span> <span class="token punctuation">:</span> <span class="token class-name">INotifyPropertyChanged</span>
<span class="token punctuation">{</span>
<span class="token keyword">public</span> <span class="token keyword">event</span> <span class="token class-name">PropertyChangedEventHandler</span> PropertyChanged<span class="token punctuation">;</span>
<span class="token keyword">private</span> <span class="token keyword">const</span> <span class="token keyword">int</span> DefaultPageSize <span class="token operator">=</span> <span class="token number">10</span><span class="token punctuation">;</span>
<span class="token keyword">private</span> <span class="token keyword">const</span> <span class="token keyword">int</span> DefaultMaxPageSize <span class="token operator">=</span> <span class="token number">100</span><span class="token punctuation">;</span>
<span class="token keyword">private</span> <span class="token keyword">int</span> _pageIndex <span class="token operator">=</span> <span class="token number">1</span><span class="token punctuation">;</span>
<span class="token keyword">public</span> <span class="token keyword">virtual</span> <span class="token keyword">int</span> PageIndex
<span class="token punctuation">{</span>
<span class="token keyword">get</span> <span class="token operator">=></span> _pageIndex<span class="token punctuation">;</span>
<span class="token keyword">set</span> <span class="token operator">=></span> <span class="token function">SetField</span><span class="token punctuation">(</span><span class="token keyword">ref</span> _pageIndex<span class="token punctuation">,</span> <span class="token keyword">value</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token keyword">private</span> <span class="token keyword">int</span> _pageSize <span class="token operator">=</span> DefaultPageSize<span class="token punctuation">;</span>
<span class="token keyword">public</span> <span class="token keyword">virtual</span> <span class="token keyword">int</span> PageSize
<span class="token punctuation">{</span>
<span class="token keyword">get</span> <span class="token operator">=></span> _pageSize<span class="token punctuation">;</span>
<span class="token keyword">set</span> <span class="token operator">=></span> <span class="token function">SetField</span><span class="token punctuation">(</span><span class="token keyword">ref</span> _pageSize<span class="token punctuation">,</span> <span class="token keyword">value</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token keyword">private</span> <span class="token keyword">int</span> _maxPageSize <span class="token operator">=</span> DefaultMaxPageSize<span class="token punctuation">;</span>
<span class="token keyword">public</span> <span class="token keyword">virtual</span> <span class="token keyword">int</span> MaxPageSize
<span class="token punctuation">{</span>
<span class="token keyword">get</span> <span class="token operator">=></span> _maxPageSize<span class="token punctuation">;</span>
<span class="token keyword">set</span> <span class="token operator">=></span> <span class="token function">SetField</span><span class="token punctuation">(</span><span class="token keyword">ref</span> _maxPageSize<span class="token punctuation">,</span> <span class="token keyword">value</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token keyword">public</span> <span class="token keyword">string</span> OrderBy <span class="token punctuation">{</span> <span class="token keyword">get</span><span class="token punctuation">;</span> <span class="token keyword">set</span><span class="token punctuation">;</span> <span class="token punctuation">}</span>
<span class="token keyword">public</span> <span class="token keyword">string</span> Fields <span class="token punctuation">{</span> <span class="token keyword">get</span><span class="token punctuation">;</span> <span class="token keyword">set</span><span class="token punctuation">;</span> <span class="token punctuation">}</span>
<span class="token keyword">protected</span> <span class="token keyword">void</span> <span class="token generic-method"><span class="token function">SetField</span><span class="token punctuation"><</span><span class="token class-name">TField</span><span class="token punctuation">></span></span><span class="token punctuation">(</span>
<span class="token keyword">ref</span> <span class="token class-name">TField</span> field<span class="token punctuation">,</span><span class="token keyword">in</span> <span class="token class-name">TField</span> newValue<span class="token punctuation">,</span><span class="token punctuation">[</span><span class="token class-name">CallerMemberName</span><span class="token punctuation">]</span> <span class="token keyword">string</span> propertyName <span class="token operator">=</span> <span class="token keyword">null</span><span class="token punctuation">)</span>
<span class="token punctuation">{</span>
<span class="token keyword">if</span> <span class="token punctuation">(</span>EqualityComparer<span class="token operator"><</span>TField<span class="token operator">></span><span class="token punctuation">.</span>Default<span class="token punctuation">.</span><span class="token function">Equals</span><span class="token punctuation">(</span>field<span class="token punctuation">,</span> newValue<span class="token punctuation">)</span><span class="token punctuation">)</span>
<span class="token keyword">return</span><span class="token punctuation">;</span>
field <span class="token operator">=</span> newValue<span class="token punctuation">;</span>
<span class="token keyword">if</span> <span class="token punctuation">(</span>propertyName <span class="token operator">==</span> <span class="token function">nameof</span><span class="token punctuation">(</span>PageSize<span class="token punctuation">)</span> <span class="token operator">||</span> propertyName <span class="token operator">==</span> <span class="token function">nameof</span><span class="token punctuation">(</span>MaxPageSize<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token function">SetPageSize</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
PropertyChanged<span class="token punctuation">?.</span><span class="token function">Invoke</span><span class="token punctuation">(</span><span class="token keyword">this</span><span class="token punctuation">,</span> <span class="token keyword">new</span> <span class="token class-name">PropertyChangedEventArgs</span><span class="token punctuation">(</span>propertyName<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token keyword">private</span> <span class="token keyword">void</span> <span class="token function">SetPageSize</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
<span class="token punctuation">{</span>
<span class="token keyword">if</span> <span class="token punctuation">(</span>_maxPageSize <span class="token operator"><=</span> <span class="token number">0</span><span class="token punctuation">)</span> _maxPageSize <span class="token operator">=</span> DefaultMaxPageSize<span class="token punctuation">;</span>
<span class="token keyword">if</span> <span class="token punctuation">(</span>_pageSize <span class="token operator"><=</span> <span class="token number">0</span><span class="token punctuation">)</span> _pageSize <span class="token operator">=</span> DefaultPageSize<span class="token punctuation">;</span>
_pageSize <span class="token operator">=</span> _pageSize <span class="token operator">></span> _maxPageSize <span class="token punctuation">?</span> _maxPageSize <span class="token punctuation">:</span> _pageSize<span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span>
}
namespace ApiStudy.Core.Entities
{
public class ApiUserParameters:QueryParameters
{
public string UserName { get; set; }
}
}
Repository实现支持翻页请求参数的方法
<details>
<summary>Repository相关代码</summary>
<pre data-role="codeBlock" data-info="CSharp" class="language-csharp"><span class="token comment">/*----- ApiUserRepository -----*/</span>
public PaginatedList<ApiUser> GetAllApiUsers(ApiUserParameters parameters)
{
return new PaginatedList<ApiUser>(
parameters.PageIndex,
parameters.PageSize,
_context.ApiUsers.Count(),
_context.ApiUsers.Skip(parameters.PageIndex * parameters.PageSize)
.Take(parameters.PageSize));
}
public Task<PaginatedList<ApiUser>> GetAllApiUsersAsync(ApiUserParameters parameters)
{
return Task.Run(() => GetAllApiUsers(parameters));
}
/----- IApiUserRepository -----/
PaginatedList<ApiUser> GetAllApiUsers(ApiUserParameters parameters);
Task<PaginatedList<ApiUser>> GetAllApiUsersAsync(ApiUserParameters parameters);
UserController部分代码
... [HttpGet(Name = "GetAllApiUsers")]
public async Task<IActionResult> GetAllApiUsers(ApiUserParameters parameters)
{
PaginatedList<ApiUser> apiUsers = await _apiUserRepository.GetAllApiUsersAsync(parameters);IEnumerable<span class="token operator"><</span>ApiUserResource<span class="token operator">></span> apiUserResources <span class="token operator">=</span>
_mapper<span class="token punctuation">.</span>Map<span class="token operator"><</span>IEnumerable<span class="token operator"><</span>ApiUser<span class="token operator">></span><span class="token punctuation">,</span>IEnumerable<span class="token operator"><</span>ApiUserResource<span class="token operator">>></span><span class="token punctuation">(</span>apiUsers<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">var</span> meta <span class="token operator">=</span> <span class="token keyword">new</span>
<span class="token punctuation">{</span>
PageIndex <span class="token operator">=</span> apiUsers<span class="token punctuation">.</span>PageIndex<span class="token punctuation">,</span>
PageSize <span class="token operator">=</span> apiUsers<span class="token punctuation">.</span>PageSize<span class="token punctuation">,</span>
PageCount <span class="token operator">=</span> apiUsers<span class="token punctuation">.</span>PageCount<span class="token punctuation">,</span>
TotalItemsCount <span class="token operator">=</span> apiUsers<span class="token punctuation">.</span>TotalItemsCount<span class="token punctuation">,</span>
NextPageUrl <span class="token operator">=</span> <span class="token function">CreateApiUserUrl</span><span class="token punctuation">(</span>parameters<span class="token punctuation">,</span> ResourceUriType<span class="token punctuation">.</span>NextPage<span class="token punctuation">)</span><span class="token punctuation">,</span>
PreviousPageUrl <span class="token operator">=</span> <span class="token function">CreateApiUserUrl</span><span class="token punctuation">(</span>parameters<span class="token punctuation">,</span> ResourceUriType<span class="token punctuation">.</span>PreviousPage<span class="token punctuation">)</span>
<span class="token punctuation">}</span><span class="token punctuation">;</span>
Response<span class="token punctuation">.</span>Headers<span class="token punctuation">.</span><span class="token function">Add</span><span class="token punctuation">(</span>
<span class="token string">"X-Pagination"</span><span class="token punctuation">,</span>
JsonConvert<span class="token punctuation">.</span><span class="token function">SerializeObject</span><span class="token punctuation">(</span>
meta<span class="token punctuation">,</span>
<span class="token keyword">new</span> <span class="token class-name">JsonSerializerSettings</span>
<span class="token punctuation">{</span> ContractResolver <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">CamelCasePropertyNamesContractResolver</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">return</span> <span class="token function">Ok</span><span class="token punctuation">(</span>apiUserResources<span class="token punctuation">)</span><span class="token punctuation">;</span>
}
...
private string CreateApiUserUrl(ApiUserParameters parameters,ResourceUriType uriType)
{
var param = new ApiUserParameters
{
PageIndex = parameters.PageIndex,
PageSize = parameters.PageSize
};
switch (uriType)
{
case ResourceUriType.PreviousPage:
param.PageIndex--;
break;
case ResourceUriType.NextPage:
param.PageIndex++;
break;
case ResourceUriType.CurrentPage:
break;
default:break;
}
return Url.Link("GetAllApiUsers", parameters);
}
PS注意,为HttpGet方法添加参数的话,在.net
core2.2版本下,去掉那个ApiUserController上的
[ApiController());] 特性,否则参数传不进来..net
core3.0中据说已经修复这个问题.
搜索(过滤)
<p>修改Repository代码:</p>
<pre data-role="codeBlock" data-info="CSharp" class="language-csharp"> <span class="token keyword">public</span> PaginatedList<span class="token operator"><</span>ApiUser<span class="token operator">></span> <span class="token function">GetAllApiUsers</span><span class="token punctuation">(</span><span class="token class-name">ApiUserParameters</span> parameters<span class="token punctuation">)</span>
{
IQueryable<ApiUser> query = _context.ApiUsers.AsQueryable();
query = query.Skip(parameters.PageIndex * parameters.PageSize)
.Take(parameters.PageSize);
<span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span><span class="token keyword">string</span><span class="token punctuation">.</span><span class="token function">IsNullOrEmpty</span><span class="token punctuation">(</span>parameters<span class="token punctuation">.</span>UserName<span class="token punctuation">)</span><span class="token punctuation">)</span>
query <span class="token operator">=</span> _context<span class="token punctuation">.</span>ApiUsers<span class="token punctuation">.</span><span class="token function">Where</span><span class="token punctuation">(</span>
x <span class="token operator">=></span> StringComparer<span class="token punctuation">.</span>OrdinalIgnoreCase<span class="token punctuation">.</span><span class="token function">Compare</span><span class="token punctuation">(</span>x<span class="token punctuation">.</span>Name<span class="token punctuation">,</span> parameters<span class="token punctuation">.</span>UserName<span class="token punctuation">)</span> <span class="token operator">==</span> <span class="token number">0</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">return</span> <span class="token keyword">new</span> <span class="token generic-method"><span class="token function">PaginatedList</span><span class="token punctuation"><</span><span class="token class-name">ApiUser</span><span class="token punctuation">></span></span><span class="token punctuation">(</span>
parameters<span class="token punctuation">.</span>PageIndex<span class="token punctuation">,</span>
parameters<span class="token punctuation">.</span>PageSize<span class="token punctuation">,</span>
query<span class="token punctuation">.</span><span class="token function">Count</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
query<span class="token punctuation">)</span><span class="token punctuation">;</span>
}
排序
<h4 class="mume-header" id="%E6%8E%92%E5%BA%8F%E6%80%9D%E8%B7%AF">>排序思路</h4>
<ul>
<li>需要安装System.Linq.Dynamic.Core</li>
</ul>
<p><strong>思路</strong>:</p>
<ul>
<li>PropertyMappingContainer
<ul>
<li>PropertyMapping(ApiUserPropertyMapping)
<ul>
<li>MappedProperty</li>
</ul>
</li>
</ul>
</li>
</ul>
<details>
<summary>MappedProperty</summary>
<pre data-role="codeBlock" data-info="CSharp" class="language-csharp"><span class="token keyword">namespace</span> ApiStudy<span class="token punctuation">.</span>Infrastructure<span class="token punctuation">.</span>Services
{
public struct MappedProperty
{
public MappedProperty(string name, bool revert = false)
{
Name = name;
Revert = revert;
}
<span class="token keyword">public</span> <span class="token keyword">string</span> Name <span class="token punctuation">{</span> <span class="token keyword">get</span><span class="token punctuation">;</span> <span class="token keyword">set</span><span class="token punctuation">;</span> <span class="token punctuation">}</span>
<span class="token keyword">public</span> <span class="token keyword">bool</span> Revert <span class="token punctuation">{</span> <span class="token keyword">get</span><span class="token punctuation">;</span> <span class="token keyword">set</span><span class="token punctuation">;</span> <span class="token punctuation">}</span>
<span class="token punctuation">}</span>
}
namespace ApiStudy.Infrastructure.Services
{
using System.Collections.Generic;<span class="token keyword">public</span> <span class="token keyword">interface</span> <span class="token class-name">IPropertyMapping</span>
<span class="token punctuation">{</span>
Dictionary<span class="token operator"><</span><span class="token keyword">string</span><span class="token punctuation">,</span> List<span class="token operator"><</span>MappedProperty<span class="token operator">>></span> MappingDictionary <span class="token punctuation">{</span> <span class="token keyword">get</span><span class="token punctuation">;</span> <span class="token punctuation">}</span>
<span class="token punctuation">}</span>
}
namespace ApiStudy.Infrastructure.Services
{
using System.Collections.Generic;<span class="token keyword">public</span> <span class="token keyword">abstract</span> <span class="token keyword">class</span> <span class="token class-name">PropertyMapping</span><span class="token operator"><</span>TSource<span class="token punctuation">,</span>TDestination<span class="token operator">></span> <span class="token punctuation">:</span> IPropertyMapping
<span class="token punctuation">{</span>
<span class="token keyword">public</span> Dictionary<span class="token operator"><</span><span class="token keyword">string</span><span class="token punctuation">,</span> List<span class="token operator"><</span>MappedProperty<span class="token operator">>></span> MappingDictionary <span class="token punctuation">{</span> <span class="token keyword">get</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword">public</span> <span class="token function">PropertyMapping</span><span class="token punctuation">(</span>Dictionary<span class="token operator"><</span><span class="token keyword">string</span><span class="token punctuation">,</span> List<span class="token operator"><</span>MappedProperty<span class="token operator">>></span> MappingDict<span class="token punctuation">)</span>
<span class="token punctuation">{</span>
MappingDictionary <span class="token operator">=</span> MappingDict<span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span>
}
namespace ApiStudy.Infrastructure.Services
{
public interface IPropertyMappingContainer
{
void Register<T>() where T : IPropertyMapping, new();
IPropertyMapping Resolve<TSource, TDestination>();
bool ValidateMappingExistsFor<TSource, TDestination>(string fields);
}
}
namespace ApiStudy.Infrastructure.Services
{
using System;
using System.Linq;
using System.Collections.Generic;<span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">PropertyMappingContainer</span> <span class="token punctuation">:</span> <span class="token class-name">IPropertyMappingContainer</span>
<span class="token punctuation">{</span>
<span class="token keyword">protected</span> <span class="token keyword">internal</span> <span class="token keyword">readonly</span> IList<span class="token operator"><</span>IPropertyMapping<span class="token operator">></span> PropertyMappings <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token generic-method"><span class="token function">List</span><span class="token punctuation"><</span><span class="token class-name">IPropertyMapping</span><span class="token punctuation">></span></span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token generic-method"><span class="token function">Register</span><span class="token punctuation"><</span><span class="token class-name">T</span><span class="token punctuation">></span></span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token keyword">where</span> T <span class="token punctuation">:</span> IPropertyMapping<span class="token punctuation">,</span> <span class="token keyword">new</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
<span class="token punctuation">{</span>
<span class="token keyword">if</span> <span class="token punctuation">(</span>PropertyMappings<span class="token punctuation">.</span><span class="token function">Any</span><span class="token punctuation">(</span>x <span class="token operator">=></span> x<span class="token punctuation">.</span><span class="token function">GetType</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">==</span> <span class="token keyword">typeof</span><span class="token punctuation">(</span>T<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token keyword">return</span><span class="token punctuation">;</span>
PropertyMappings<span class="token punctuation">.</span><span class="token function">Add</span><span class="token punctuation">(</span><span class="token keyword">new</span> <span class="token class-name">T</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span> <span class="token keyword">public</span> IPropertyMapping <span class="token generic-method"><span class="token function">Resolve</span><span class="token punctuation"><</span><span class="token class-name">TSource</span><span class="token punctuation">,</span><span class="token class-name">TDestination</span><span class="token punctuation">></span></span><span class="token punctuation">(</span><span class="token punctuation">)</span>
<span class="token punctuation">{</span>
IEnumerable<span class="token operator"><</span>PropertyMapping<span class="token operator"><</span>TSource<span class="token punctuation">,</span> TDestination<span class="token operator">>></span> result <span class="token operator">=</span> PropertyMappings<span class="token punctuation">.</span>OfType<span class="token operator"><</span>PropertyMapping<span class="token operator"><</span>TSource<span class="token punctuation">,</span>TDestination<span class="token operator">>></span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">if</span> <span class="token punctuation">(</span>result<span class="token punctuation">.</span><span class="token function">Count</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator">></span> <span class="token number">0</span><span class="token punctuation">)</span>
<span class="token keyword">return</span> result<span class="token punctuation">.</span><span class="token function">First</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">throw</span> <span class="token keyword">new</span> <span class="token class-name">InvalidCastException</span><span class="token punctuation">(</span>
<span class="token keyword">string</span><span class="token punctuation">.</span><span class="token function">Format</span><span class="token punctuation">(</span> <span class="token string">"Cannot find property mapping instance for {0}, {1}"</span><span class="token punctuation">,</span> <span class="token keyword">typeof</span><span class="token punctuation">(</span>TSource<span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token keyword">typeof</span><span class="token punctuation">(</span>TDestination<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span> <span class="token keyword">public</span> <span class="token keyword">bool</span> <span class="token generic-method"><span class="token function">ValidateMappingExistsFor</span><span class="token punctuation"><</span><span class="token class-name">TSource</span><span class="token punctuation">,</span> <span class="token class-name">TDestination</span><span class="token punctuation">></span></span><span class="token punctuation">(</span><span class="token keyword">string</span> fields<span class="token punctuation">)</span>
<span class="token punctuation">{</span>
<span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token keyword">string</span><span class="token punctuation">.</span><span class="token function">IsNullOrEmpty</span><span class="token punctuation">(</span>fields<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token keyword">return</span> <span class="token keyword">true</span><span class="token punctuation">;</span> <span class="token class-name">IPropertyMapping</span> propertyMapping <span class="token operator">=</span> <span class="token generic-method"><span class="token function">Resolve</span><span class="token punctuation"><</span><span class="token class-name">TSource</span><span class="token punctuation">,</span> <span class="token class-name">TDestination</span><span class="token punctuation">></span></span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">string</span><span class="token punctuation">[</span><span class="token punctuation">]</span> splitFields <span class="token operator">=</span> fields<span class="token punctuation">.</span><span class="token function">Split</span><span class="token punctuation">(</span><span class="token string">','</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">foreach</span><span class="token punctuation">(</span><span class="token keyword">string</span> property <span class="token keyword">in</span> splitFields<span class="token punctuation">)</span>
<span class="token punctuation">{</span>
<span class="token keyword">string</span> trimmedProperty <span class="token operator">=</span> property<span class="token punctuation">.</span><span class="token function">Trim</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">int</span> indexOfFirstWhiteSpace <span class="token operator">=</span> trimmedProperty<span class="token punctuation">.</span><span class="token function">IndexOf</span><span class="token punctuation">(</span><span class="token string">' '</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">string</span> propertyName <span class="token operator">=</span> indexOfFirstWhiteSpace <span class="token operator"><=</span> <span class="token number">0</span> <span class="token punctuation">?</span> trimmedProperty <span class="token punctuation">:</span> trimmedProperty<span class="token punctuation">.</span><span class="token function">Remove</span><span class="token punctuation">(</span>indexOfFirstWhiteSpace<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span>propertyMapping<span class="token punctuation">.</span>MappingDictionary<span class="token punctuation">.</span>Keys<span class="token punctuation">.</span><span class="token function">Any</span><span class="token punctuation">(</span>x <span class="token operator">=></span> <span class="token keyword">string</span><span class="token punctuation">.</span><span class="token function">Equals</span><span class="token punctuation">(</span>propertyName<span class="token punctuation">,</span>x<span class="token punctuation">,</span>StringComparison<span class="token punctuation">.</span>OrdinalIgnoreCase<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token keyword">return</span> <span class="token keyword">false</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token keyword">return</span> <span class="token keyword">true</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span>
}
namespace ApiStudy.Infrastructure.Extensions
{
using ApiStudy.Infrastructure.Services;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Dynamic.Core;<span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token keyword">class</span> <span class="token class-name">QueryExtensions</span>
<span class="token punctuation">{</span>
<span class="token keyword">public</span> <span class="token keyword">static</span> IQueryable<span class="token operator"><</span>T<span class="token operator">></span> <span class="token generic-method"><span class="token function">ApplySort</span><span class="token punctuation"><</span><span class="token class-name">T</span><span class="token punctuation">></span></span><span class="token punctuation">(</span>
<span class="token keyword">this</span> IQueryable<span class="token operator"><</span>T<span class="token operator">></span> data<span class="token punctuation">,</span><span class="token keyword">in</span> <span class="token keyword">string</span> orderBy<span class="token punctuation">,</span><span class="token keyword">in</span> <span class="token class-name">IPropertyMapping</span> propertyMapping<span class="token punctuation">)</span>
<span class="token punctuation">{</span>
<span class="token keyword">if</span> <span class="token punctuation">(</span>data <span class="token operator">==</span> <span class="token keyword">null</span><span class="token punctuation">)</span> <span class="token keyword">throw</span> <span class="token keyword">new</span> <span class="token class-name">ArgumentNullException</span><span class="token punctuation">(</span><span class="token function">nameof</span><span class="token punctuation">(</span>data<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token keyword">string</span><span class="token punctuation">.</span><span class="token function">IsNullOrEmpty</span><span class="token punctuation">(</span>orderBy<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token keyword">return</span> data<span class="token punctuation">;</span> <span class="token keyword">string</span><span class="token punctuation">[</span><span class="token punctuation">]</span> splitOrderBy <span class="token operator">=</span> orderBy<span class="token punctuation">.</span><span class="token function">Split</span><span class="token punctuation">(</span><span class="token string">','</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">foreach</span><span class="token punctuation">(</span><span class="token keyword">string</span> property <span class="token keyword">in</span> splitOrderBy<span class="token punctuation">)</span>
<span class="token punctuation">{</span>
<span class="token keyword">string</span> trimmedProperty <span class="token operator">=</span> property<span class="token punctuation">.</span><span class="token function">Trim</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">int</span> indexOfFirstSpace <span class="token operator">=</span> trimmedProperty<span class="token punctuation">.</span><span class="token function">IndexOf</span><span class="token punctuation">(</span><span class="token string">' '</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">bool</span> desc <span class="token operator">=</span> trimmedProperty<span class="token punctuation">.</span><span class="token function">EndsWith</span><span class="token punctuation">(</span><span class="token string">" desc"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">string</span> propertyName <span class="token operator">=</span> indexOfFirstSpace <span class="token operator">></span> <span class="token number">0</span> <span class="token punctuation">?</span> trimmedProperty<span class="token punctuation">.</span><span class="token function">Remove</span><span class="token punctuation">(</span>indexOfFirstSpace<span class="token punctuation">)</span> <span class="token punctuation">:</span> trimmedProperty<span class="token punctuation">;</span>
propertyName <span class="token operator">=</span> propertyMapping<span class="token punctuation">.</span>MappingDictionary<span class="token punctuation">.</span>Keys<span class="token punctuation">.</span><span class="token function">FirstOrDefault</span><span class="token punctuation">(</span>
x <span class="token operator">=></span> <span class="token keyword">string</span><span class="token punctuation">.</span><span class="token function">Equals</span><span class="token punctuation">(</span>x<span class="token punctuation">,</span> propertyName<span class="token punctuation">,</span> StringComparison<span class="token punctuation">.</span>OrdinalIgnoreCase<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">//ignore case of sort property</span> <span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span>propertyMapping<span class="token punctuation">.</span>MappingDictionary<span class="token punctuation">.</span><span class="token function">TryGetValue</span><span class="token punctuation">(</span>
propertyName<span class="token punctuation">,</span> <span class="token keyword">out</span> List<span class="token operator"><</span>MappedProperty<span class="token operator">></span> mappedProperties<span class="token punctuation">)</span><span class="token punctuation">)</span>
<span class="token keyword">throw</span> <span class="token keyword">new</span> <span class="token class-name">InvalidCastException</span><span class="token punctuation">(</span>$<span class="token string">"key mapping for {propertyName} is missing"</span><span class="token punctuation">)</span><span class="token punctuation">;</span> mappedProperties<span class="token punctuation">.</span><span class="token function">Reverse</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">foreach</span><span class="token punctuation">(</span><span class="token class-name">MappedProperty</span> mappedProperty <span class="token keyword">in</span> mappedProperties<span class="token punctuation">)</span>
<span class="token punctuation">{</span>
<span class="token keyword">if</span> <span class="token punctuation">(</span>mappedProperty<span class="token punctuation">.</span>Revert<span class="token punctuation">)</span> desc <span class="token operator">=</span> <span class="token operator">!</span>desc<span class="token punctuation">;</span>
data <span class="token operator">=</span> data<span class="token punctuation">.</span><span class="token function">OrderBy</span><span class="token punctuation">(</span>$<span class="token string">"{mappedProperty.Name} {(desc ? "</span><span class="token keyword">descending</span><span class="token string">" : "</span><span class="token keyword">ascending</span><span class="token string">")} "</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span>
<span class="token keyword">return</span> data<span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span>
}
[HttpGet(Name = "GetAllApiUsers")]
public async Task<IActionResult> GetAllApiUsers(ApiUserParameters parameters)
{
if (!_propertyMappingContainer.ValidateMappingExistsFor<ApiUserResource, ApiUser>(parameters.OrderBy))
return BadRequest("can't find fields for sorting.");PaginatedList<span class="token operator"><</span>ApiUser<span class="token operator">></span> apiUsers <span class="token operator">=</span> <span class="token keyword">await</span> _apiUserRepository<span class="token punctuation">.</span><span class="token function">GetAllApiUsersAsync</span><span class="token punctuation">(</span>parameters<span class="token punctuation">)</span><span class="token punctuation">;</span> IEnumerable<span class="token operator"><</span>ApiUserResource<span class="token operator">></span> apiUserResources <span class="token operator">=</span>
_mapper<span class="token punctuation">.</span>Map<span class="token operator"><</span>IEnumerable<span class="token operator"><</span>ApiUser<span class="token operator">></span><span class="token punctuation">,</span> IEnumerable<span class="token operator"><</span>ApiUserResource<span class="token operator">>></span><span class="token punctuation">(</span>apiUsers<span class="token punctuation">)</span><span class="token punctuation">;</span> IEnumerable<span class="token operator"><</span>ApiUserResource<span class="token operator">></span> sortedApiUserResources <span class="token operator">=</span>
apiUserResources<span class="token punctuation">.</span><span class="token function">AsQueryable</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">ApplySort</span><span class="token punctuation">(</span>
parameters<span class="token punctuation">.</span>OrderBy<span class="token punctuation">,</span> _propertyMappingContainer<span class="token punctuation">.</span><span class="token generic-method"><span class="token function">Resolve</span><span class="token punctuation"><</span><span class="token class-name">ApiUserResource</span><span class="token punctuation">,</span> <span class="token class-name">ApiUser</span><span class="token punctuation">></span></span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">var</span> meta <span class="token operator">=</span> <span class="token keyword">new</span>
<span class="token punctuation">{</span>
apiUsers<span class="token punctuation">.</span>PageIndex<span class="token punctuation">,</span>
apiUsers<span class="token punctuation">.</span>PageSize<span class="token punctuation">,</span>
apiUsers<span class="token punctuation">.</span>PageCount<span class="token punctuation">,</span>
apiUsers<span class="token punctuation">.</span>TotalItemsCount<span class="token punctuation">,</span>
PreviousPageUrl <span class="token operator">=</span> apiUsers<span class="token punctuation">.</span>HasPreviousPage <span class="token punctuation">?</span> <span class="token function">CreateApiUserUrl</span><span class="token punctuation">(</span>parameters<span class="token punctuation">,</span> ResourceUriType<span class="token punctuation">.</span>PreviousPage<span class="token punctuation">)</span> <span class="token punctuation">:</span> <span class="token keyword">string</span><span class="token punctuation">.</span>Empty<span class="token punctuation">,</span>
NextPageUrl <span class="token operator">=</span> apiUsers<span class="token punctuation">.</span>HasNextPage <span class="token punctuation">?</span> <span class="token function">CreateApiUserUrl</span><span class="token punctuation">(</span>parameters<span class="token punctuation">,</span> ResourceUriType<span class="token punctuation">.</span>NextPage<span class="token punctuation">)</span> <span class="token punctuation">:</span> <span class="token keyword">string</span><span class="token punctuation">.</span>Empty<span class="token punctuation">,</span>
<span class="token punctuation">}</span><span class="token punctuation">;</span>
Response<span class="token punctuation">.</span>Headers<span class="token punctuation">.</span><span class="token function">Add</span><span class="token punctuation">(</span>
<span class="token string">"X-Pagination"</span><span class="token punctuation">,</span>
JsonConvert<span class="token punctuation">.</span><span class="token function">SerializeObject</span><span class="token punctuation">(</span>
meta<span class="token punctuation">,</span>
<span class="token keyword">new</span> <span class="token class-name">JsonSerializerSettings</span>
<span class="token punctuation">{</span> ContractResolver <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">CamelCasePropertyNamesContractResolver</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">return</span> <span class="token function">Ok</span><span class="token punctuation">(</span>sortedApiUserResources<span class="token punctuation">)</span><span class="token punctuation">;</span>
}
private string CreateApiUserUrl(ApiUserParameters parameters, ResourceUriType uriType)
{
var param = new {
parameters.PageIndex,
parameters.PageSize
};
switch (uriType)
{
case ResourceUriType.PreviousPage:
param = new
{
PageIndex = parameters.PageIndex - 1,
parameters.PageSize
};
break;
case ResourceUriType.NextPage:
param = new
{
PageIndex = parameters.PageIndex + 1,
parameters.PageSize
};
break;
case ResourceUriType.CurrentPage:
break;
default: break;
}
return Url.Link("GetAllApiUsers", param);
}
资源塑形(Resource shaping)
<p>返回 资源的指定字段</p>
<details>
<summary>ApiStudy.Infrastructure.Extensions.TypeExtensions</summary>
<pre data-role="codeBlock" data-info="CSharp" class="language-csharp"><span class="token keyword">namespace</span> ApiStudy<span class="token punctuation">.</span>Infrastructure<span class="token punctuation">.</span>Extensions
{
using System;
using System.Collections.Generic;
using System.Reflection;
<span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token keyword">class</span> <span class="token class-name">TypeExtensions</span>
<span class="token punctuation">{</span>
<span class="token keyword">public</span> <span class="token keyword">static</span> IEnumerable<span class="token operator"><</span>PropertyInfo<span class="token operator">></span> <span class="token function">GetProeprties</span><span class="token punctuation">(</span><span class="token keyword">this</span> <span class="token class-name">Type</span> source<span class="token punctuation">,</span> <span class="token keyword">string</span> fields <span class="token operator">=</span> <span class="token keyword">null</span><span class="token punctuation">)</span>
<span class="token punctuation">{</span>
List<span class="token operator"><</span>PropertyInfo<span class="token operator">></span> propertyInfoList <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token generic-method"><span class="token function">List</span><span class="token punctuation"><</span><span class="token class-name">PropertyInfo</span><span class="token punctuation">></span></span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token keyword">string</span><span class="token punctuation">.</span><span class="token function">IsNullOrEmpty</span><span class="token punctuation">(</span>fields<span class="token punctuation">)</span><span class="token punctuation">)</span>
<span class="token punctuation">{</span>
propertyInfoList<span class="token punctuation">.</span><span class="token function">AddRange</span><span class="token punctuation">(</span>source<span class="token punctuation">.</span><span class="token function">GetProperties</span><span class="token punctuation">(</span>BindingFlags<span class="token punctuation">.</span>Public <span class="token operator">|</span> BindingFlags<span class="token punctuation">.</span>Instance<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token keyword">else</span>
<span class="token punctuation">{</span>
<span class="token keyword">string</span><span class="token punctuation">[</span><span class="token punctuation">]</span> properties <span class="token operator">=</span> fields<span class="token punctuation">.</span><span class="token function">Trim</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">Split</span><span class="token punctuation">(</span><span class="token string">','</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">foreach</span> <span class="token punctuation">(</span><span class="token keyword">string</span> propertyName <span class="token keyword">in</span> properties<span class="token punctuation">)</span>
<span class="token punctuation">{</span>
propertyInfoList<span class="token punctuation">.</span><span class="token function">Add</span><span class="token punctuation">(</span>
source<span class="token punctuation">.</span><span class="token function">GetProperty</span><span class="token punctuation">(</span>
propertyName<span class="token punctuation">.</span><span class="token function">Trim</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
BindingFlags<span class="token punctuation">.</span>Public <span class="token operator">|</span> BindingFlags<span class="token punctuation">.</span>Instance <span class="token operator">|</span> BindingFlags<span class="token punctuation">.</span>IgnoreCase<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span>
<span class="token keyword">return</span> propertyInfoList<span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span>
}
namespace ApiStudy.Infrastructure.Extensions
{
using System.Collections.Generic;
using System.Dynamic;
using System.Linq;
using System.Reflection;<span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token keyword">class</span> <span class="token class-name">ObjectExtensions</span>
<span class="token punctuation">{</span>
<span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token class-name">ExpandoObject</span> <span class="token function">ToDynamicObject</span><span class="token punctuation">(</span><span class="token keyword">this</span> <span class="token keyword">object</span> source<span class="token punctuation">,</span> <span class="token keyword">in</span> <span class="token keyword">string</span> fields <span class="token operator">=</span> <span class="token keyword">null</span><span class="token punctuation">)</span>
<span class="token punctuation">{</span>
List<span class="token operator"><</span>PropertyInfo<span class="token operator">></span> propertyInfoList <span class="token operator">=</span> source<span class="token punctuation">.</span><span class="token function">GetType</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">GetProeprties</span><span class="token punctuation">(</span>fields<span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">ToList</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token class-name">ExpandoObject</span> expandoObject <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">ExpandoObject</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">foreach</span> <span class="token punctuation">(</span><span class="token class-name">PropertyInfo</span> propertyInfo <span class="token keyword">in</span> propertyInfoList<span class="token punctuation">)</span>
<span class="token punctuation">{</span>
<span class="token keyword">try</span>
<span class="token punctuation">{</span>
<span class="token punctuation">(</span>expandoObject <span class="token keyword">as</span> IDictionary<span class="token operator"><</span><span class="token keyword">string</span><span class="token punctuation">,</span> <span class="token keyword">object</span><span class="token operator">></span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">Add</span><span class="token punctuation">(</span>
propertyInfo<span class="token punctuation">.</span>Name<span class="token punctuation">,</span> propertyInfo<span class="token punctuation">.</span><span class="token function">GetValue</span><span class="token punctuation">(</span>source<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token keyword">catch</span> <span class="token punctuation">{</span> <span class="token keyword">continue</span><span class="token punctuation">;</span> <span class="token punctuation">}</span>
<span class="token punctuation">}</span>
<span class="token keyword">return</span> expandoObject<span class="token punctuation">;</span>
<span class="token punctuation">}</span> <span class="token keyword">internal</span> <span class="token keyword">static</span> <span class="token class-name">ExpandoObject</span> <span class="token function">ToDynamicObject</span><span class="token punctuation">(</span><span class="token keyword">this</span> <span class="token keyword">object</span> source<span class="token punctuation">,</span> <span class="token keyword">in</span> IEnumerable<span class="token operator"><</span>PropertyInfo<span class="token operator">></span> propertyInfos<span class="token punctuation">,</span> <span class="token keyword">in</span> <span class="token keyword">string</span> fields <span class="token operator">=</span> <span class="token keyword">null</span><span class="token punctuation">)</span>
<span class="token punctuation">{</span>
<span class="token class-name">ExpandoObject</span> expandoObject <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">ExpandoObject</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">foreach</span> <span class="token punctuation">(</span><span class="token class-name">PropertyInfo</span> propertyInfo <span class="token keyword">in</span> propertyInfos<span class="token punctuation">)</span>
<span class="token punctuation">{</span>
<span class="token keyword">try</span>
<span class="token punctuation">{</span>
<span class="token punctuation">(</span>expandoObject <span class="token keyword">as</span> IDictionary<span class="token operator"><</span><span class="token keyword">string</span><span class="token punctuation">,</span> <span class="token keyword">object</span><span class="token operator">></span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">Add</span><span class="token punctuation">(</span>
propertyInfo<span class="token punctuation">.</span>Name<span class="token punctuation">,</span> propertyInfo<span class="token punctuation">.</span><span class="token function">GetValue</span><span class="token punctuation">(</span>source<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token keyword">catch</span> <span class="token punctuation">{</span> <span class="token keyword">continue</span><span class="token punctuation">;</span> <span class="token punctuation">}</span>
<span class="token punctuation">}</span>
<span class="token keyword">return</span> expandoObject<span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span>
}
namespace ApiStudy.Infrastructure.Extensions
{
using System;
using System.Collections.Generic;
using System.Dynamic;
using System.Linq;
using System.Reflection;<span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token keyword">class</span> <span class="token class-name">IEnumerableExtensions</span>
<span class="token punctuation">{</span>
<span class="token keyword">public</span> <span class="token keyword">static</span> IEnumerable<span class="token operator"><</span>ExpandoObject<span class="token operator">></span> <span class="token generic-method"><span class="token function">ToDynamicObject</span><span class="token punctuation"><</span><span class="token class-name">T</span><span class="token punctuation">></span></span><span class="token punctuation">(</span>
<span class="token keyword">this</span> IEnumerable<span class="token operator"><</span>T<span class="token operator">></span> source<span class="token punctuation">,</span><span class="token keyword">in</span> <span class="token keyword">string</span> fields <span class="token operator">=</span> <span class="token keyword">null</span><span class="token punctuation">)</span>
<span class="token punctuation">{</span>
<span class="token keyword">if</span> <span class="token punctuation">(</span>source <span class="token operator">==</span> <span class="token keyword">null</span><span class="token punctuation">)</span> <span class="token keyword">throw</span> <span class="token keyword">new</span> <span class="token class-name">ArgumentNullException</span><span class="token punctuation">(</span><span class="token function">nameof</span><span class="token punctuation">(</span>source<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span> List<span class="token operator"><</span>ExpandoObject<span class="token operator">></span> expandoObejctList <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token generic-method"><span class="token function">List</span><span class="token punctuation"><</span><span class="token class-name">ExpandoObject</span><span class="token punctuation">></span></span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
List<span class="token operator"><</span>PropertyInfo<span class="token operator">></span> propertyInfoList <span class="token operator">=</span> <span class="token keyword">typeof</span><span class="token punctuation">(</span>T<span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">GetProeprties</span><span class="token punctuation">(</span>fields<span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">ToList</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">foreach</span><span class="token punctuation">(</span><span class="token class-name">T</span> x <span class="token keyword">in</span> source<span class="token punctuation">)</span>
<span class="token punctuation">{</span>
expandoObejctList<span class="token punctuation">.</span><span class="token function">Add</span><span class="token punctuation">(</span>x<span class="token punctuation">.</span><span class="token function">ToDynamicObject</span><span class="token punctuation">(</span>propertyInfoList<span class="token punctuation">,</span> fields<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token keyword">return</span> expandoObejctList<span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span>
}
namespace ApiStudy.Infrastructure.Services
{
using System.Reflection;<span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">TypeHelperServices</span> <span class="token punctuation">:</span> <span class="token class-name">ITypeHelperServices</span>
<span class="token punctuation">{</span>
<span class="token keyword">public</span> <span class="token keyword">bool</span> <span class="token generic-method"><span class="token function">HasProperties</span><span class="token punctuation"><</span><span class="token class-name">T</span><span class="token punctuation">></span></span><span class="token punctuation">(</span><span class="token keyword">string</span> fields<span class="token punctuation">)</span>
<span class="token punctuation">{</span>
<span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token keyword">string</span><span class="token punctuation">.</span><span class="token function">IsNullOrEmpty</span><span class="token punctuation">(</span>fields<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token keyword">return</span> <span class="token keyword">true</span><span class="token punctuation">;</span> <span class="token keyword">string</span><span class="token punctuation">[</span><span class="token punctuation">]</span> splitFields <span class="token operator">=</span> fields<span class="token punctuation">.</span><span class="token function">Split</span><span class="token punctuation">(</span><span class="token string">','</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">foreach</span><span class="token punctuation">(</span><span class="token keyword">string</span> splitField <span class="token keyword">in</span> splitFields<span class="token punctuation">)</span>
<span class="token punctuation">{</span>
<span class="token keyword">string</span> proeprtyName <span class="token operator">=</span> splitField<span class="token punctuation">.</span><span class="token function">Trim</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token class-name">PropertyInfo</span> propertyInfo <span class="token operator">=</span> <span class="token keyword">typeof</span><span class="token punctuation">(</span>T<span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">GetProperty</span><span class="token punctuation">(</span>
proeprtyName<span class="token punctuation">,</span> BindingFlags<span class="token punctuation">.</span>Public <span class="token operator">|</span> BindingFlags<span class="token punctuation">.</span>Instance <span class="token operator">|</span> BindingFlags<span class="token punctuation">.</span>IgnoreCase<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">if</span> <span class="token punctuation">(</span>propertyInfo <span class="token operator">==</span> <span class="token keyword">null</span><span class="token punctuation">)</span> <span class="token keyword">return</span> <span class="token keyword">false</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token keyword">return</span> <span class="token keyword">true</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span>
}
[HttpGet(Name = "GetAllApiUsers")]
public async Task<IActionResult> GetAllApiUsers(ApiUserParameters parameters)
{
//added code
if (!_typeHelper.HasProperties<ApiUserResource>(parameters.Fields))
return BadRequest("fields not exist.");<span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span>_propertyMappingContainer<span class="token punctuation">.</span><span class="token generic-method"><span class="token function">ValidateMappingExistsFor</span><span class="token punctuation"><</span><span class="token class-name">ApiUserResource</span><span class="token punctuation">,</span> <span class="token class-name">ApiUser</span><span class="token punctuation">></span></span><span class="token punctuation">(</span>parameters<span class="token punctuation">.</span>OrderBy<span class="token punctuation">)</span><span class="token punctuation">)</span>
<span class="token keyword">return</span> <span class="token function">BadRequest</span><span class="token punctuation">(</span><span class="token string">"can't find fields for sorting."</span><span class="token punctuation">)</span><span class="token punctuation">;</span> PaginatedList<span class="token operator"><</span>ApiUser<span class="token operator">></span> apiUsers <span class="token operator">=</span> <span class="token keyword">await</span> _apiUserRepository<span class="token punctuation">.</span><span class="token function">GetAllApiUsersAsync</span><span class="token punctuation">(</span>parameters<span class="token punctuation">)</span><span class="token punctuation">;</span> IEnumerable<span class="token operator"><</span>ApiUserResource<span class="token operator">></span> apiUserResources <span class="token operator">=</span>
_mapper<span class="token punctuation">.</span>Map<span class="token operator"><</span>IEnumerable<span class="token operator"><</span>ApiUser<span class="token operator">></span><span class="token punctuation">,</span> IEnumerable<span class="token operator"><</span>ApiUserResource<span class="token operator">>></span><span class="token punctuation">(</span>apiUsers<span class="token punctuation">)</span><span class="token punctuation">;</span> IEnumerable<span class="token operator"><</span>ApiUserResource<span class="token operator">></span> sortedApiUserResources <span class="token operator">=</span>
apiUserResources<span class="token punctuation">.</span><span class="token function">AsQueryable</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">ApplySort</span><span class="token punctuation">(</span>
parameters<span class="token punctuation">.</span>OrderBy<span class="token punctuation">,</span> _propertyMappingContainer<span class="token punctuation">.</span><span class="token generic-method"><span class="token function">Resolve</span><span class="token punctuation"><</span><span class="token class-name">ApiUserResource</span><span class="token punctuation">,</span> <span class="token class-name">ApiUser</span><span class="token punctuation">></span></span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">//modified code</span>
IEnumerable<span class="token operator"><</span>ExpandoObject<span class="token operator">></span> sharpedApiUserResources <span class="token operator">=</span>
sortedApiUserResources<span class="token punctuation">.</span><span class="token function">ToDynamicObject</span><span class="token punctuation">(</span>parameters<span class="token punctuation">.</span>Fields<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">var</span> meta <span class="token operator">=</span> <span class="token keyword">new</span>
<span class="token punctuation">{</span>
apiUsers<span class="token punctuation">.</span>PageIndex<span class="token punctuation">,</span>
apiUsers<span class="token punctuation">.</span>PageSize<span class="token punctuation">,</span>
apiUsers<span class="token punctuation">.</span>PageCount<span class="token punctuation">,</span>
apiUsers<span class="token punctuation">.</span>TotalItemsCount<span class="token punctuation">,</span>
PreviousPageUrl <span class="token operator">=</span> apiUsers<span class="token punctuation">.</span>HasPreviousPage <span class="token punctuation">?</span> <span class="token function">CreateApiUserUrl</span><span class="token punctuation">(</span>parameters<span class="token punctuation">,</span> ResourceUriType<span class="token punctuation">.</span>PreviousPage<span class="token punctuation">)</span> <span class="token punctuation">:</span> <span class="token keyword">string</span><span class="token punctuation">.</span>Empty<span class="token punctuation">,</span>
NextPageUrl <span class="token operator">=</span> apiUsers<span class="token punctuation">.</span>HasNextPage <span class="token punctuation">?</span> <span class="token function">CreateApiUserUrl</span><span class="token punctuation">(</span>parameters<span class="token punctuation">,</span> ResourceUriType<span class="token punctuation">.</span>NextPage<span class="token punctuation">)</span> <span class="token punctuation">:</span> <span class="token keyword">string</span><span class="token punctuation">.</span>Empty<span class="token punctuation">,</span>
<span class="token punctuation">}</span><span class="token punctuation">;</span>
Response<span class="token punctuation">.</span>Headers<span class="token punctuation">.</span><span class="token function">Add</span><span class="token punctuation">(</span>
<span class="token string">"X-Pagination"</span><span class="token punctuation">,</span>
JsonConvert<span class="token punctuation">.</span><span class="token function">SerializeObject</span><span class="token punctuation">(</span>
meta<span class="token punctuation">,</span>
<span class="token keyword">new</span> <span class="token class-name">JsonSerializerSettings</span>
<span class="token punctuation">{</span> ContractResolver <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">CamelCasePropertyNamesContractResolver</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token comment">//modified code</span>
<span class="token keyword">return</span> <span class="token function">Ok</span><span class="token punctuation">(</span>sharpedApiUserResources<span class="token punctuation">)</span><span class="token punctuation">;</span>
}
配置返回的json名称风格为CamelCase
StartupDevelopment.ConfigureServices
services.AddMvc(options =>
{
options.ReturnHttpNotAcceptable = true;
options.OutputFormatters.Add(new XmlDataContractSerializerOutputFormatter());
})
.AddJsonOptions(options =>
{
//added code
options.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver();
});
HATEOAS
<p>REST里最复杂的约束,构建成熟RESTAPI的核心
</p>
<ul>
<li>可进化性,自我描述</li>
<li>超媒体(Hypermedia,例如超链接)驱动如何消<br>
费和使用API</li>
</ul>
<details>
<summary>UserContext</summary>
<pre data-role="codeBlock" data-info="CSharp" class="language-csharp"><span class="token keyword">private</span> IEnumerable<span class="token operator"><</span>LinkResource<span class="token operator">></span> <span class="token function">CreateLinksForApiUser</span><span class="token punctuation">(</span><span class="token keyword">string</span> guid<span class="token punctuation">,</span><span class="token keyword">string</span> fields <span class="token operator">=</span> <span class="token keyword">null</span><span class="token punctuation">)</span>
{
List<LinkResource> linkResources = new List<LinkResource>();
if (string.IsNullOrEmpty(fields))
{
linkResources.Add(
new LinkResource(Url.Link("GetApiUser", new { guid }), "self", "get"));
}
else
{
linkResources.Add(
new LinkResource(Url.Link("GetApiUser", new { guid, fields }), "self", "get"));
}
linkResources<span class="token punctuation">.</span><span class="token function">Add</span><span class="token punctuation">(</span>
<span class="token keyword">new</span> <span class="token class-name">LinkResource</span><span class="token punctuation">(</span>Url<span class="token punctuation">.</span><span class="token function">Link</span><span class="token punctuation">(</span><span class="token string">"DeleteApiUser"</span><span class="token punctuation">,</span> <span class="token keyword">new</span> <span class="token punctuation">{</span> guid <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token string">"self"</span><span class="token punctuation">,</span> <span class="token string">"Get"</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">return</span> linkResources<span class="token punctuation">;</span>
}
private IEnumerable<LinkResource> CreateLinksForApiUsers(ApiUserParameters parameters,bool hasPrevious,bool hasNext)
{
List<LinkResource> resources = new List<LinkResource>();
resources<span class="token punctuation">.</span><span class="token function">Add</span><span class="token punctuation">(</span>
<span class="token keyword">new</span> <span class="token class-name">LinkResource</span><span class="token punctuation">(</span>
<span class="token function">CreateApiUserUrl</span><span class="token punctuation">(</span>parameters<span class="token punctuation">,</span>ResourceUriType<span class="token punctuation">.</span>CurrentPage<span class="token punctuation">)</span><span class="token punctuation">,</span>
<span class="token string">"current_page"</span><span class="token punctuation">,</span> <span class="token string">"get"</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">if</span> <span class="token punctuation">(</span>hasPrevious<span class="token punctuation">)</span>
resources<span class="token punctuation">.</span><span class="token function">Add</span><span class="token punctuation">(</span>
<span class="token keyword">new</span> <span class="token class-name">LinkResource</span><span class="token punctuation">(</span>
<span class="token function">CreateApiUserUrl</span><span class="token punctuation">(</span>parameters<span class="token punctuation">,</span> ResourceUriType<span class="token punctuation">.</span>PreviousPage<span class="token punctuation">)</span><span class="token punctuation">,</span>
<span class="token string">"previous_page"</span><span class="token punctuation">,</span> <span class="token string">"get"</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">if</span> <span class="token punctuation">(</span>hasNext<span class="token punctuation">)</span>
resources<span class="token punctuation">.</span><span class="token function">Add</span><span class="token punctuation">(</span>
<span class="token keyword">new</span> <span class="token class-name">LinkResource</span><span class="token punctuation">(</span>
<span class="token function">CreateApiUserUrl</span><span class="token punctuation">(</span>parameters<span class="token punctuation">,</span> ResourceUriType<span class="token punctuation">.</span>NextPage<span class="token punctuation">)</span><span class="token punctuation">,</span>
<span class="token string">"next_page"</span><span class="token punctuation">,</span> <span class="token string">"get"</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">return</span> resources<span class="token punctuation">;</span>
}
[HttpGet(Name = "GetAllApiUsers")]
public async Task<IActionResult> GetAllApiUsers(ApiUserParameters parameters)
{
if (!_typeHelper.HasProperties<ApiUserResource>(parameters.Fields))
return BadRequest("fields not exist.");
<span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span>_propertyMappingContainer<span class="token punctuation">.</span><span class="token generic-method"><span class="token function">ValidateMappingExistsFor</span><span class="token punctuation"><</span><span class="token class-name">ApiUserResource</span><span class="token punctuation">,</span> <span class="token class-name">ApiUser</span><span class="token punctuation">></span></span><span class="token punctuation">(</span>parameters<span class="token punctuation">.</span>OrderBy<span class="token punctuation">)</span><span class="token punctuation">)</span>
<span class="token keyword">return</span> <span class="token function">BadRequest</span><span class="token punctuation">(</span><span class="token string">"can't find fields for sorting."</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
PaginatedList<span class="token operator"><</span>ApiUser<span class="token operator">></span> apiUsers <span class="token operator">=</span> <span class="token keyword">await</span> _apiUserRepository<span class="token punctuation">.</span><span class="token function">GetAllApiUsersAsync</span><span class="token punctuation">(</span>parameters<span class="token punctuation">)</span><span class="token punctuation">;</span>
IEnumerable<span class="token operator"><</span>ApiUserResource<span class="token operator">></span> apiUserResources <span class="token operator">=</span>
_mapper<span class="token punctuation">.</span>Map<span class="token operator"><</span>IEnumerable<span class="token operator"><</span>ApiUser<span class="token operator">></span><span class="token punctuation">,</span> IEnumerable<span class="token operator"><</span>ApiUserResource<span class="token operator">>></span><span class="token punctuation">(</span>apiUsers<span class="token punctuation">)</span><span class="token punctuation">;</span>
IEnumerable<span class="token operator"><</span>ApiUserResource<span class="token operator">></span> sortedApiUserResources <span class="token operator">=</span>
apiUserResources<span class="token punctuation">.</span><span class="token function">AsQueryable</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">ApplySort</span><span class="token punctuation">(</span>
parameters<span class="token punctuation">.</span>OrderBy<span class="token punctuation">,</span> _propertyMappingContainer<span class="token punctuation">.</span><span class="token generic-method"><span class="token function">Resolve</span><span class="token punctuation"><</span><span class="token class-name">ApiUserResource</span><span class="token punctuation">,</span> <span class="token class-name">ApiUser</span><span class="token punctuation">></span></span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
IEnumerable<span class="token operator"><</span>ExpandoObject<span class="token operator">></span> shapedApiUserResources <span class="token operator">=</span>
sortedApiUserResources<span class="token punctuation">.</span><span class="token function">ToDynamicObject</span><span class="token punctuation">(</span>parameters<span class="token punctuation">.</span>Fields<span class="token punctuation">)</span><span class="token punctuation">;</span>
IEnumerable<span class="token operator"><</span>ExpandoObject<span class="token operator">></span> shapedApiUserResourcesWithLinks <span class="token operator">=</span> shapedApiUserResources<span class="token punctuation">.</span><span class="token function">Select</span><span class="token punctuation">(</span>
x <span class="token operator">=></span>
<span class="token punctuation">{</span>
IDictionary<span class="token operator"><</span><span class="token keyword">string</span><span class="token punctuation">,</span> <span class="token keyword">object</span><span class="token operator">></span> dict <span class="token operator">=</span> x <span class="token keyword">as</span> IDictionary<span class="token operator"><</span><span class="token keyword">string</span><span class="token punctuation">,</span> <span class="token keyword">object</span><span class="token operator">></span><span class="token punctuation">;</span>
<span class="token keyword">if</span><span class="token punctuation">(</span>dict<span class="token punctuation">.</span>Keys<span class="token punctuation">.</span><span class="token function">Contains</span><span class="token punctuation">(</span><span class="token string">"guid"</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
dict<span class="token punctuation">.</span><span class="token function">Add</span><span class="token punctuation">(</span><span class="token string">"links"</span><span class="token punctuation">,</span> <span class="token function">CreateLinksForApiUser</span><span class="token punctuation">(</span>dict<span class="token punctuation">[</span><span class="token string">"guid"</span><span class="token punctuation">]</span> <span class="token keyword">as</span> <span class="token keyword">string</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">return</span> dict <span class="token keyword">as</span> ExpandoObject<span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">var</span> result <span class="token operator">=</span> <span class="token keyword">new</span>
<span class="token punctuation">{</span>
<span class="token keyword">value</span> <span class="token operator">=</span> shapedApiUserResourcesWithLinks<span class="token punctuation">,</span>
links <span class="token operator">=</span> <span class="token function">CreateLinksForApiUsers</span><span class="token punctuation">(</span>parameters<span class="token punctuation">,</span> apiUsers<span class="token punctuation">.</span>HasPreviousPage<span class="token punctuation">,</span> apiUsers<span class="token punctuation">.</span>HasNextPage<span class="token punctuation">)</span>
<span class="token punctuation">}</span><span class="token punctuation">;</span>
<span class="token keyword">var</span> meta <span class="token operator">=</span> <span class="token keyword">new</span>
<span class="token punctuation">{</span>
apiUsers<span class="token punctuation">.</span>PageIndex<span class="token punctuation">,</span>
apiUsers<span class="token punctuation">.</span>PageSize<span class="token punctuation">,</span>
apiUsers<span class="token punctuation">.</span>PageCount<span class="token punctuation">,</span>
apiUsers<span class="token punctuation">.</span>TotalItemsCount<span class="token punctuation">,</span>
<span class="token comment">//PreviousPageUrl = apiUsers.HasPreviousPage ? CreateApiUserUrl(parameters, ResourceUriType.PreviousPage) : string.Empty,</span>
<span class="token comment">//NextPageUrl = apiUsers.HasNextPage ? CreateApiUserUrl(parameters, ResourceUriType.NextPage) : string.Empty,</span>
<span class="token punctuation">}</span><span class="token punctuation">;</span>
Response<span class="token punctuation">.</span>Headers<span class="token punctuation">.</span><span class="token function">Add</span><span class="token punctuation">(</span>
<span class="token string">"X-Pagination"</span><span class="token punctuation">,</span>
JsonConvert<span class="token punctuation">.</span><span class="token function">SerializeObject</span><span class="token punctuation">(</span>
meta<span class="token punctuation">,</span>
<span class="token keyword">new</span> <span class="token class-name">JsonSerializerSettings</span>
<span class="token punctuation">{</span> ContractResolver <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">CamelCasePropertyNamesContractResolver</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">return</span> <span class="token function">Ok</span><span class="token punctuation">(</span>result<span class="token punctuation">)</span><span class="token punctuation">;</span>
}
创建供应商特定媒体类型
<ul>
<li>application/vnd.mycompany.hateoas+json
<ul>
<li>vnd是vendor的缩写,这一条是mime
type的原则,表示这个媒体类型是供应商特定的
</li>
<li>自定义的标识,也可能还包括额外的值,这里我是用的是公司名,随后是hateoas表示返回的响应里面要<br>
包含链接</li>
<li>“+json”</li>
</ul>
</li>
<li>在Startup里注册.</li>
</ul>
<h4 class="mume-header" id="%E5%88%A4%E6%96%ADmedia-type%E7%B1%BB%E5%9E%8B">判断Media
Type类型</h4>
<ul>
<li>[FromHeader(Name = "Accept")] stringmediaType</li>
</ul>
<pre data-role="codeBlock" data-info="CSharp" class="language-csharp"><span class="token comment">//Startup.ConfigureServices 中注册媒体类型</span>
services.AddMvc(options =>
{
options.ReturnHttpNotAcceptable = true;
//options.OutputFormatters.Add(new XmlDataContractSerializerOutputFormatter());
JsonOutputFormatter formatter = options.OutputFormatters.OfType<JsonOutputFormatter>().FirstOrDefault();
formatter.SupportedMediaTypes.Add("application/vnd.laggage.hateoas+json");
})
// get方法中判断媒体类型
if (mediaType "application/json")
return Ok(shapedApiUserResources);
else if (mediaType "application/vnd.laggage.hateoas+json")
{
...
return;
}
注意,要是的 Action 认识 application/vnd.laggage.hateoss+json
,需要在Startup.ConfigureServices中注册这个媒体类型,上面的代码给出了具体操作.
UserContext
[HttpGet(Name = "GetAllApiUsers")]
public async Task<IActionResult> GetAllApiUsers(ApiUserParameters parameters,[FromHeader(Name = "Accept")] string mediaType)
{
if (!_typeHelper.HasProperties<ApiUserResource>(parameters.Fields))
return BadRequest("fields not exist.");<span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span>_propertyMappingContainer<span class="token punctuation">.</span><span class="token generic-method"><span class="token function">ValidateMappingExistsFor</span><span class="token punctuation"><</span><span class="token class-name">ApiUserResource</span><span class="token punctuation">,</span> <span class="token class-name">ApiUser</span><span class="token punctuation">></span></span><span class="token punctuation">(</span>parameters<span class="token punctuation">.</span>OrderBy<span class="token punctuation">)</span><span class="token punctuation">)</span>
<span class="token keyword">return</span> <span class="token function">BadRequest</span><span class="token punctuation">(</span><span class="token string">"can't find fields for sorting."</span><span class="token punctuation">)</span><span class="token punctuation">;</span> PaginatedList<span class="token operator"><</span>ApiUser<span class="token operator">></span> apiUsers <span class="token operator">=</span> <span class="token keyword">await</span> _apiUserRepository<span class="token punctuation">.</span><span class="token function">GetAllApiUsersAsync</span><span class="token punctuation">(</span>parameters<span class="token punctuation">)</span><span class="token punctuation">;</span> IEnumerable<span class="token operator"><</span>ApiUserResource<span class="token operator">></span> apiUserResources <span class="token operator">=</span>
_mapper<span class="token punctuation">.</span>Map<span class="token operator"><</span>IEnumerable<span class="token operator"><</span>ApiUser<span class="token operator">></span><span class="token punctuation">,</span> IEnumerable<span class="token operator"><</span>ApiUserResource<span class="token operator">>></span><span class="token punctuation">(</span>apiUsers<span class="token punctuation">)</span><span class="token punctuation">;</span> IEnumerable<span class="token operator"><</span>ApiUserResource<span class="token operator">></span> sortedApiUserResources <span class="token operator">=</span>
apiUserResources<span class="token punctuation">.</span><span class="token function">AsQueryable</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">ApplySort</span><span class="token punctuation">(</span>
parameters<span class="token punctuation">.</span>OrderBy<span class="token punctuation">,</span> _propertyMappingContainer<span class="token punctuation">.</span><span class="token generic-method"><span class="token function">Resolve</span><span class="token punctuation"><</span><span class="token class-name">ApiUserResource</span><span class="token punctuation">,</span> <span class="token class-name">ApiUser</span><span class="token punctuation">></span></span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span> IEnumerable<span class="token operator"><</span>ExpandoObject<span class="token operator">></span> shapedApiUserResources <span class="token operator">=</span>
sortedApiUserResources<span class="token punctuation">.</span><span class="token function">ToDynamicObject</span><span class="token punctuation">(</span>parameters<span class="token punctuation">.</span>Fields<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">if</span> <span class="token punctuation">(</span>mediaType <span class="token operator">==</span> <span class="token string">"application/json"</span><span class="token punctuation">)</span> <span class="token keyword">return</span> <span class="token function">Ok</span><span class="token punctuation">(</span>shapedApiUserResources<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">else</span> <span class="token keyword">if</span> <span class="token punctuation">(</span>mediaType <span class="token operator">==</span> <span class="token string">"application/vnd.laggage.hateoas+json"</span><span class="token punctuation">)</span>
<span class="token punctuation">{</span>
IEnumerable<span class="token operator"><</span>ExpandoObject<span class="token operator">></span> shapedApiUserResourcesWithLinks <span class="token operator">=</span> shapedApiUserResources<span class="token punctuation">.</span><span class="token function">Select</span><span class="token punctuation">(</span>
x <span class="token operator">=></span>
<span class="token punctuation">{</span>
IDictionary<span class="token operator"><</span><span class="token keyword">string</span><span class="token punctuation">,</span> <span class="token keyword">object</span><span class="token operator">></span> dict <span class="token operator">=</span> x <span class="token keyword">as</span> IDictionary<span class="token operator"><</span><span class="token keyword">string</span><span class="token punctuation">,</span> <span class="token keyword">object</span><span class="token operator">></span><span class="token punctuation">;</span>
<span class="token keyword">if</span> <span class="token punctuation">(</span>dict<span class="token punctuation">.</span>Keys<span class="token punctuation">.</span><span class="token function">Contains</span><span class="token punctuation">(</span><span class="token string">"guid"</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
dict<span class="token punctuation">.</span><span class="token function">Add</span><span class="token punctuation">(</span><span class="token string">"links"</span><span class="token punctuation">,</span> <span class="token function">CreateLinksForApiUser</span><span class="token punctuation">(</span>
dict<span class="token punctuation">.</span><span class="token function">FirstOrDefault</span><span class="token punctuation">(</span>
a <span class="token operator">=></span> <span class="token keyword">string</span><span class="token punctuation">.</span><span class="token function">Equals</span><span class="token punctuation">(</span>
a<span class="token punctuation">.</span>Key<span class="token punctuation">,</span><span class="token string">"guid"</span><span class="token punctuation">,</span>StringComparison<span class="token punctuation">.</span>OrdinalIgnoreCase<span class="token punctuation">)</span><span class="token punctuation">)</span>
<span class="token punctuation">.</span>Value<span class="token punctuation">.</span><span class="token function">ToString</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">return</span> dict <span class="token keyword">as</span> ExpandoObject<span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">var</span> result <span class="token operator">=</span> <span class="token keyword">new</span>
<span class="token punctuation">{</span>
<span class="token keyword">value</span> <span class="token operator">=</span> shapedApiUserResourcesWithLinks<span class="token punctuation">,</span>
links <span class="token operator">=</span> <span class="token function">CreateLinksForApiUsers</span><span class="token punctuation">(</span>parameters<span class="token punctuation">,</span> apiUsers<span class="token punctuation">.</span>HasPreviousPage<span class="token punctuation">,</span> apiUsers<span class="token punctuation">.</span>HasNextPage<span class="token punctuation">)</span>
<span class="token punctuation">}</span><span class="token punctuation">;</span> <span class="token keyword">var</span> meta <span class="token operator">=</span> <span class="token keyword">new</span>
<span class="token punctuation">{</span>
apiUsers<span class="token punctuation">.</span>PageIndex<span class="token punctuation">,</span>
apiUsers<span class="token punctuation">.</span>PageSize<span class="token punctuation">,</span>
apiUsers<span class="token punctuation">.</span>PageCount<span class="token punctuation">,</span>
apiUsers<span class="token punctuation">.</span>TotalItemsCount<span class="token punctuation">,</span>
<span class="token punctuation">}</span><span class="token punctuation">;</span>
Response<span class="token punctuation">.</span>Headers<span class="token punctuation">.</span><span class="token function">Add</span><span class="token punctuation">(</span>
<span class="token string">"X-Pagination"</span><span class="token punctuation">,</span>
JsonConvert<span class="token punctuation">.</span><span class="token function">SerializeObject</span><span class="token punctuation">(</span>
meta<span class="token punctuation">,</span>
<span class="token keyword">new</span> <span class="token class-name">JsonSerializerSettings</span>
<span class="token punctuation">{</span> ContractResolver <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">CamelCasePropertyNamesContractResolver</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">return</span> <span class="token function">Ok</span><span class="token punctuation">(</span>result<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token keyword">return</span> <span class="token function">NotFound</span><span class="token punctuation">(</span>$<span class="token string">"Can't find resources for the given media type: [{mediaType}]."</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
}
[HttpGet("{guid}",Name = "GetApiUser")]
public async Task<IActionResult> Get(string guid, [FromHeader(Name = "Accept")] string mediaType , string fields = null)
{
if (!_typeHelper.HasProperties<ApiUserResource>(fields))
return BadRequest("fields not exist.");<span class="token class-name">ApiUser</span> apiUser <span class="token operator">=</span> <span class="token keyword">await</span> _apiUserRepository<span class="token punctuation">.</span><span class="token function">GetApiUserByGuidAsync</span><span class="token punctuation">(</span>Guid<span class="token punctuation">.</span><span class="token function">Parse</span><span class="token punctuation">(</span>guid<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">if</span> <span class="token punctuation">(</span>apiUser <span class="token keyword">is</span> <span class="token keyword">null</span><span class="token punctuation">)</span> <span class="token keyword">return</span> <span class="token function">NotFound</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token class-name">ApiUserResource</span> apiUserResource <span class="token operator">=</span> _mapper<span class="token punctuation">.</span><span class="token generic-method"><span class="token function">Map</span><span class="token punctuation"><</span><span class="token class-name">ApiUser</span><span class="token punctuation">,</span> <span class="token class-name">ApiUserResource</span><span class="token punctuation">></span></span><span class="token punctuation">(</span>apiUser<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token class-name">ExpandoObject</span> shapedApiUserResource <span class="token operator">=</span> apiUserResource<span class="token punctuation">.</span><span class="token function">ToDynamicObject</span><span class="token punctuation">(</span>fields<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">if</span> <span class="token punctuation">(</span>mediaType <span class="token operator">==</span> <span class="token string">"application/json"</span><span class="token punctuation">)</span> <span class="token keyword">return</span> <span class="token function">Ok</span><span class="token punctuation">(</span>shapedApiUserResource<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">else</span> <span class="token keyword">if</span><span class="token punctuation">(</span>mediaType <span class="token operator">==</span> <span class="token string">"application/vnd.laggage.hateoas+json"</span><span class="token punctuation">)</span>
<span class="token punctuation">{</span> IDictionary<span class="token operator"><</span><span class="token keyword">string</span><span class="token punctuation">,</span> <span class="token keyword">object</span><span class="token operator">></span> shapedApiUserResourceWithLink <span class="token operator">=</span> shapedApiUserResource <span class="token keyword">as</span> IDictionary<span class="token operator"><</span><span class="token keyword">string</span><span class="token punctuation">,</span> <span class="token keyword">object</span><span class="token operator">></span><span class="token punctuation">;</span>
shapedApiUserResourceWithLink<span class="token punctuation">.</span><span class="token function">Add</span><span class="token punctuation">(</span><span class="token string">"links"</span><span class="token punctuation">,</span> <span class="token function">CreateLinksForApiUser</span><span class="token punctuation">(</span>guid<span class="token punctuation">,</span> fields<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">return</span> <span class="token function">Ok</span><span class="token punctuation">(</span>shapedApiUserResourceWithLink<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token keyword">return</span> <span class="token function">NotFound</span><span class="token punctuation">(</span><span class="token string">@"Can't find resource for the given media type: [{mediaType}]."</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
}
- 自定义Action约束.
RequestHeaderMatchingMediaTypeAttribute
[AttributeUsage(AttributeTargets.All, Inherited = true, AllowMultiple = true)]
public class RequestHeaderMatchingMediaTypeAttribute : Attribute, IActionConstraint
{
private readonly string _requestHeaderToMatch;
private readonly string[] _mediaTypes;<span class="token keyword">public</span> <span class="token function">RequestHeaderMatchingMediaTypeAttribute</span><span class="token punctuation">(</span><span class="token keyword">string</span> requestHeaderToMatch<span class="token punctuation">,</span> <span class="token keyword">string</span><span class="token punctuation">[</span><span class="token punctuation">]</span> mediaTypes<span class="token punctuation">)</span>
<span class="token punctuation">{</span>
_requestHeaderToMatch <span class="token operator">=</span> requestHeaderToMatch<span class="token punctuation">;</span>
_mediaTypes <span class="token operator">=</span> mediaTypes<span class="token punctuation">;</span>
<span class="token punctuation">}</span> <span class="token keyword">public</span> <span class="token keyword">bool</span> <span class="token function">Accept</span><span class="token punctuation">(</span><span class="token class-name">ActionConstraintContext</span> context<span class="token punctuation">)</span>
<span class="token punctuation">{</span>
<span class="token keyword">var</span> requestHeaders <span class="token operator">=</span> context<span class="token punctuation">.</span>RouteContext<span class="token punctuation">.</span>HttpContext<span class="token punctuation">.</span>Request<span class="token punctuation">.</span>Headers<span class="token punctuation">;</span>
<span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span>requestHeaders<span class="token punctuation">.</span><span class="token function">ContainsKey</span><span class="token punctuation">(</span>_requestHeaderToMatch<span class="token punctuation">)</span><span class="token punctuation">)</span>
<span class="token punctuation">{</span>
<span class="token keyword">return</span> <span class="token keyword">false</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span> <span class="token keyword">foreach</span> <span class="token punctuation">(</span><span class="token keyword">var</span> mediaType <span class="token keyword">in</span> _mediaTypes<span class="token punctuation">)</span>
<span class="token punctuation">{</span>
<span class="token keyword">var</span> mediaTypeMatches <span class="token operator">=</span> <span class="token keyword">string</span><span class="token punctuation">.</span><span class="token function">Equals</span><span class="token punctuation">(</span>requestHeaders<span class="token punctuation">[</span>_requestHeaderToMatch<span class="token punctuation">]</span><span class="token punctuation">.</span><span class="token function">ToString</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span>
mediaType<span class="token punctuation">,</span> StringComparison<span class="token punctuation">.</span>OrdinalIgnoreCase<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">if</span> <span class="token punctuation">(</span>mediaTypeMatches<span class="token punctuation">)</span>
<span class="token punctuation">{</span>
<span class="token keyword">return</span> <span class="token keyword">true</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span> <span class="token keyword">return</span> <span class="token keyword">false</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span> <span class="token keyword">public</span> <span class="token keyword">int</span> Order <span class="token punctuation">{</span> <span class="token keyword">get</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span>
}
UserContext
[HttpGet(Name = "GetAllApiUsers")]
[RequestHeaderMatchingMediaType("Accept",new string[] { "application/vnd.laggage.hateoas+json" })]
public async Task<IActionResult> GetHateoas(ApiUserParameters parameters)
{
if (!_typeHelper.HasProperties<ApiUserResource>(parameters.Fields))
return BadRequest("fields not exist.");<span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span>_propertyMappingContainer<span class="token punctuation">.</span><span class="token generic-method"><span class="token function">ValidateMappingExistsFor</span><span class="token punctuation"><</span><span class="token class-name">ApiUserResource</span><span class="token punctuation">,</span> <span class="token class-name">ApiUser</span><span class="token punctuation">></span></span><span class="token punctuation">(</span>parameters<span class="token punctuation">.</span>OrderBy<span class="token punctuation">)</span><span class="token punctuation">)</span>
<span class="token keyword">return</span> <span class="token function">BadRequest</span><span class="token punctuation">(</span><span class="token string">"can't find fields for sorting."</span><span class="token punctuation">)</span><span class="token punctuation">;</span> PaginatedList<span class="token operator"><</span>ApiUser<span class="token operator">></span> apiUsers <span class="token operator">=</span> <span class="token keyword">await</span> _apiUserRepository<span class="token punctuation">.</span><span class="token function">GetAllApiUsersAsync</span><span class="token punctuation">(</span>parameters<span class="token punctuation">)</span><span class="token punctuation">;</span> IEnumerable<span class="token operator"><</span>ApiUserResource<span class="token operator">></span> apiUserResources <span class="token operator">=</span>
_mapper<span class="token punctuation">.</span>Map<span class="token operator"><</span>IEnumerable<span class="token operator"><</span>ApiUser<span class="token operator">></span><span class="token punctuation">,</span> IEnumerable<span class="token operator"><</span>ApiUserResource<span class="token operator">>></span><span class="token punctuation">(</span>apiUsers<span class="token punctuation">)</span><span class="token punctuation">;</span> IEnumerable<span class="token operator"><</span>ApiUserResource<span class="token operator">></span> sortedApiUserResources <span class="token operator">=</span>
apiUserResources<span class="token punctuation">.</span><span class="token function">AsQueryable</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">ApplySort</span><span class="token punctuation">(</span>
parameters<span class="token punctuation">.</span>OrderBy<span class="token punctuation">,</span> _propertyMappingContainer<span class="token punctuation">.</span><span class="token generic-method"><span class="token function">Resolve</span><span class="token punctuation"><</span><span class="token class-name">ApiUserResource</span><span class="token punctuation">,</span> <span class="token class-name">ApiUser</span><span class="token punctuation">></span></span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span> IEnumerable<span class="token operator"><</span>ExpandoObject<span class="token operator">></span> shapedApiUserResources <span class="token operator">=</span>
sortedApiUserResources<span class="token punctuation">.</span><span class="token function">ToDynamicObject</span><span class="token punctuation">(</span>parameters<span class="token punctuation">.</span>Fields<span class="token punctuation">)</span><span class="token punctuation">;</span> IEnumerable<span class="token operator"><</span>ExpandoObject<span class="token operator">></span> shapedApiUserResourcesWithLinks <span class="token operator">=</span> shapedApiUserResources<span class="token punctuation">.</span><span class="token function">Select</span><span class="token punctuation">(</span>
x <span class="token operator">=></span>
<span class="token punctuation">{</span>
IDictionary<span class="token operator"><</span><span class="token keyword">string</span><span class="token punctuation">,</span> <span class="token keyword">object</span><span class="token operator">></span> dict <span class="token operator">=</span> x <span class="token keyword">as</span> IDictionary<span class="token operator"><</span><span class="token keyword">string</span><span class="token punctuation">,</span> <span class="token keyword">object</span><span class="token operator">></span><span class="token punctuation">;</span>
<span class="token keyword">if</span> <span class="token punctuation">(</span>dict<span class="token punctuation">.</span>Keys<span class="token punctuation">.</span><span class="token function">Contains</span><span class="token punctuation">(</span><span class="token string">"guid"</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
dict<span class="token punctuation">.</span><span class="token function">Add</span><span class="token punctuation">(</span><span class="token string">"links"</span><span class="token punctuation">,</span> <span class="token function">CreateLinksForApiUser</span><span class="token punctuation">(</span>
dict<span class="token punctuation">.</span><span class="token function">FirstOrDefault</span><span class="token punctuation">(</span>
a <span class="token operator">=></span> <span class="token keyword">string</span><span class="token punctuation">.</span><span class="token function">Equals</span><span class="token punctuation">(</span>
a<span class="token punctuation">.</span>Key<span class="token punctuation">,</span><span class="token string">"guid"</span><span class="token punctuation">,</span>StringComparison<span class="token punctuation">.</span>OrdinalIgnoreCase<span class="token punctuation">)</span><span class="token punctuation">)</span>
<span class="token punctuation">.</span>Value<span class="token punctuation">.</span><span class="token function">ToString</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">return</span> dict <span class="token keyword">as</span> ExpandoObject<span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">var</span> result <span class="token operator">=</span> <span class="token keyword">new</span>
<span class="token punctuation">{</span>
<span class="token keyword">value</span> <span class="token operator">=</span> shapedApiUserResourcesWithLinks<span class="token punctuation">,</span>
links <span class="token operator">=</span> <span class="token function">CreateLinksForApiUsers</span><span class="token punctuation">(</span>parameters<span class="token punctuation">,</span> apiUsers<span class="token punctuation">.</span>HasPreviousPage<span class="token punctuation">,</span> apiUsers<span class="token punctuation">.</span>HasNextPage<span class="token punctuation">)</span>
<span class="token punctuation">}</span><span class="token punctuation">;</span> <span class="token keyword">var</span> meta <span class="token operator">=</span> <span class="token keyword">new</span>
<span class="token punctuation">{</span>
apiUsers<span class="token punctuation">.</span>PageIndex<span class="token punctuation">,</span>
apiUsers<span class="token punctuation">.</span>PageSize<span class="token punctuation">,</span>
apiUsers<span class="token punctuation">.</span>PageCount<span class="token punctuation">,</span>
apiUsers<span class="token punctuation">.</span>TotalItemsCount<span class="token punctuation">,</span>
<span class="token punctuation">}</span><span class="token punctuation">;</span>
Response<span class="token punctuation">.</span>Headers<span class="token punctuation">.</span><span class="token function">Add</span><span class="token punctuation">(</span>
<span class="token string">"X-Pagination"</span><span class="token punctuation">,</span>
JsonConvert<span class="token punctuation">.</span><span class="token function">SerializeObject</span><span class="token punctuation">(</span>
meta<span class="token punctuation">,</span>
<span class="token keyword">new</span> <span class="token class-name">JsonSerializerSettings</span>
<span class="token punctuation">{</span> ContractResolver <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">CamelCasePropertyNamesContractResolver</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">return</span> <span class="token function">Ok</span><span class="token punctuation">(</span>result<span class="token punctuation">)</span><span class="token punctuation">;</span>
}
[HttpGet(Name = "GetAllApiUsers")]
[RequestHeaderMatchingMediaType("Accept",new string[] { "application/json" })]
public async Task<IActionResult> Get(ApiUserParameters parameters)
{
if (!_typeHelper.HasProperties<ApiUserResource>(parameters.Fields))
return BadRequest("fields not exist.");<span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span>_propertyMappingContainer<span class="token punctuation">.</span><span class="token generic-method"><span class="token function">ValidateMappingExistsFor</span><span class="token punctuation"><</span><span class="token class-name">ApiUserResource</span><span class="token punctuation">,</span> <span class="token class-name">ApiUser</span><span class="token punctuation">></span></span><span class="token punctuation">(</span>parameters<span class="token punctuation">.</span>OrderBy<span class="token punctuation">)</span><span class="token punctuation">)</span>
<span class="token keyword">return</span> <span class="token function">BadRequest</span><span class="token punctuation">(</span><span class="token string">"can't find fields for sorting."</span><span class="token punctuation">)</span><span class="token punctuation">;</span> PaginatedList<span class="token operator"><</span>ApiUser<span class="token operator">></span> apiUsers <span class="token operator">=</span> <span class="token keyword">await</span> _apiUserRepository<span class="token punctuation">.</span><span class="token function">GetAllApiUsersAsync</span><span class="token punctuation">(</span>parameters<span class="token punctuation">)</span><span class="token punctuation">;</span> IEnumerable<span class="token operator"><</span>ApiUserResource<span class="token operator">></span> apiUserResources <span class="token operator">=</span>
_mapper<span class="token punctuation">.</span>Map<span class="token operator"><</span>IEnumerable<span class="token operator"><</span>ApiUser<span class="token operator">></span><span class="token punctuation">,</span> IEnumerable<span class="token operator"><</span>ApiUserResource<span class="token operator">>></span><span class="token punctuation">(</span>apiUsers<span class="token punctuation">)</span><span class="token punctuation">;</span> IEnumerable<span class="token operator"><</span>ApiUserResource<span class="token operator">></span> sortedApiUserResources <span class="token operator">=</span>
apiUserResources<span class="token punctuation">.</span><span class="token function">AsQueryable</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">ApplySort</span><span class="token punctuation">(</span>
parameters<span class="token punctuation">.</span>OrderBy<span class="token punctuation">,</span> _propertyMappingContainer<span class="token punctuation">.</span><span class="token generic-method"><span class="token function">Resolve</span><span class="token punctuation"><</span><span class="token class-name">ApiUserResource</span><span class="token punctuation">,</span> <span class="token class-name">ApiUser</span><span class="token punctuation">></span></span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span> IEnumerable<span class="token operator"><</span>ExpandoObject<span class="token operator">></span> shapedApiUserResources <span class="token operator">=</span>
sortedApiUserResources<span class="token punctuation">.</span><span class="token function">ToDynamicObject</span><span class="token punctuation">(</span>parameters<span class="token punctuation">.</span>Fields<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">return</span> <span class="token function">Ok</span><span class="token punctuation">(</span>shapedApiUserResources<span class="token punctuation">)</span><span class="token punctuation">;</span>
}
[HttpGet("{guid}", Name = "GetApiUser")]
[RequestHeaderMatchingMediaType("Accept", new string[] { "application/vnd.laggage.hateoas+json" })]
public async Task<IActionResult> GetHateoas(string guid, string fields = null)
{
if (!_typeHelper.HasProperties<ApiUserResource>(fields))
return BadRequest("fields not exist.");<span class="token class-name">ApiUser</span> apiUser <span class="token operator">=</span> <span class="token keyword">await</span> _apiUserRepository<span class="token punctuation">.</span><span class="token function">GetApiUserByGuidAsync</span><span class="token punctuation">(</span>Guid<span class="token punctuation">.</span><span class="token function">Parse</span><span class="token punctuation">(</span>guid<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">if</span> <span class="token punctuation">(</span>apiUser <span class="token keyword">is</span> <span class="token keyword">null</span><span class="token punctuation">)</span> <span class="token keyword">return</span> <span class="token function">NotFound</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token class-name">ApiUserResource</span> apiUserResource <span class="token operator">=</span> _mapper<span class="token punctuation">.</span><span class="token generic-method"><span class="token function">Map</span><span class="token punctuation"><</span><span class="token class-name">ApiUser</span><span class="token punctuation">,</span> <span class="token class-name">ApiUserResource</span><span class="token punctuation">></span></span><span class="token punctuation">(</span>apiUser<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token class-name">ExpandoObject</span> shapedApiUserResource <span class="token operator">=</span> apiUserResource<span class="token punctuation">.</span><span class="token function">ToDynamicObject</span><span class="token punctuation">(</span>fields<span class="token punctuation">)</span><span class="token punctuation">;</span> IDictionary<span class="token operator"><</span><span class="token keyword">string</span><span class="token punctuation">,</span> <span class="token keyword">object</span><span class="token operator">></span> shapedApiUserResourceWithLink <span class="token operator">=</span> shapedApiUserResource <span class="token keyword">as</span> IDictionary<span class="token operator"><</span><span class="token keyword">string</span><span class="token punctuation">,</span> <span class="token keyword">object</span><span class="token operator">></span><span class="token punctuation">;</span>
shapedApiUserResourceWithLink<span class="token punctuation">.</span><span class="token function">Add</span><span class="token punctuation">(</span><span class="token string">"links"</span><span class="token punctuation">,</span> <span class="token function">CreateLinksForApiUser</span><span class="token punctuation">(</span>guid<span class="token punctuation">,</span> fields<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">return</span> <span class="token function">Ok</span><span class="token punctuation">(</span>shapedApiUserResourceWithLink<span class="token punctuation">)</span><span class="token punctuation">;</span>
}
[HttpGet("{guid}", Name = "GetApiUser")]
[RequestHeaderMatchingMediaType("Accept", new string[] { "application/json" })]
public async Task<IActionResult> Get(string guid, string fields = null)
{
if (!_typeHelper.HasProperties<ApiUserResource>(fields))
return BadRequest("fields not exist.");<span class="token class-name">ApiUser</span> apiUser <span class="token operator">=</span> <span class="token keyword">await</span> _apiUserRepository<span class="token punctuation">.</span><span class="token function">GetApiUserByGuidAsync</span><span class="token punctuation">(</span>Guid<span class="token punctuation">.</span><span class="token function">Parse</span><span class="token punctuation">(</span>guid<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">if</span> <span class="token punctuation">(</span>apiUser <span class="token keyword">is</span> <span class="token keyword">null</span><span class="token punctuation">)</span> <span class="token keyword">return</span> <span class="token function">NotFound</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token class-name">ApiUserResource</span> apiUserResource <span class="token operator">=</span> _mapper<span class="token punctuation">.</span><span class="token generic-method"><span class="token function">Map</span><span class="token punctuation"><</span><span class="token class-name">ApiUser</span><span class="token punctuation">,</span> <span class="token class-name">ApiUserResource</span><span class="token punctuation">></span></span><span class="token punctuation">(</span>apiUser<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token class-name">ExpandoObject</span> shapedApiUserResource <span class="token operator">=</span> apiUserResource<span class="token punctuation">.</span><span class="token function">ToDynamicObject</span><span class="token punctuation">(</span>fields<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">return</span> <span class="token function">Ok</span><span class="token punctuation">(</span>shapedApiUserResource<span class="token punctuation">)</span><span class="token punctuation">;</span>
}
Post添加资源
<p>Post - <strong>不安全</strong>,<strong>非幂等</strong><br>
要返回添加好的资源,并且返回头中有获得新创建资源的连接.
</p>
<h3 class="mume-header" id="%E5%AE%89%E5%85%A8%E6%80%A7%E5%92%8C%E5%B9%82%E7%AD%89%E6%80%A7">
安全性和幂等性</h3>
<ul>
<li>安全性是指方法执行后并不会改变资源的表述
</li>
<li>幂等性是指方法无论执行多少次都会得到同样<br>
的结果<br>
<img src="https://img2018.cnblogs.com/blog/1596066/201907/1596066-20190703115335902-2000181175.png" alt>
</li>
</ul>
<h3 class="mume-header" id="%E4%BB%A3%E7%A0%81%E5%AE%9E%E7%8E%B0">代码实现</h3>
<p>StartUp中注册Fluent,用于验证</p>
<pre data-role="codeBlock" data-info="CSharp" class="language-csharp">services<span class="token punctuation">.</span><span class="token function">AddMvc</span><span class="token punctuation">(</span><span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">.</span><span class="token punctuation">)</span>
<span class="token punctuation">.</span><span class="token function">AddFluentValidation</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
services.AddTransient<IValidator<ApiUserAddResource>, ApiUserAddResourceValidator>();
namespace ApiStudy.Infrastructure.Resources
{
using FluentValidation;<span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">ApiUserAddResourceValidator</span> <span class="token punctuation">:</span> <span class="token class-name">AbstractValidator</span><span class="token operator"><</span>ApiUserAddResource<span class="token operator">></span>
<span class="token punctuation">{</span>
<span class="token keyword">public</span> <span class="token function">ApiUserAddResourceValidator</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
<span class="token punctuation">{</span>
<span class="token function">RuleFor</span><span class="token punctuation">(</span>x <span class="token operator">=></span> x<span class="token punctuation">.</span>Name<span class="token punctuation">)</span>
<span class="token punctuation">.</span><span class="token function">MaximumLength</span><span class="token punctuation">(</span><span class="token number">20</span><span class="token punctuation">)</span>
<span class="token punctuation">.</span><span class="token function">WithName</span><span class="token punctuation">(</span><span class="token string">"用户名"</span><span class="token punctuation">)</span>
<span class="token punctuation">.</span><span class="token function">WithMessage</span><span class="token punctuation">(</span><span class="token string">"{PropertyName}的最大长度为20!"</span><span class="token punctuation">)</span>
<span class="token punctuation">.</span><span class="token function">NotNull</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
<span class="token punctuation">.</span><span class="token function">WithMessage</span><span class="token punctuation">(</span><span class="token string">"{PropertyName}是必填的!"</span><span class="token punctuation">)</span>
<span class="token punctuation">.</span><span class="token function">NotEmpty</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
<span class="token punctuation">.</span><span class="token function">WithMessage</span><span class="token punctuation">(</span><span class="token string">"{PropertyName}不能为空!"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token function">RuleFor</span><span class="token punctuation">(</span>x <span class="token operator">=></span> x<span class="token punctuation">.</span>Passwd<span class="token punctuation">)</span>
<span class="token punctuation">.</span><span class="token function">NotNull</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
<span class="token punctuation">.</span><span class="token function">WithName</span><span class="token punctuation">(</span><span class="token string">"密码"</span><span class="token punctuation">)</span>
<span class="token punctuation">.</span><span class="token function">WithMessage</span><span class="token punctuation">(</span><span class="token string">"{PropertyName}是必填的!"</span><span class="token punctuation">)</span>
<span class="token punctuation">.</span><span class="token function">MinimumLength</span><span class="token punctuation">(</span><span class="token number">6</span><span class="token punctuation">)</span>
<span class="token punctuation">.</span><span class="token function">WithMessage</span><span class="token punctuation">(</span><span class="token string">"{PropertyName}的最小长度是6"</span><span class="token punctuation">)</span>
<span class="token punctuation">.</span><span class="token function">MaximumLength</span><span class="token punctuation">(</span><span class="token number">16</span><span class="token punctuation">)</span>
<span class="token punctuation">.</span><span class="token function">WithMessage</span><span class="token punctuation">(</span><span class="token string">"{PropertyName}的最大长度是16"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token function">RuleFor</span><span class="token punctuation">(</span>x <span class="token operator">=></span> x<span class="token punctuation">.</span>PhoneNumber<span class="token punctuation">)</span>
<span class="token punctuation">.</span><span class="token function">NotNull</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
<span class="token punctuation">.</span><span class="token function">WithName</span><span class="token punctuation">(</span><span class="token string">"电话"</span><span class="token punctuation">)</span>
<span class="token punctuation">.</span><span class="token function">WithMessage</span><span class="token punctuation">(</span><span class="token string">"{PropertyName}是必填的!"</span><span class="token punctuation">)</span>
<span class="token punctuation">.</span><span class="token function">NotEmpty</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
<span class="token punctuation">.</span><span class="token function">WithMessage</span><span class="token punctuation">(</span><span class="token string">"{PropertyName}不能为空!"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span>
}
[HttpPost(Name = "CreateApiUser")]
[RequestHeaderMatchingMediaType("Content-Type",new string[] { "application/vnd.laggage.create.apiuser+json" })]
[RequestHeaderMatchingMediaType("Accept",new string[] { "application/vnd.laggage.hateoas+json" })]
public async Task<IActionResult> AddUser([FromBody] ApiUserAddResource apiUser)
{
if (!ModelState.IsValid)
return UnprocessableEntity(ModelState);<span class="token class-name">ApiUser</span> newUser <span class="token operator">=</span> _mapper<span class="token punctuation">.</span><span class="token generic-method"><span class="token function">Map</span><span class="token punctuation"><</span><span class="token class-name">ApiUser</span><span class="token punctuation">></span></span><span class="token punctuation">(</span>apiUser<span class="token punctuation">)</span><span class="token punctuation">;</span>
newUser<span class="token punctuation">.</span>Guid <span class="token operator">=</span> Guid<span class="token punctuation">.</span><span class="token function">NewGuid</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
newUser<span class="token punctuation">.</span>ProfilePhotoUrl <span class="token operator">=</span> $<span class="token string">"www.eample.com/photo/{newUser.Guid}"</span><span class="token punctuation">;</span>
newUser<span class="token punctuation">.</span>RegistrationDate <span class="token operator">=</span> DateTime<span class="token punctuation">.</span>Now<span class="token punctuation">;</span> <span class="token keyword">await</span> _apiUserRepository<span class="token punctuation">.</span><span class="token function">AddApiUserAsync</span><span class="token punctuation">(</span>newUser<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span><span class="token keyword">await</span> _unitOfWork<span class="token punctuation">.</span><span class="token function">SaveChangesAsync</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
<span class="token keyword">throw</span> <span class="token keyword">new</span> <span class="token class-name">Exception</span><span class="token punctuation">(</span><span class="token string">"Failed to save changes"</span><span class="token punctuation">)</span><span class="token punctuation">;</span> IDictionary<span class="token operator"><</span><span class="token keyword">string</span><span class="token punctuation">,</span> <span class="token keyword">object</span><span class="token operator">></span> shapedUserResource <span class="token operator">=</span>
_mapper<span class="token punctuation">.</span><span class="token generic-method"><span class="token function">Map</span><span class="token punctuation"><</span><span class="token class-name">ApiUserResource</span><span class="token punctuation">></span></span><span class="token punctuation">(</span>newUser<span class="token punctuation">)</span>
<span class="token punctuation">.</span><span class="token function">ToDynamicObject</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token keyword">as</span> IDictionary<span class="token operator"><</span><span class="token keyword">string</span><span class="token punctuation">,</span> <span class="token keyword">object</span><span class="token operator">></span><span class="token punctuation">;</span>
IEnumerable<span class="token operator"><</span>LinkResource<span class="token operator">></span> links <span class="token operator">=</span> <span class="token function">CreateLinksForApiUser</span><span class="token punctuation">(</span>newUser<span class="token punctuation">.</span>Guid<span class="token punctuation">.</span><span class="token function">ToString</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
shapedUserResource<span class="token punctuation">.</span><span class="token function">Add</span><span class="token punctuation">(</span><span class="token string">"links"</span><span class="token punctuation">,</span> links<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">return</span> <span class="token function">CreatedAtRoute</span><span class="token punctuation">(</span><span class="token string">"GetApiUser"</span><span class="token punctuation">,</span><span class="token keyword">new</span> <span class="token punctuation">{</span> newUser<span class="token punctuation">.</span>Guid <span class="token punctuation">}</span><span class="token punctuation">,</span> shapedUserResource<span class="token punctuation">)</span><span class="token punctuation">;</span>
}
Delete
<ul>
<li>参数 : <strong>ID</strong></li>
<li>幂等的
<ul>
<li>多次请求的副作用和单次请求的副作用是一样的.每次发送了DELETE请求之后,服务器的状态都是一样的.
</li>
</ul>
</li>
<li>不安全</li>
</ul>
<details>
<summary>ApiStudy.Api.Controllers.UserController</summary>
<pre data-role="codeBlock" data-info="CSharp" class="language-csharp"><span class="token punctuation">[</span><span class="token class-name">HttpDelete</span><span class="token punctuation">(</span><span class="token string">"{guid}"</span><span class="token punctuation">,</span>Name <span class="token operator">=</span> <span class="token string">"DeleteApiUser"</span><span class="token punctuation">)</span><span class="token punctuation">]</span>
public async Task<IActionResult> DeleteApiUser(string guid)
{
ApiUser userToDelete = await _apiUserRepository.GetApiUserByGuidAsync(new Guid(guid));
<span class="token keyword">if</span> <span class="token punctuation">(</span>userToDelete <span class="token operator">==</span> <span class="token keyword">null</span><span class="token punctuation">)</span> <span class="token keyword">return</span> <span class="token function">NotFound</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">await</span> _apiUserRepository<span class="token punctuation">.</span><span class="token function">DeleteApiUserAsync</span><span class="token punctuation">(</span>userToDelete<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span><span class="token keyword">await</span> _unitOfWork<span class="token punctuation">.</span><span class="token function">SaveChangesAsync</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
<span class="token keyword">throw</span> <span class="token keyword">new</span> <span class="token class-name">Exception</span><span class="token punctuation">(</span><span class="token string">"Failed to delete apiUser"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">return</span> <span class="token function">NoContent</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
}
PUT & PATCH
<p>相关类:</p>
<details>
<summary>ApiStudy.Infrastructure.Resources.ApiUserAddOrUpdateResource</summary>
<pre data-role="codeBlock" data-info="CSharp" class="language-csharp"><span class="token keyword">namespace</span> ApiStudy<span class="token punctuation">.</span>Infrastructure<span class="token punctuation">.</span>Resources
{
using System;
<span class="token keyword">public</span> <span class="token keyword">abstract</span> <span class="token keyword">class</span> <span class="token class-name">ApiUserAddOrUpdateResource</span>
<span class="token punctuation">{</span>
<span class="token keyword">public</span> <span class="token keyword">string</span> Name <span class="token punctuation">{</span> <span class="token keyword">get</span><span class="token punctuation">;</span> <span class="token keyword">set</span><span class="token punctuation">;</span> <span class="token punctuation">}</span>
<span class="token keyword">public</span> <span class="token keyword">string</span> Passwd <span class="token punctuation">{</span> <span class="token keyword">get</span><span class="token punctuation">;</span> <span class="token keyword">set</span><span class="token punctuation">;</span> <span class="token punctuation">}</span>
<span class="token keyword">public</span> <span class="token class-name">DateTime</span> Birth <span class="token punctuation">{</span> <span class="token keyword">get</span><span class="token punctuation">;</span> <span class="token keyword">set</span><span class="token punctuation">;</span> <span class="token punctuation">}</span>
<span class="token keyword">public</span> <span class="token keyword">string</span> PhoneNumber <span class="token punctuation">{</span> <span class="token keyword">get</span><span class="token punctuation">;</span> <span class="token keyword">set</span><span class="token punctuation">;</span> <span class="token punctuation">}</span>
<span class="token keyword">public</span> <span class="token keyword">string</span> Email <span class="token punctuation">{</span> <span class="token keyword">get</span><span class="token punctuation">;</span> <span class="token keyword">set</span><span class="token punctuation">;</span> <span class="token punctuation">}</span>
<span class="token punctuation">}</span>
}
namespace ApiStudy.Infrastructure.Resources
{
public class ApiUserAddResource:ApiUserAddOrUpdateResource
{
}
}
namespace ApiStudy.Infrastructure.Resources
{
public class ApiUserUpdateResource : ApiUserAddOrUpdateResource
{
}
}
namespace ApiStudy.Infrastructure.Resources
{
using FluentValidation;<span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">ApiUserAddOrUpdateResourceValidator</span><span class="token operator"><</span>T<span class="token operator">></span> <span class="token punctuation">:</span> AbstractValidator<span class="token operator"><</span>T<span class="token operator">></span> <span class="token keyword">where</span> T<span class="token punctuation">:</span> ApiUserAddOrUpdateResource
<span class="token punctuation">{</span>
<span class="token keyword">public</span> <span class="token function">ApiUserAddOrUpdateResourceValidator</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
<span class="token punctuation">{</span>
<span class="token function">RuleFor</span><span class="token punctuation">(</span>x <span class="token operator">=></span> x<span class="token punctuation">.</span>Name<span class="token punctuation">)</span>
<span class="token punctuation">.</span><span class="token function">MaximumLength</span><span class="token punctuation">(</span><span class="token number">20</span><span class="token punctuation">)</span>
<span class="token punctuation">.</span><span class="token function">WithName</span><span class="token punctuation">(</span><span class="token string">"用户名"</span><span class="token punctuation">)</span>
<span class="token punctuation">.</span><span class="token function">WithMessage</span><span class="token punctuation">(</span><span class="token string">"{PropertyName}的最大长度为20!"</span><span class="token punctuation">)</span>
<span class="token punctuation">.</span><span class="token function">NotNull</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
<span class="token punctuation">.</span><span class="token function">WithMessage</span><span class="token punctuation">(</span><span class="token string">"{PropertyName}是必填的!"</span><span class="token punctuation">)</span>
<span class="token punctuation">.</span><span class="token function">NotEmpty</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
<span class="token punctuation">.</span><span class="token function">WithMessage</span><span class="token punctuation">(</span><span class="token string">"{PropertyName}不能为空!"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token function">RuleFor</span><span class="token punctuation">(</span>x <span class="token operator">=></span> x<span class="token punctuation">.</span>Passwd<span class="token punctuation">)</span>
<span class="token punctuation">.</span><span class="token function">NotNull</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
<span class="token punctuation">.</span><span class="token function">WithName</span><span class="token punctuation">(</span><span class="token string">"密码"</span><span class="token punctuation">)</span>
<span class="token punctuation">.</span><span class="token function">WithMessage</span><span class="token punctuation">(</span><span class="token string">"{PropertyName}是必填的!"</span><span class="token punctuation">)</span>
<span class="token punctuation">.</span><span class="token function">MinimumLength</span><span class="token punctuation">(</span><span class="token number">6</span><span class="token punctuation">)</span>
<span class="token punctuation">.</span><span class="token function">WithMessage</span><span class="token punctuation">(</span><span class="token string">"{PropertyName}的最小长度是6"</span><span class="token punctuation">)</span>
<span class="token punctuation">.</span><span class="token function">MaximumLength</span><span class="token punctuation">(</span><span class="token number">16</span><span class="token punctuation">)</span>
<span class="token punctuation">.</span><span class="token function">WithMessage</span><span class="token punctuation">(</span><span class="token string">"{PropertyName}的最大长度是16"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token function">RuleFor</span><span class="token punctuation">(</span>x <span class="token operator">=></span> x<span class="token punctuation">.</span>PhoneNumber<span class="token punctuation">)</span>
<span class="token punctuation">.</span><span class="token function">NotNull</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
<span class="token punctuation">.</span><span class="token function">WithName</span><span class="token punctuation">(</span><span class="token string">"电话"</span><span class="token punctuation">)</span>
<span class="token punctuation">.</span><span class="token function">WithMessage</span><span class="token punctuation">(</span><span class="token string">"{PropertyName}是必填的!"</span><span class="token punctuation">)</span>
<span class="token punctuation">.</span><span class="token function">NotEmpty</span><span class="token punctuation">(</span><span class="token punctuation">)</span>
<span class="token punctuation">.</span><span class="token function">WithMessage</span><span class="token punctuation">(</span><span class="token string">"{PropertyName}不能为空!"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span>
}
PUT 整体更新
<ul>
<li>返回204</li>
<li>参数
<ul>
<li>ID,</li>
<li>[FromBody]XxxxUpdateResource</li>
</ul>
</li>
</ul>
<details>
<summary>ApiStudy.Api.Controllers.UpdateApiUser</summary>
<pre data-role="codeBlock" data-info="CSharp" class="language-csharp"><span class="token punctuation">[</span><span class="token class-name">HttpPut</span><span class="token punctuation">(</span><span class="token string">"{guid}"</span><span class="token punctuation">,</span>Name <span class="token operator">=</span> <span class="token string">"PutApiUser"</span><span class="token punctuation">)</span><span class="token punctuation">]</span>
public async Task<IActionResult> UpdateApiUser(string guid,[FromBody] ApiUserUpdateResource apiUserUpdateResource)
{
if (!ModelState.IsValid) return BadRequest(ModelState);
<span class="token class-name">ApiUser</span> userToUpdate <span class="token operator">=</span> <span class="token keyword">await</span> _apiUserRepository<span class="token punctuation">.</span><span class="token function">GetApiUserByGuidAsync</span><span class="token punctuation">(</span><span class="token keyword">new</span> <span class="token class-name">Guid</span><span class="token punctuation">(</span>guid<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">if</span> <span class="token punctuation">(</span>userToUpdate <span class="token operator">==</span> <span class="token keyword">null</span><span class="token punctuation">)</span> <span class="token keyword">return</span> <span class="token function">NotFound</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
_mapper<span class="token punctuation">.</span><span class="token function">Map</span><span class="token punctuation">(</span>apiUserUpdateResource<span class="token punctuation">,</span> userToUpdate<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span><span class="token keyword">await</span> _unitOfWork<span class="token punctuation">.</span><span class="token function">SaveChangesAsync</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span>
<span class="token keyword">throw</span> <span class="token keyword">new</span> <span class="token class-name">Exception</span><span class="token punctuation">(</span><span class="token string">"Failed to update Entity of ApiUser"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">return</span> <span class="token function">NoContent</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
}
PATCH
<ul>
<li>Content-Type
<ul>
<li>application/json-patch+json</li>
</ul>
</li>
<li>返回204</li>
<li>参数
<ul>
<li>ID</li>
<li>[FromBody] JsonPatchDocument<xxxxupdateresource></xxxxupdateresource>
</li>
</ul>
</li>
<li>op操作
<ul>
<li>添加:{“op”: "add", "path":
"/xxx", "value":
"xxx"},如果该属性不存,那么就添加该属性,如<br>
果属性存在,就改变属性的值。这个对静态类型不适用。
</li>
<li>删除:{“op”: "<strong>remove</strong>",
"path":
"/xxx"},删除某个属性,或把它设为默认值(例如空值)。
</li>
<li>替换:{“op”: "<strong>replace</strong>",
"path": "/xxx", "value":
"xxx"},改变属性的值,也可以理解为先执行<br>
了删除,然后进行添加。</li>
<li>复制:{“op”: "copy", "from":
"/xxx", "path":
"/yyy"},把某个属性的值赋给目标属性。
</li>
<li>移动:{“op”: "move", "from":
"/xxx", "path":
"/yyy"},把源属性的值赋值给目标属性,并把源<br>
属性删除或设成默认值。</li>
<li>测试:{“op”: "test", "path":
"/xxx", "value":
"xxx"},测试目标属性的值和指定的值是一样的。
</li>
</ul>
</li>
<li><strong>path,资源的属性名</strong>
<ul>
<li>可以有层级结构</li>
</ul>
</li>
<li><strong>value 更新的值</strong></li>
</ul>
<pre data-role="codeBlock" data-info="json" class="language-json"><span class="token punctuation">[</span>
<span class="token punctuation">{</span>
<span class="token property">"op"</span><span class="token operator">:</span><span class="token string">"replace"</span><span class="token punctuation">,</span>
<span class="token property">"path"</span><span class="token operator">:</span><span class="token string">"/name"</span><span class="token punctuation">,</span>
<span class="token property">"value"</span><span class="token operator">:</span><span class="token string">"阿黄"</span>
<span class="token punctuation">}</span><span class="token punctuation">,</span>
<span class="token punctuation">{</span>
<span class="token property">"op"</span><span class="token operator">:</span><span class="token string">"remove"</span><span class="token punctuation">,</span>
<span class="token property">"path"</span><span class="token operator">:</span><span class="token string">"/email"</span>
<span class="token punctuation">}</span>
]
[HttpPatch("{guid}",Name = "PatchApiUser")]
[RequestHeaderMatchingMediaType("Content-Type",new string[] { "application/vnd.laggage.patch.apiuser+json" })]
public async Task<IActionResult> UpdateApiUser(
string guid,[FromBody] JsonPatchDocument<ApiUserUpdateResource> userUpdateDoc)
{
if (userUpdateDoc == null) return BadRequest();<span class="token class-name">ApiUser</span> userToUpdate <span class="token operator">=</span> <span class="token keyword">await</span> _apiUserRepository<span class="token punctuation">.</span><span class="token function">GetApiUserByGuidAsync</span><span class="token punctuation">(</span><span class="token keyword">new</span> <span class="token class-name">Guid</span><span class="token punctuation">(</span>guid<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">if</span> <span class="token punctuation">(</span>userToUpdate <span class="token keyword">is</span> <span class="token keyword">null</span><span class="token punctuation">)</span> <span class="token keyword">return</span> <span class="token function">NotFound</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token class-name">ApiUserUpdateResource</span> userToUpdateResource <span class="token operator">=</span> _mapper<span class="token punctuation">.</span><span class="token generic-method"><span class="token function">Map</span><span class="token punctuation"><</span><span class="token class-name">ApiUserUpdateResource</span><span class="token punctuation">></span></span><span class="token punctuation">(</span>userToUpdate<span class="token punctuation">)</span><span class="token punctuation">;</span>
userUpdateDoc<span class="token punctuation">.</span><span class="token function">ApplyTo</span><span class="token punctuation">(</span>userToUpdateResource<span class="token punctuation">)</span><span class="token punctuation">;</span> _mapper<span class="token punctuation">.</span><span class="token function">Map</span><span class="token punctuation">(</span>userToUpdateResource<span class="token punctuation">,</span> userToUpdate<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">if</span> <span class="token punctuation">(</span><span class="token operator">!</span><span class="token keyword">await</span> _unitOfWork<span class="token punctuation">.</span><span class="token function">SaveChangesAsync</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token keyword">throw</span> <span class="token keyword">new</span> <span class="token class-name">Exception</span><span class="token punctuation">(</span><span class="token string">"Failed to update Entity of ApiUser"</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword">return</span> <span class="token function">NoContent</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
}
Http常用方法总结
<ul>
<li><strong>GET</strong>(获取资源):
<ul>
<li>GET
api/countries,返回200,集合数据;找不到数据返回404。
</li>
<li>GET
api/countries/{id},返回200,单个数据;找不到返回404.
</li>
</ul>
</li>
<li><strong>DELETE</strong>(删除资源)
<ul>
<li>DELETE
api/countries/{id},成功204;没找到资源404。
</li>
<li>DELETE
api/countries,很少用,也是204或者404.
</li>
</ul>
</li>
<li><strong>POST</strong> (创建资源):
<ul>
<li>POST
api/countries,成功返回201和单个数据;如果资源没有创建则返回404
</li>
<li>POST
api/countries/{id},肯定不会成功,返回404或409.
</li>
<li>POST
api/countrycollections,成功返回201和集合;没创建资源则返回404
</li>
</ul>
</li>
<li><strong>PUT</strong> (整体更新):
<ul>
<li>PUT
api/countries/{id},成功可以返回200,204;没找到资源则返回404
</li>
<li>PUT
api/countries,集合操作很少见,返回200,204或404
</li>
</ul>
</li>
<li><strong>PATCH</strong>(局部更新):
<ul>
<li>PATCHapi/countries/{id},200单个数据,204或者404
</li>
<li>PATCHapi/countries,集合操作很少见,返回200集合,204或404.
</li>
</ul>
</li>
</ul>
</div>
Asp.NetCoreWebApi - RESTful Api的更多相关文章
- ASP.NET Core Web API 开发-RESTful API实现
ASP.NET Core Web API 开发-RESTful API实现 REST 介绍: 符合REST设计风格的Web API称为RESTful API. 具象状态传输(英文:Representa ...
- IIS 部署ASP.Net, WebAPI, Restful API, PUT/DELETE 报405错解决办法, webapi method not allowed 405
WebDAV 是超文本传输协议 (HTTP) 的一组扩展,为 Internet 上计算机之间的编辑和文件管理提供了标准.利用这个协议用户可以通过Web进行远程的基本文件操作,如拷贝.移动.删除等.在I ...
- 使用ASP.NET Core 3.x 构建 RESTful API - 1.准备工作
以前写过ASP.NET Core 2.x的REST API文章,今年再更新一下到3.0版本. 先决条件 我在B站有一个非常入门的ASP.NET Core 3.0的视频教程,如果您对ASP.NET Co ...
- 使用ASP.NET Core 3.x 构建 RESTful API - 2. 什么是RESTful API
1. 使用ASP.NET Core 3.x 构建 RESTful API - 1.准备工作 什么是REST REST一词最早是在2000年,由Roy Fielding在他的博士论文<Archit ...
- 使用ASP.NET Core 3.x 构建 RESTful API - 3.4 内容协商
现在,当谈论起 RESTful Web API 的时候,人们总会想到 JSON.但是实际上,JSON 和 RESTful API 没有半毛钱关系,只不过 JSON 恰好是RESTful API 结果的 ...
- 使用ASP.NET Core构建RESTful API的技术指南
译者荐语:利用周末的时间,本人拜读了长沙.NET技术社区翻译的技术标准<微软RESTFul API指南>,打算按照步骤写一个完整的教程,后来无意中看到了这篇文章,与我要写的主题有不少相似之 ...
- 使用ASP.NET Core 3.x 构建 RESTful API - 3.1 资源命名
之前讲了RESTful API的统一资源接口这个约束,里面提到了资源是通过URI来进行识别的,每个资源都有自己的URI.URI里还涉及到资源的名称,而针对资源的名称却没有一个标准来进行规范,但是业界还 ...
- 在一个空ASP.NET Web项目上创建一个ASP.NET Web API 2.0应用
由于ASP.NET Web API具有与ASP.NET MVC类似的编程方式,再加上目前市面上专门介绍ASP.NET Web API 的书籍少之又少(我们看到的相关内容往往是某本介绍ASP.NET M ...
- How ASP.NET Web API 2.0 Works?[持续更新中…]
一.概述 RESTful Web API [Web标准篇]RESTful Web API [设计篇] 在一个空ASP.NET Web项目上创建一个ASP.NET Web API 2.0应用 二.路由 ...
随机推荐
- Docker 清理日志
docker 长时间运行后,日志文件会逐渐变大可以使用下面命令进行清除 #!/bin/bash echo "==================== start clean docker c ...
- odoo10学习笔记四:onchange、唯一性约束
转载请注明原文地址:https://www.cnblogs.com/ygj0930/p/11189273.html 一:onchange机制[onchange=前端js函数!可以实现前端实时更新以及修 ...
- Python 简易web日志查看工具&可改装为命令行工具
Python 简易web日志查看工具&可改装为命令行工具 效果图 原理 利用python的paramiko库模拟ssh登录操作,并执行tail命令 所需库 flask.paramiko.gev ...
- c# 第18节 数组的操作
本节内容: 1:遍历数组 2:查找数组元素 3:数组排序 4:数组合并与拆分 5:数组的添加 1:遍历数组 遍历数组方法: :数组.length ###获取数组长度 :数组.GetLowerBound ...
- 201871010126 王亚涛 《面向对象程序设计(Java)》第八周实验总结
项目 内容 这个作业属于哪个课程 https://www.cnblogs.com/nwnu-daizh/ 这个作业的要求在哪里 https://www.cnblogs.com/nwnu-daizh/p ...
- docker 持久化存储
1.data Volume mysql5.7:dockerfile FROM debian:stretch-slim # add our user and group first to make s ...
- Springboot将数据存储到数据库当中
1.从前端获取数据,同时存储到use当中 public String login(HttpServletRequest request) { User user = new User(); user. ...
- 【Oracle】Windows启动
cd D:\app\Administrator\product\\dbhome_1\BIN D: sqlplus /nolog conn sys/system as sysdba startup pf ...
- python27期尚哥讲网络编程:
python27day26网络编程----------------------------------------------------------------------------------- ...
- leetcode138. 复制带随机指针的链表
思路一:哈希 借助哈希保存节点信息. 代码 时间复杂度:O(n)空间复杂度:O(n) class Solution{ public: Node* copyRandomList(Node* head) ...