Asp.NetCoreWebApi - RESTful Api
阅读原文时间:2023年07月15日阅读:6

目录

  • 参考文章

  • REST

  • 常用http动词

  • WebApi 在 Asp.NetCore 中的实现

  • 支持https

  • 支持HSTS

  • 使用SerilLog

  • Asp.NetCore配置文件

  • 自定义一个异常处理,ExceptionHandler

  • 实现数据接口类(Resource),使用AutoMapper在Resource和Entity中映射

  • 使用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年在他的博士论文
        &quot;Architectural Styles and the Design of Network-based Software Architectures&quot;
        中提出来的一种万维网软件架构风格。<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官方的包是
            MySql.Data.EntityFrameworkCore,但是这个包有bug,我在github上看到有人说有替代方案
            -
            Pomelo.EntityFrameworkCore.MySql,经过尝试,后者比前者好用.所有这里就选择后者了.使用前者的话可能会导致数据库迁移失败(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项目安装 Pomelo.EntityFrameworkCore.MySql<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>

}

UserContext

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">&lt;</span>UserContext<span class="token operator">&gt;</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">&lt;</span><span class="token class-name">ApiUser</span><span class="token punctuation">&gt;</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">=&gt;</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">&lt;</span>ApiUser<span class="token operator">&gt;</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">&lt;</span><span class="token class-name">UserContext</span><span class="token punctuation">&gt;</span></span><span class="token punctuation">(</span>options <span class="token operator">=&gt;</span>
        <span class="token punctuation">{</span>
            <span class="token keyword">string</span> connString <span class="token operator">=</span> <span class="token string">&quot;Server=Xxx:xxx:xxx:xxx;Database=Xxxx;Uid=root;Pwd=Xxxxx; &quot;</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 &gt; NuGet Package Manager &gt; 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">
        迁移数据库失败, 提示 Unable to create an object
                of type &apos;&lt;Xxxx&gt;Context&apos;. For the different patterns supported at design time, see
                https://go.microsoft.com/fwlink/?linkid=851728</h4>

    <p>原因应该是EfCore迁移工具不知道如何创建
        <strong>DbContext</strong> 导致的.</p>
    <p><strong>解决方案</strong></p>
    <p>在DbContext所在的项目下新建一个类:
    </p>
    <pre data-role="codeBlock" data-info="CSharp" class="language-csharp"><span class="token comment">/// &lt;summary&gt;</span>

/// 设计时DbContext的创建, 告诉EF Core迁移工具如何创建DbContext

///

public class ContextFactory : IDesignTimeDbContextFactory<Context>

{

public Context CreateDbContext(string[] args)

{

var optionsBuilder = new DbContextOptionsBuilder<Context>();

optionsBuilder.UseMySql(

@"Server=[服务器ip];Database=[数据库]];Uid=[用户名];Pwd=[密码];");

    <span class="token keyword">return</span> <span class="token keyword">new</span> <span class="token operator">&lt;</span>Xxxx<span class="token operator">&gt;</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">&quot;la&quot;</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">&quot;123587&quot;</span><span class="token punctuation">,</span>
                        ProfilePhotoUrl <span class="token operator">=</span> <span class="token string">&quot;https://www.laggage.top/&quot;</span><span class="token punctuation">,</span>
                        PhoneNumber <span class="token operator">=</span> <span class="token string">&quot;10086&quot;</span><span class="token punctuation">,</span>
                        Email <span class="token operator">=</span> <span class="token string">&quot;yu@outlook.com&quot;</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">&quot;David&quot;</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">&quot;awt87495987&quot;</span><span class="token punctuation">,</span>
                        ProfilePhotoUrl <span class="token operator">=</span> <span class="token string">&quot;https://www.laggage.top/&quot;</span><span class="token punctuation">,</span>
                        PhoneNumber <span class="token operator">=</span> <span class="token string">&quot;1008611&quot;</span><span class="token punctuation">,</span>
                        Email <span class="token operator">=</span> <span class="token string">&quot;David@outlook.com&quot;</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">&quot;David&quot;</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">&quot;awt87495987&quot;</span><span class="token punctuation">,</span>
                        ProfilePhotoUrl <span class="token operator">=</span> <span class="token string">&quot;https://www.laggage.top/&quot;</span><span class="token punctuation">,</span>
                        PhoneNumber <span class="token operator">=</span> <span class="token string">&quot;1008611&quot;</span><span class="token punctuation">,</span>
                        Email <span class="token operator">=</span> <span class="token string">&quot;David@outlook.com&quot;</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">&quot;Linus&quot;</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">&quot;awt87495987&quot;</span><span class="token punctuation">,</span>
                        ProfilePhotoUrl <span class="token operator">=</span> <span class="token string">&quot;https://www.laggage.top/&quot;</span><span class="token punctuation">,</span>
                        PhoneNumber <span class="token operator">=</span> <span class="token string">&quot;17084759987&quot;</span><span class="token punctuation">,</span>
                        Email <span class="token operator">=</span> <span class="token string">&quot;Linus@outlook.com&quot;</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">&quot;YouYou&quot;</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">&quot;grwe874864987&quot;</span><span class="token punctuation">,</span>
                        ProfilePhotoUrl <span class="token operator">=</span> <span class="token string">&quot;https://www.laggage.top/&quot;</span><span class="token punctuation">,</span>
                        PhoneNumber <span class="token operator">=</span> <span class="token string">&quot;17084759987&quot;</span><span class="token punctuation">,</span>
                        Email <span class="token operator">=</span> <span class="token string">&quot;YouYou@outlook.com&quot;</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">&quot;小白&quot;</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">&quot;gewa749864&quot;</span><span class="token punctuation">,</span>
                        ProfilePhotoUrl <span class="token operator">=</span> <span class="token string">&quot;https://www.laggage.top/&quot;</span><span class="token punctuation">,</span>
                        PhoneNumber <span class="token operator">=</span> <span class="token string">&quot;17084759987&quot;</span><span class="token punctuation">,</span>
                        Email <span class="token operator">=</span> <span class="token string">&quot;BaiBai@outlook.com&quot;</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">&lt;</span><span class="token class-name">UserContextSeed</span><span class="token punctuation">&gt;</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">&quot;Error occurred while seeding database&quot;</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();

    ILoggerFactory loggerFactory = provider.GetService();

    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);



    <p>将所有http请求全部映射到https</p>
    <p>Startup中:<br>
        ConfigureServices方法注册,并配置端口和状态码等:<br>
        services.AddHttpsRedirection(…)</p>
    <pre data-role="codeBlock" data-info class="language-"><code>services.AddHttpsRedirection(options =&gt;
            {
                options.RedirectStatusCode = StatusCodes.Status307TemporaryRedirect;
                options.HttpsPort = 5001;
            });

Configure方法使用该中间件:

app.UseHttpsRedirection()


    <p>ConfigureServices方法注册<br>
        看<a
            href="https://docs.microsoft.com/en-us/aspnet/core/security/enforcing-ssl?view=aspnetcore-2.1&amp;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">=&gt;</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()

方法之后.

    <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">&quot;Microsoft&quot;</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()
.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(&quot;appsettings.json&quot;).Build()--&gt;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”]

    <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">=&gt;</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">=&gt;</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">&quot;application/json&quot;</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">&lt;</span><span class="token class-name">Exception</span><span class="token punctuation">&gt;</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">&quot;ApiStudy.Api.Extensions.ExceptionHandlingExtensions&quot;</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">&quot;Error occurred.&quot;</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">&quot;Error occurred, but cannot get exception message.For more detail, go to see the log.&quot;</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>

}

    <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>
                AutoMapper<br>
                AutoMapper.Extensions.Microsoft.DependencyInjection</p>
        </li>
        <li>
            <p>配置映射<br>
                可以创建Profile<br>
                CreateMap&lt;TSource,TDestination&gt;()</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">&lt;</span><span class="token class-name">ApiUser</span><span class="token punctuation">,</span> <span class="token class-name">ApiUserResource</span><span class="token punctuation">&gt;</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">=&gt;</span> d<span class="token punctuation">.</span>Passwd<span class="token punctuation">,</span>
            opt <span class="token operator">=&gt;</span> opt<span class="token punctuation">.</span><span class="token function">AddTransform</span><span class="token punctuation">(</span>s <span class="token operator">=&gt;</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">&lt;</span><span class="token class-name">ApiUserResource</span><span class="token punctuation">,</span> <span class="token class-name">ApiUser</span><span class="token punctuation">&gt;</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">=&gt;</span> d<span class="token punctuation">.</span>Passwd<span class="token punctuation">,</span>
            opt <span class="token operator">=&gt;</span> opt<span class="token punctuation">.</span><span class="token function">AddTransform</span><span class="token punctuation">(</span>s <span class="token operator">=&gt;</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()

    <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">&lt;</span>ApiUserResource<span class="token operator">&gt;</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">=&gt;</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">&quot;用户名&quot;</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">&quot;{PropertyName}的最大长度为80&quot;</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">&quot;{PropertyName}不能为空!&quot;</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,

    ApiUserResourceValidator>();`

    <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 Get()

{

IEnumerable apiUsers = await _apiUserRepository.GetAllApiUsersAsync();

IEnumerable<span class="token operator">&lt;</span>ApiUserResource<span class="token operator">&gt;</span> apiUserResources <span class="token operator">=</span>
    _mapper<span class="token punctuation">.</span>Map<span class="token operator">&lt;</span>IEnumerable<span class="token operator">&lt;</span>ApiUser<span class="token operator">&gt;</span><span class="token punctuation">,</span>IEnumerable<span class="token operator">&lt;</span>ApiUserResource<span class="token operator">&gt;&gt;</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 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">&lt;</span><span class="token class-name">ApiUser</span><span class="token punctuation">,</span><span class="token class-name">ApiUserResource</span><span class="token punctuation">&gt;</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>例如api/department/{departmentId}/emoloyees,
            这就表示了 department
            (部门)和员工<br>
            (<strong>employee</strong>)之前是主从关系.</li>
        <li>而api/department/{departmentId}/emoloyees/{employeeId},就表示了该部门下的某个员<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 =&gt;

{

options.ReturnHttpNotAcceptable = true;

});

  • 支持输出XML格式: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">=&gt;</span> _pageIndex<span class="token punctuation">;</span>
        <span class="token keyword">set</span> <span class="token operator">=&gt;</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">=&gt;</span> _pageSize<span class="token punctuation">;</span>
        <span class="token keyword">set</span> <span class="token operator">=&gt;</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">=&gt;</span> _maxPageSize<span class="token punctuation">;</span>
        <span class="token keyword">set</span> <span class="token operator">=&gt;</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">&lt;</span><span class="token class-name">TField</span><span class="token punctuation">&gt;</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">&lt;</span>TField<span class="token operator">&gt;</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">&lt;=</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">&lt;=</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">&gt;</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>

}

ApiUserParameters

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 GetAllApiUsers(ApiUserParameters parameters)

{

return new PaginatedList(

parameters.PageIndex,

parameters.PageSize,

_context.ApiUsers.Count(),

_context.ApiUsers.Skip(parameters.PageIndex * parameters.PageSize)

.Take(parameters.PageSize));

}

public Task> GetAllApiUsersAsync(ApiUserParameters parameters)

{

return Task.Run(() => GetAllApiUsers(parameters));

}

/----- IApiUserRepository -----/

PaginatedList GetAllApiUsers(ApiUserParameters parameters);

Task> GetAllApiUsersAsync(ApiUserParameters parameters);

UserController部分代码

[HttpGet(Name = "GetAllApiUsers")]

public async Task GetAllApiUsers(ApiUserParameters parameters)

{

PaginatedList apiUsers = await _apiUserRepository.GetAllApiUsersAsync(parameters);

IEnumerable<span class="token operator">&lt;</span>ApiUserResource<span class="token operator">&gt;</span> apiUserResources <span class="token operator">=</span>
    _mapper<span class="token punctuation">.</span>Map<span class="token operator">&lt;</span>IEnumerable<span class="token operator">&lt;</span>ApiUser<span class="token operator">&gt;</span><span class="token punctuation">,</span>IEnumerable<span class="token operator">&lt;</span>ApiUserResource<span class="token operator">&gt;&gt;</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">&quot;X-Pagination&quot;</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">&lt;</span>ApiUser<span class="token operator">&gt;</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 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">=&gt;</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">&lt;</span><span class="token class-name">ApiUser</span><span class="token punctuation">&gt;</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">&gt;排序思路</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>

}

IPropertyMapping

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">&lt;</span><span class="token keyword">string</span><span class="token punctuation">,</span> List<span class="token operator">&lt;</span>MappedProperty<span class="token operator">&gt;&gt;</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>

} PropertyMapping

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">&lt;</span>TSource<span class="token punctuation">,</span>TDestination<span class="token operator">&gt;</span> <span class="token punctuation">:</span> IPropertyMapping
<span class="token punctuation">{</span>
    <span class="token keyword">public</span> Dictionary<span class="token operator">&lt;</span><span class="token keyword">string</span><span class="token punctuation">,</span> List<span class="token operator">&lt;</span>MappedProperty<span class="token operator">&gt;&gt;</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">&lt;</span><span class="token keyword">string</span><span class="token punctuation">,</span> List<span class="token operator">&lt;</span>MappedProperty<span class="token operator">&gt;&gt;</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>

} IPropertyMappingContainer

namespace ApiStudy.Infrastructure.Services

{

public interface IPropertyMappingContainer

{

void Register() where T : IPropertyMapping, new();

IPropertyMapping Resolve();

bool ValidateMappingExistsFor(string fields);

}

} PropertyMappingContainer

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">&lt;</span>IPropertyMapping<span class="token operator">&gt;</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">&lt;</span><span class="token class-name">IPropertyMapping</span><span class="token punctuation">&gt;</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">&lt;</span><span class="token class-name">T</span><span class="token punctuation">&gt;</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">=&gt;</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">&lt;</span><span class="token class-name">TSource</span><span class="token punctuation">,</span><span class="token class-name">TDestination</span><span class="token punctuation">&gt;</span></span><span class="token punctuation">(</span><span class="token punctuation">)</span>
    <span class="token punctuation">{</span>
        IEnumerable<span class="token operator">&lt;</span>PropertyMapping<span class="token operator">&lt;</span>TSource<span class="token punctuation">,</span> TDestination<span class="token operator">&gt;&gt;</span> result <span class="token operator">=</span> PropertyMappings<span class="token punctuation">.</span>OfType<span class="token operator">&lt;</span>PropertyMapping<span class="token operator">&lt;</span>TSource<span class="token punctuation">,</span>TDestination<span class="token operator">&gt;&gt;</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">&gt;</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">&quot;Cannot find property mapping instance for {0}, {1}&quot;</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">&lt;</span><span class="token class-name">TSource</span><span class="token punctuation">,</span> <span class="token class-name">TDestination</span><span class="token punctuation">&gt;</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">&lt;</span><span class="token class-name">TSource</span><span class="token punctuation">,</span> <span class="token class-name">TDestination</span><span class="token punctuation">&gt;</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">&apos;,&apos;</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">&apos; &apos;</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">&lt;=</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">=&gt;</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>

} QueryExtensions

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">&lt;</span>T<span class="token operator">&gt;</span> <span class="token generic-method"><span class="token function">ApplySort</span><span class="token punctuation">&lt;</span><span class="token class-name">T</span><span class="token punctuation">&gt;</span></span><span class="token punctuation">(</span>
       <span class="token keyword">this</span> IQueryable<span class="token operator">&lt;</span>T<span class="token operator">&gt;</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">&apos;,&apos;</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">&apos; &apos;</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">&quot; desc&quot;</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">&gt;</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">=&gt;</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">&lt;</span>MappedProperty<span class="token operator">&gt;</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">&quot;key mapping for {propertyName} is missing&quot;</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">&quot;{mappedProperty.Name} {(desc ? &quot;</span><span class="token keyword">descending</span><span class="token string">&quot; : &quot;</span><span class="token keyword">ascending</span><span class="token string">&quot;)} &quot;</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>

} UserController 部分代码

[HttpGet(Name = "GetAllApiUsers")]

public async Task GetAllApiUsers(ApiUserParameters parameters)

{

if (!_propertyMappingContainer.ValidateMappingExistsFor(parameters.OrderBy))

return BadRequest("can't find fields for sorting.");

PaginatedList<span class="token operator">&lt;</span>ApiUser<span class="token operator">&gt;</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">&lt;</span>ApiUserResource<span class="token operator">&gt;</span> apiUserResources <span class="token operator">=</span>
    _mapper<span class="token punctuation">.</span>Map<span class="token operator">&lt;</span>IEnumerable<span class="token operator">&lt;</span>ApiUser<span class="token operator">&gt;</span><span class="token punctuation">,</span> IEnumerable<span class="token operator">&lt;</span>ApiUserResource<span class="token operator">&gt;&gt;</span><span class="token punctuation">(</span>apiUsers<span class="token punctuation">)</span><span class="token punctuation">;</span>

IEnumerable<span class="token operator">&lt;</span>ApiUserResource<span class="token operator">&gt;</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">&lt;</span><span class="token class-name">ApiUserResource</span><span class="token punctuation">,</span> <span class="token class-name">ApiUser</span><span class="token punctuation">&gt;</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">&quot;X-Pagination&quot;</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);

}

    <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">&lt;</span>PropertyInfo<span class="token operator">&gt;</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">&lt;</span>PropertyInfo<span class="token operator">&gt;</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">&lt;</span><span class="token class-name">PropertyInfo</span><span class="token punctuation">&gt;</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">&apos;,&apos;</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>

}

ApiStudy.Infrastructure.Extensions.ObjectExtensions

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">&lt;</span>PropertyInfo<span class="token operator">&gt;</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">&lt;</span><span class="token keyword">string</span><span class="token punctuation">,</span> <span class="token keyword">object</span><span class="token operator">&gt;</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">&lt;</span>PropertyInfo<span class="token operator">&gt;</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">&lt;</span><span class="token keyword">string</span><span class="token punctuation">,</span> <span class="token keyword">object</span><span class="token operator">&gt;</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>

} ApiStudy.Infrastructure.Extensions.IEnumerableExtensions

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">&lt;</span>ExpandoObject<span class="token operator">&gt;</span> <span class="token generic-method"><span class="token function">ToDynamicObject</span><span class="token punctuation">&lt;</span><span class="token class-name">T</span><span class="token punctuation">&gt;</span></span><span class="token punctuation">(</span>
        <span class="token keyword">this</span> IEnumerable<span class="token operator">&lt;</span>T<span class="token operator">&gt;</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">&lt;</span>ExpandoObject<span class="token operator">&gt;</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">&lt;</span><span class="token class-name">ExpandoObject</span><span class="token punctuation">&gt;</span></span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        List<span class="token operator">&lt;</span>PropertyInfo<span class="token operator">&gt;</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>

} ApiStudy.Infrastructure.Services.TypeHelperServices

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">&lt;</span><span class="token class-name">T</span><span class="token punctuation">&gt;</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">&apos;,&apos;</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>

} UserContext.GetAllApiUsers(), UserContext.Get()

[HttpGet(Name = "GetAllApiUsers")]

public async Task GetAllApiUsers(ApiUserParameters parameters)

{

//added code

if (!_typeHelper.HasProperties(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">&lt;</span><span class="token class-name">ApiUserResource</span><span class="token punctuation">,</span> <span class="token class-name">ApiUser</span><span class="token punctuation">&gt;</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">&quot;can&apos;t find fields for sorting.&quot;</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

PaginatedList<span class="token operator">&lt;</span>ApiUser<span class="token operator">&gt;</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">&lt;</span>ApiUserResource<span class="token operator">&gt;</span> apiUserResources <span class="token operator">=</span>
    _mapper<span class="token punctuation">.</span>Map<span class="token operator">&lt;</span>IEnumerable<span class="token operator">&lt;</span>ApiUser<span class="token operator">&gt;</span><span class="token punctuation">,</span> IEnumerable<span class="token operator">&lt;</span>ApiUserResource<span class="token operator">&gt;&gt;</span><span class="token punctuation">(</span>apiUsers<span class="token punctuation">)</span><span class="token punctuation">;</span>

IEnumerable<span class="token operator">&lt;</span>ApiUserResource<span class="token operator">&gt;</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">&lt;</span><span class="token class-name">ApiUserResource</span><span class="token punctuation">,</span> <span class="token class-name">ApiUser</span><span class="token punctuation">&gt;</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">&lt;</span>ExpandoObject<span class="token operator">&gt;</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">&quot;X-Pagination&quot;</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();

});

    <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">&lt;</span>LinkResource<span class="token operator">&gt;</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 linkResources = new List();

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">&quot;DeleteApiUser&quot;</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">&quot;self&quot;</span><span class="token punctuation">,</span> <span class="token string">&quot;Get&quot;</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 CreateLinksForApiUsers(ApiUserParameters parameters,bool hasPrevious,bool hasNext)

{

List resources = new List();

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">&quot;current_page&quot;</span><span class="token punctuation">,</span> <span class="token string">&quot;get&quot;</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">&quot;previous_page&quot;</span><span class="token punctuation">,</span> <span class="token string">&quot;get&quot;</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">&quot;next_page&quot;</span><span class="token punctuation">,</span> <span class="token string">&quot;get&quot;</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 GetAllApiUsers(ApiUserParameters parameters)

{

if (!_typeHelper.HasProperties(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">&lt;</span><span class="token class-name">ApiUserResource</span><span class="token punctuation">,</span> <span class="token class-name">ApiUser</span><span class="token punctuation">&gt;</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">&quot;can&apos;t find fields for sorting.&quot;</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

PaginatedList<span class="token operator">&lt;</span>ApiUser<span class="token operator">&gt;</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">&lt;</span>ApiUserResource<span class="token operator">&gt;</span> apiUserResources <span class="token operator">=</span>
    _mapper<span class="token punctuation">.</span>Map<span class="token operator">&lt;</span>IEnumerable<span class="token operator">&lt;</span>ApiUser<span class="token operator">&gt;</span><span class="token punctuation">,</span> IEnumerable<span class="token operator">&lt;</span>ApiUserResource<span class="token operator">&gt;&gt;</span><span class="token punctuation">(</span>apiUsers<span class="token punctuation">)</span><span class="token punctuation">;</span>

IEnumerable<span class="token operator">&lt;</span>ApiUserResource<span class="token operator">&gt;</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">&lt;</span><span class="token class-name">ApiUserResource</span><span class="token punctuation">,</span> <span class="token class-name">ApiUser</span><span class="token punctuation">&gt;</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">&lt;</span>ExpandoObject<span class="token operator">&gt;</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">&lt;</span>ExpandoObject<span class="token operator">&gt;</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">=&gt;</span>
    <span class="token punctuation">{</span>
        IDictionary<span class="token operator">&lt;</span><span class="token keyword">string</span><span class="token punctuation">,</span> <span class="token keyword">object</span><span class="token operator">&gt;</span> dict <span class="token operator">=</span> x <span class="token keyword">as</span> IDictionary<span class="token operator">&lt;</span><span class="token keyword">string</span><span class="token punctuation">,</span> <span class="token keyword">object</span><span class="token operator">&gt;</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">&quot;guid&quot;</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">&quot;links&quot;</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">&quot;guid&quot;</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">&quot;X-Pagination&quot;</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 = &quot;Accept&quot;)] 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().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 GetAllApiUsers(ApiUserParameters parameters,[FromHeader(Name = "Accept")] string mediaType)

{

if (!_typeHelper.HasProperties(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">&lt;</span><span class="token class-name">ApiUserResource</span><span class="token punctuation">,</span> <span class="token class-name">ApiUser</span><span class="token punctuation">&gt;</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">&quot;can&apos;t find fields for sorting.&quot;</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

PaginatedList<span class="token operator">&lt;</span>ApiUser<span class="token operator">&gt;</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">&lt;</span>ApiUserResource<span class="token operator">&gt;</span> apiUserResources <span class="token operator">=</span>
    _mapper<span class="token punctuation">.</span>Map<span class="token operator">&lt;</span>IEnumerable<span class="token operator">&lt;</span>ApiUser<span class="token operator">&gt;</span><span class="token punctuation">,</span> IEnumerable<span class="token operator">&lt;</span>ApiUserResource<span class="token operator">&gt;&gt;</span><span class="token punctuation">(</span>apiUsers<span class="token punctuation">)</span><span class="token punctuation">;</span>

IEnumerable<span class="token operator">&lt;</span>ApiUserResource<span class="token operator">&gt;</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">&lt;</span><span class="token class-name">ApiUserResource</span><span class="token punctuation">,</span> <span class="token class-name">ApiUser</span><span class="token punctuation">&gt;</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">&lt;</span>ExpandoObject<span class="token operator">&gt;</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">&quot;application/json&quot;</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">&quot;application/vnd.laggage.hateoas+json&quot;</span><span class="token punctuation">)</span>
<span class="token punctuation">{</span>
    IEnumerable<span class="token operator">&lt;</span>ExpandoObject<span class="token operator">&gt;</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">=&gt;</span>
        <span class="token punctuation">{</span>
            IDictionary<span class="token operator">&lt;</span><span class="token keyword">string</span><span class="token punctuation">,</span> <span class="token keyword">object</span><span class="token operator">&gt;</span> dict <span class="token operator">=</span> x <span class="token keyword">as</span> IDictionary<span class="token operator">&lt;</span><span class="token keyword">string</span><span class="token punctuation">,</span> <span class="token keyword">object</span><span class="token operator">&gt;</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">&quot;guid&quot;</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">&quot;links&quot;</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">=&gt;</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">&quot;guid&quot;</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">&quot;X-Pagination&quot;</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">&quot;Can&apos;t find resources for the given media type: [{mediaType}].&quot;</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

}

[HttpGet("{guid}",Name = "GetApiUser")]

public async Task Get(string guid, [FromHeader(Name = "Accept")] string mediaType , string fields = null)

{

if (!_typeHelper.HasProperties(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">&lt;</span><span class="token class-name">ApiUser</span><span class="token punctuation">,</span> <span class="token class-name">ApiUserResource</span><span class="token punctuation">&gt;</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">&quot;application/json&quot;</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">&quot;application/vnd.laggage.hateoas+json&quot;</span><span class="token punctuation">)</span>
<span class="token punctuation">{</span>

IDictionary<span class="token operator">&lt;</span><span class="token keyword">string</span><span class="token punctuation">,</span> <span class="token keyword">object</span><span class="token operator">&gt;</span> shapedApiUserResourceWithLink <span class="token operator">=</span> shapedApiUserResource <span class="token keyword">as</span> IDictionary<span class="token operator">&lt;</span><span class="token keyword">string</span><span class="token punctuation">,</span> <span class="token keyword">object</span><span class="token operator">&gt;</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">&quot;links&quot;</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">@&quot;Can&apos;t find resource for the given media type: [{mediaType}].&quot;</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 GetHateoas(ApiUserParameters parameters)

{

if (!_typeHelper.HasProperties(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">&lt;</span><span class="token class-name">ApiUserResource</span><span class="token punctuation">,</span> <span class="token class-name">ApiUser</span><span class="token punctuation">&gt;</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">&quot;can&apos;t find fields for sorting.&quot;</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

PaginatedList<span class="token operator">&lt;</span>ApiUser<span class="token operator">&gt;</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">&lt;</span>ApiUserResource<span class="token operator">&gt;</span> apiUserResources <span class="token operator">=</span>
    _mapper<span class="token punctuation">.</span>Map<span class="token operator">&lt;</span>IEnumerable<span class="token operator">&lt;</span>ApiUser<span class="token operator">&gt;</span><span class="token punctuation">,</span> IEnumerable<span class="token operator">&lt;</span>ApiUserResource<span class="token operator">&gt;&gt;</span><span class="token punctuation">(</span>apiUsers<span class="token punctuation">)</span><span class="token punctuation">;</span>

IEnumerable<span class="token operator">&lt;</span>ApiUserResource<span class="token operator">&gt;</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">&lt;</span><span class="token class-name">ApiUserResource</span><span class="token punctuation">,</span> <span class="token class-name">ApiUser</span><span class="token punctuation">&gt;</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">&lt;</span>ExpandoObject<span class="token operator">&gt;</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">&lt;</span>ExpandoObject<span class="token operator">&gt;</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">=&gt;</span>
        <span class="token punctuation">{</span>
            IDictionary<span class="token operator">&lt;</span><span class="token keyword">string</span><span class="token punctuation">,</span> <span class="token keyword">object</span><span class="token operator">&gt;</span> dict <span class="token operator">=</span> x <span class="token keyword">as</span> IDictionary<span class="token operator">&lt;</span><span class="token keyword">string</span><span class="token punctuation">,</span> <span class="token keyword">object</span><span class="token operator">&gt;</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">&quot;guid&quot;</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">&quot;links&quot;</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">=&gt;</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">&quot;guid&quot;</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">&quot;X-Pagination&quot;</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 Get(ApiUserParameters parameters)

{

if (!_typeHelper.HasProperties(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">&lt;</span><span class="token class-name">ApiUserResource</span><span class="token punctuation">,</span> <span class="token class-name">ApiUser</span><span class="token punctuation">&gt;</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">&quot;can&apos;t find fields for sorting.&quot;</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

PaginatedList<span class="token operator">&lt;</span>ApiUser<span class="token operator">&gt;</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">&lt;</span>ApiUserResource<span class="token operator">&gt;</span> apiUserResources <span class="token operator">=</span>
    _mapper<span class="token punctuation">.</span>Map<span class="token operator">&lt;</span>IEnumerable<span class="token operator">&lt;</span>ApiUser<span class="token operator">&gt;</span><span class="token punctuation">,</span> IEnumerable<span class="token operator">&lt;</span>ApiUserResource<span class="token operator">&gt;&gt;</span><span class="token punctuation">(</span>apiUsers<span class="token punctuation">)</span><span class="token punctuation">;</span>

IEnumerable<span class="token operator">&lt;</span>ApiUserResource<span class="token operator">&gt;</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">&lt;</span><span class="token class-name">ApiUserResource</span><span class="token punctuation">,</span> <span class="token class-name">ApiUser</span><span class="token punctuation">&gt;</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">&lt;</span>ExpandoObject<span class="token operator">&gt;</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 GetHateoas(string guid, string fields = null)

{

if (!_typeHelper.HasProperties(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">&lt;</span><span class="token class-name">ApiUser</span><span class="token punctuation">,</span> <span class="token class-name">ApiUserResource</span><span class="token punctuation">&gt;</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">&lt;</span><span class="token keyword">string</span><span class="token punctuation">,</span> <span class="token keyword">object</span><span class="token operator">&gt;</span> shapedApiUserResourceWithLink <span class="token operator">=</span> shapedApiUserResource <span class="token keyword">as</span> IDictionary<span class="token operator">&lt;</span><span class="token keyword">string</span><span class="token punctuation">,</span> <span class="token keyword">object</span><span class="token operator">&gt;</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">&quot;links&quot;</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 Get(string guid, string fields = null)

{

if (!_typeHelper.HasProperties(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">&lt;</span><span class="token class-name">ApiUser</span><span class="token punctuation">,</span> <span class="token class-name">ApiUserResource</span><span class="token punctuation">&gt;</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>

}

    <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, ApiUserAddResourceValidator>();

ApiStudy.Infrastructure.Resources.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">&lt;</span>ApiUserAddResource<span class="token operator">&gt;</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">=&gt;</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">&quot;用户名&quot;</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">&quot;{PropertyName}的最大长度为20!&quot;</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">&quot;{PropertyName}是必填的!&quot;</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">&quot;{PropertyName}不能为空!&quot;</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">=&gt;</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">&quot;密码&quot;</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">&quot;{PropertyName}是必填的!&quot;</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">&quot;{PropertyName}的最小长度是6&quot;</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">&quot;{PropertyName}的最大长度是16&quot;</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">=&gt;</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">&quot;电话&quot;</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">&quot;{PropertyName}是必填的!&quot;</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">&quot;{PropertyName}不能为空!&quot;</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
<span class="token punctuation">}</span>

} UserContext.AddApiUser()

[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 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">&lt;</span><span class="token class-name">ApiUser</span><span class="token punctuation">&gt;</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">&quot;www.eample.com/photo/{newUser.Guid}&quot;</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">&quot;Failed to save changes&quot;</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

IDictionary<span class="token operator">&lt;</span><span class="token keyword">string</span><span class="token punctuation">,</span> <span class="token keyword">object</span><span class="token operator">&gt;</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">&lt;</span><span class="token class-name">ApiUserResource</span><span class="token punctuation">&gt;</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">&lt;</span><span class="token keyword">string</span><span class="token punctuation">,</span> <span class="token keyword">object</span><span class="token operator">&gt;</span><span class="token punctuation">;</span>
IEnumerable<span class="token operator">&lt;</span>LinkResource<span class="token operator">&gt;</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">&quot;links&quot;</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">&quot;GetApiUser&quot;</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>

}

    <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">&quot;{guid}&quot;</span><span class="token punctuation">,</span>Name <span class="token operator">=</span> <span class="token string">&quot;DeleteApiUser&quot;</span><span class="token punctuation">)</span><span class="token punctuation">]</span>

public async Task 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">&quot;Failed to delete apiUser&quot;</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>

}

    <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>

}

ApiStudy.Infrastructure.Resources.ApiUserAddResource

namespace ApiStudy.Infrastructure.Resources

{

public class ApiUserAddResource:ApiUserAddOrUpdateResource

{

}

} ApiStudy.Infrastructure.Resources.ApiUserUpdateResource

namespace ApiStudy.Infrastructure.Resources

{

public class ApiUserUpdateResource : ApiUserAddOrUpdateResource

{

}

} ApiStudy.Infrastructure.Resources.ApiUserAddOrUpdateResourceValidator

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">&lt;</span>T<span class="token operator">&gt;</span> <span class="token punctuation">:</span> AbstractValidator<span class="token operator">&lt;</span>T<span class="token operator">&gt;</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">=&gt;</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">&quot;用户名&quot;</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">&quot;{PropertyName}的最大长度为20!&quot;</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">&quot;{PropertyName}是必填的!&quot;</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">&quot;{PropertyName}不能为空!&quot;</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">=&gt;</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">&quot;密码&quot;</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">&quot;{PropertyName}是必填的!&quot;</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">&quot;{PropertyName}的最小长度是6&quot;</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">&quot;{PropertyName}的最大长度是16&quot;</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">=&gt;</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">&quot;电话&quot;</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">&quot;{PropertyName}是必填的!&quot;</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">&quot;{PropertyName}不能为空!&quot;</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">&quot;{guid}&quot;</span><span class="token punctuation">,</span>Name <span class="token operator">=</span> <span class="token string">&quot;PutApiUser&quot;</span><span class="token punctuation">)</span><span class="token punctuation">]</span>

public async Task 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">&quot;Failed to update Entity of ApiUser&quot;</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”: &quot;add&quot;, &quot;path&quot;:
                    &quot;/xxx&quot;, &quot;value&quot;:
                    &quot;xxx&quot;},如果该属性不存,那么就添加该属性,如<br>
                    果属性存在,就改变属性的值。这个对静态类型不适用。
                </li>
                <li>删除:{“op”: &quot;<strong>remove</strong>&quot;,
                    &quot;path&quot;:
                    &quot;/xxx&quot;},删除某个属性,或把它设为默认值(例如空值)。
                </li>
                <li>替换:{“op”: &quot;<strong>replace</strong>&quot;,
                    &quot;path&quot;: &quot;/xxx&quot;, &quot;value&quot;:
                    &quot;xxx&quot;},改变属性的值,也可以理解为先执行<br>
                    了删除,然后进行添加。</li>
                <li>复制:{“op”: &quot;copy&quot;, &quot;from&quot;:
                    &quot;/xxx&quot;, &quot;path&quot;:
                    &quot;/yyy&quot;},把某个属性的值赋给目标属性。
                </li>
                <li>移动:{“op”: &quot;move&quot;, &quot;from&quot;:
                    &quot;/xxx&quot;, &quot;path&quot;:
                    &quot;/yyy&quot;},把源属性的值赋值给目标属性,并把源<br>
                    属性删除或设成默认值。</li>
                <li>测试:{“op”: &quot;test&quot;, &quot;path&quot;:
                    &quot;/xxx&quot;, &quot;value&quot;:
                    &quot;xxx&quot;},测试目标属性的值和指定的值是一样的。
                </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">&quot;op&quot;</span><span class="token operator">:</span><span class="token string">&quot;replace&quot;</span><span class="token punctuation">,</span>
    <span class="token property">&quot;path&quot;</span><span class="token operator">:</span><span class="token string">&quot;/name&quot;</span><span class="token punctuation">,</span>
    <span class="token property">&quot;value&quot;</span><span class="token operator">:</span><span class="token string">&quot;阿黄&quot;</span>
<span class="token punctuation">}</span><span class="token punctuation">,</span>
<span class="token punctuation">{</span>
    <span class="token property">&quot;op&quot;</span><span class="token operator">:</span><span class="token string">&quot;remove&quot;</span><span class="token punctuation">,</span>
    <span class="token property">&quot;path&quot;</span><span class="token operator">:</span><span class="token string">&quot;/email&quot;</span>
<span class="token punctuation">}</span>

]

ApiStudy.Api.Controllers.UserContext.UpdateApiUser

[HttpPatch("{guid}",Name = "PatchApiUser")]

[RequestHeaderMatchingMediaType("Content-Type",new string[] { "application/vnd.laggage.patch.apiuser+json" })]

public async Task UpdateApiUser(

string guid,[FromBody] JsonPatchDocument 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">&lt;</span><span class="token class-name">ApiUserUpdateResource</span><span class="token punctuation">&gt;</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">&quot;Failed to update Entity of ApiUser&quot;</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>

}

    <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>