使用ASP.NET Core和Ion构建优雅的REST API

使用ASP.NET Core和Ion构建优雅的REST API

BeautifulRestApiBeautiful REST API design with ASP.NET Core and Ion项目地址:https://gitcode.com/gh_mirrors/be/BeautifulRestApi

你好!在这个仓库中,我们提供了一个用C#和ASP.NET Core 1.1编写的示例API。它利用Ion超媒体规范作为起点,设计出一个一致且简洁的REST API,完全拥抱了HATEOAS原则。

这个例子在我的演讲《使用ASP.NET Core构建美观的RESTful API》中被用到(查看链接以获取幻灯片)。

深入学习视频课程

想要深入探讨REST、HATEOAS、Ion、ASP.NET Core以及更多相关知识,可以查看我在LinkedIn Learning上的课程在ASP.NET Core中构建和保护RESTful API。如果你没有LinkedIn Learning或Lynda的订阅,可以通过电子邮件联系我,我会为你提供优惠券!

如何试用

  1. 克隆此仓库。
  2. 使用Visual Studio或命令行(使用dotnet build)构建解决方案。
  3. 运行项目。API将在http://localhost:50647或http://localhost:5000(使用dotnet run)启动。
  4. 使用HTTP客户端如Postman或Fiddler进行测试,发送GET http://localhost:50647请求。
  5. 尽享HATEOAS。
  6. 获得收益!:moneybag:

建立RESTful API在ASP.NET Core中的技巧

这个示例包含许多我在ASP.NET Core上构建API时学到的技巧。如果有关于改进的建议,请告诉我!

在内存中使用Entity Framework Core实现快速原型

借助Entity Framework Core的内存提供者,你可以快速地进行原型设计而不必关心数据库设置。你可以建立并测试一个快速的内存存储,并在准备就绪时切换到实际的数据库。

安装Microsoft.EntityFrameworkCore.InMemory包后,创建一个DbContext

public class ApiDbContext : DbContext
{
    public ApiDbContext(DbContextOptions<ApiDbContext> options)
        : base(options)
    {
    }

    // DbSet...
}

与其他“正常”的DbContext唯一的区别是在构造函数中添加了接受DbContextOptions<>参数的需求。这是内存提供者所要求的。

然后,在Startup.ConfigureServices中配置内存提供者:

services.AddDbContext<ApiDbContext>(options =>
{
    // 使用随机数据库名的内存数据库进行测试
    options.UseInMemoryDatabase(Guid.NewGuid().ToString());
});

应用启动时,数据库将为空。为了使原型设计和测试更容易,你可以在Startup.cs中添加测试数据:

// 在Configure()中
var dbContext = app.ApplicationServices.GetRequiredService<ApiDbContext>();
AddTestData(dbContext);

private static void AddTestData(ApiDbContext context)
{
    context.Conversations.Add(new Models.ConversationEntity
    {
        Id = Guid.Parse("6f1e369b-29ce-4d43-b027-3756f03899a1"),
        CreatedAt = DateTimeOffset.UtcNow,
        Title = "谁是最酷的复仇者?"
    });

    // 别忘了保存更改!
    context.SaveChanges();
}

通过Ion模型化链接、资源和集合

Ion为JSON中的REST对象提供了简单框架。这些Ion对象可以用C#的POCO来表示。这是一个Link对象的例子:

public class Link
{
    public string Href { get; set; }

    // 由于ASP.NET Core默认使用JSON.NET,因此可以通过JSON.NET属性调整序列化
    [JsonProperty(NullValueHandling = NullValueHandling.Ignore, DefaultValueHandling = DefaultValueHandling.Ignore)]
    [DefaultValue(GetMethod)]
    public string Method { get; set; }

    [JsonProperty(PropertyName = "rel", NullValueHandling = NullValueHandling.Ignore)]
    public string[] Relations { get; set; }
}

资源和集合的建模同样简便:

// 资源也是(自引用)链接
public abstract class Resource : Link
{
    // 在响应管道中通过LinkRewritingFilter重写
    [JsonIgnore]
    public Link Self { get; set; }
}

// 集合也是资源
public class Collection<T> : Resource
{
    public const string CollectionRelation = "collection";

    public T[] Value { get; set; }
}

这些基类使得从API返回响应变得非常简洁。

基础API控制器与路由

ASP.NET Core中的API控制器继承自Controller类,并使用属性定义路由。常见的模式是将控制器命名为<RouteName>Controller,并将/[controller]作为属性值,这样会自动根据控制器名称命名路由:

// 处理所有在/comments下的路由
[Route("/[controller]")]
public class CommentsController : Controller
{
    // 方法...
}

控制器的方法处理特定的HTTP动词和子路由。返回IActionResult使您可以灵活地返回HTTP状态码和对象负载:

// 处理路由:
// GET /comments
[HttpGet]
public async Task<IActionResult> GetCommentsAsync(CancellationToken ct)
{
    return NotFound(); // 404
    
    return Ok(data); // 200带有JSON负载
}

// 处理路由:
// GET /comments/{commentId}
// 并将{commentId}绑定到方法签名中的参数
[HttpGet("{commentId}"]
public async Task<IActionResult> GetCommentByIdAsync(Guid commentId, CancellationToken ct)
{
    // ...
}

命名路由模式

如果你需要稍后在代码中引用特定的路由,你可以使用Name属性在路由属性中提供唯一名称。我喜欢使用nameof以方法自身相同的描述性名称来命名路由:

[HttpGet(Name = nameof(GetCommentsAsync))]
public async Task<IActionResult> GetCommentsAsync(CancellationToken ct)
{
    // ...
}

这样,编译器会确保路由名称总是正确的。

异步/等待最佳实践

ASP.NET Core在堆栈全过程中支持异步/等待。任何进行网络或数据库调用的控制器和服务都应该async。Entity Framework Core提供了像SingleAsyncToListAsync这样的异步数据库方法。

向路由方法添加CancellationToken参数允许ASP.NET Core通知你的异步任务取消(例如,如果浏览器关闭了连接)。

保持控制器精简

我喜欢尽可能让控制器保持简洁,只关注以下方面:

  1. 验证模型绑定(或者不验证,见下文!)
  2. 检查null值,尽早返回
  3. 协调对服务的请求
  4. 返回友好的结果

避免业务逻辑!保持控制器的精简使其更易于测试和维护。精简的控制器也更适合更复杂的模式,如CQRS或Mediator。

通过ActionFilter验证模型绑定

大多数路由都需要在继续之前验证输入值是否有效。这可以通过一行代码完成:

if (!ModelState.IsValid) return BadRequest(ModelState);

而不是在每个路由方法的开头都有这行代码,你可以把它作为一个属性提取到ActionFilter中:

[HttpGet(Name = nameof(GetCommentsAsync))]
[ValidateModel]
public async Task<IActionResult> GetCommentsAsync(...)

ModelState字典包含了描述错误的消息(特别是当模型用到了验证属性)。你可以把所有的错误返回给用户,也可以遍历字典来取出第一条错误:

var firstErrorIfAny = modelState
    .FirstOrDefault(x => x.Value.Errors.Any())
    .Value?.Errors?.FirstOrDefault()?.ErrorMessage

提供根路由

除非API有一个清晰的入口点,否则它不是HATEOAS。根文档可以定义为一组链接的简单资源:

public class RootResource : Resource
{
    public Link Conversations { get; set; }

    public Link Comments { get; set; }
}

并且可以被很容易地返回:

// 省略实现

这就是为什么你应该考虑使用这个开源项目。它不仅提供了实用的代码示例,还涵盖了REST API设计的最佳实践。无论你是新手还是经验丰富的开发者,这个项目都会让你的API设计更加高效、易于理解和扩展。

BeautifulRestApiBeautiful REST API design with ASP.NET Core and Ion项目地址:https://gitcode.com/gh_mirrors/be/BeautifulRestApi

  • 7
    点赞
  • 30
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

任澄翊

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值