在Mac下创建ASP.NET Core Web API

这系列文章是参考了.NET Core文档和源码,可能有人要问,直接看官方的英文文档不就可以了吗,为什么还要写这些文章呢?

原因如下:

  • 官方文档涉及的内容相当全面,属于那种大而全的知识仓库,不太适合初学者,很容易让人失去重要,让人掉入到具体的细节之中。
  • 对于大多数人来讲开发语言只是工具,程序员都有一个通病,就是死磕工具,把工具学深。我认为在工具上没有必要投入太多时间,以能高效地完成日常的工作项目为准即可。要需求驱动学习,你需要什么学什么。如果你学的新技术新特性只是屠龙之技或者只需要用到的时候去查一下即可的话,这种死磕这又有什么用。没有必要花120%的时间去学100%的知识,你只需要花20%的时间去学习80%的知识就可以了,剩下的等实际的项目中用到的时候去查就可以了,工具只是工具,不是工作本身。
  • 目前基本所有的文章都是基于Windows平台的Visual Studio IDE来介绍的。而我用的是一台Mac,所以我将基于Mac平台的Visual Studio Code讲解适合我们实际项目中遇到的知识。
  • 还有一点,就是这是我个人的学习总结。

这系列文章就是让你去花20%的时间去学80%的东西,剩下的20%再去看官方文档。

在.NET Core里面MVC和WebAPI两者被整合成一个框架,分享同一套代码和管线。这样我们就可以更方便地开发MVC应用程序和Web API接口。

创建项目

在这篇文章中我们将要创建的API如下:

API 描述
GET /api/user 获取所有的用户信息
GET /api/user/{id} 根据ID获取指定的用户
POST /api/user 添加新的用户
PUT /api/user/{id} 更新用户信息
PATCH /api/user/{id} 更新用户信息
DELETE /api/user/{id} 删除用户信息

根据上一篇文章,我们通过Yeoman创建一个WebAPI项目,命名为UserWebAPI:

添加模型类

然后在项目根目录下面新建一个Models文件夹,在该文件夹下面利用yo aspnet:class UserItem新建一个UserItem类。

namespace UserWebAPI.Models
{
public class UserItem
{
public string Key { get; set; }
public string Name { get; set; }
public int Age { get; set; }
}
}

添加仓储类

Repository类是封装了数据层的对象,包含了获取数据、并映射到实体模型类的业务逻辑。

首先我们在Models文件夹下面定义一个IUserRepositoryrepository接口。

通过运行yo aspnet:interface IUserRepository命令来创建该接口。

namespace UserWebAPI.Models
{
public interface IUserRepository
{
void Add(UserItem item);
IEnumerable<UserItem> GetAll();
UserItem Find(string key);
UserItem Remove(string key);
void Update(UserItem item);
}
}

接着再添加一个UserRepository类来实现IUserRepository接口。

namespace UserWebAPI.Models
{
public class UserRepository : IUserRepository
{
private static ConcurrentDictionary<string, UserItem> _users
= new ConcurrentDictionary<string, UserItem>(); public UserRepository()
{
Add(new UserItem { Name = "Charlie", Age = 18 });
} public void Add(UserItem item)
{
item.Key = Guid.NewGuid().ToString();
_users[item.Key] = item;
} public UserItem Find(string key)
{
UserItem user;
_users.TryGetValue(key, out user);
return user;
} public IEnumerable<UserItem> GetAll()
{
return _users.Values;
} public UserItem Remove(string key)
{
UserItem user;
_users.TryRemove(key, out user);
return user;
} public void Update(UserItem item)
{
_users[item.Key] = item;
}
}
}

注册仓储

通过定义一个repository接口,我们从使用它的MVC Controller来解耦该repository类。我们在此将通过注入一个UserRepository来代替直接在Controller里面实例化一个UserRepository类。

为了注入一个repository到controller,我们必须通过DI容器来注册它,打开Startup.cs文件,在ConfigureServices方法添加如下代码:

添加控制器

控制器是用于处理HTTP请求并创建HTTP响应的对象,这里通过运行yo aspnet:webapicontroller UserController命令生成UserController控制器。

namespace UserWebAPI.Controllers
{
[Route("api/[controller]")]
public class UserController : Controller
{
public IUserRepository UserItems { get; set; } public UserController(IUserRepository userItems)
{
UserItems = userItems;
}
}
}

获取用户信息

[HttpGet]
public IEnumerable<UserItem> GetAll()
{
return UserItems.GetAll();
} [HttpGet("{id}", Name = "GetUser")]
public IActionResult GetById(string id)
{
var item = UserItems.Find(id);
if (item == null)
{
return NotFound();
}
return new ObjectResult(item);
}

上述两个方法实现了两个GET方法:

  • GET /api/user
  • GET /api/user/{id}

运行dotnet restoredotnet run之后,应用程序将会在本机启动,并在http://localhost:5000上开启监听服务。

然后在Postman上测试你的API接口是否能正确运行。

GetById方法中:

[HttpGet("{id}", Name = "GetTodo")]
public IActionResult GetById(string id)

其中"{id}"是UserItem的ID占位符,当GetById被调用时,URL中的“{id}”值会被分配给该方法的id参数。

Name = "GetTodo"创建了一个命名的路由,并允许你在HTTP响应中链接到该路由。

GetAll方法返回了一个IEnumerable,MVC会自动将对象序列化成JSON并将JSON写入到响应消息的正文中。该方法的响应状态码为200,假设没有发生任何未处理异常。

GetById方法返回的是一个更为通用的IActionResult类型。该方法有两种不同的返回类型:

  • 如果没有项匹配指定的请求ID,该方法通过返回NotFound表示一个404错误。
  • 否则,该方法返回一个JSON响应正文和200响应码,通过返回ObjectResult来表示。

添加新用户

[HttpPost]
public IActionResult Create([FromBody]UserItem item)
{
if (item == null)
{
return BadRequest();
}
UserItems.Add(item);
return CreatedAtRoute("GetUser", new { id = item.Key }, item);
}

通过[HttpPost] attribute 标明这个一个HTTP POST方法,[FromBody] attribute 告诉MVC从HTTP 请求的正文中获取用户UserItem值。

CreatedAtRoute方法返回一个201响应状态码(实际上是CreatedAtRouteResult对象),201状态码是通过POST方法在服务器上成功创建了一个新的资源时的标准响应码。CreateAtRoute也在响应里面添加了一个Location头信息,这个头信息指定了最新创建的User URI。

/// <summary>
/// Creates a <see cref="CreatedAtRouteResult"/> object that produces a Created (201) response.
/// </summary>
/// <param name="routeName">The name of the route to use for generating the URL.</param>
/// <param name="routeValues">The route data to use for generating the URL.</param>
/// <param name="value">The content value to format in the entity body.</param>
/// <returns>The created <see cref="CreatedAtRouteResult"/> for the response.</returns>
[NonAction]
public virtual CreatedAtRouteResult CreatedAtRoute(string routeName, object routeValues,
object value)
{
return new CreatedAtRouteResult(routeName, routeValues, value);
}
/// <summary>
/// Initializes a new instance of the <see cref="CreatedAtRouteResult"/> class with the values
/// provided.
/// </summary>
/// <param name="routeName">The name of the route to use for generating the URL.</param>
/// <param name="routeValues">The route data to use for generating the URL.</param>
/// <param name="value">The value to format in the entity body.</param>
public CreatedAtRouteResult(string routeName, object routeValues, object value)
: base(value)
{
RouteName = routeName;
RouteValues = routeValues == null ? null : new RouteValueDictionary(routeValues);
StatusCode = StatusCodes.Status201Created;
}

通过查看CreatedAtRouteResult的构造函数可以看到StatusCode(从ObjectResult对象继承而来)被直接设置成了Status201Created枚举值。

201状态码是当你在用POST/PUT在服务器端成功创建了一个新的资源时,服务器就应当返回201 Created同时在响应头添加一个Location来指定刚刚创建好的资源的URI。

通过Postman来发送Create请求

刚服务器接收到请求,会在VS Code的控制台显示出相应的信息:

点击Headers tab可以看到Location的值显示刚刚创建好的资源的URI。

更新用户信息(HTTP PUT)

[HttpPut("{id}")]
public IActionResult Update(string id, [FromBody] UserItem item)
{
if (item == null || item.Key != id)
{
return BadRequest();
}
var user=UserItems.Find(id);
if(user==null)
{
return NotFound();
} UserItems.Update(item);
return new NoContentResult();
}

采用了HTTP PUT标记Update方法,并且响应状态码设置为204(No Content)。根据HTTP规范,PUT请求要求客户端发送整个被更新实体,而不是增量更新部分。如果要支持局部更新,则需要使用HTTP PATCH。

204(No Content)状态码表示服务器已经成功处理了你的请求,但不需要返回具体的数据。浏览器不用刷新页面,也不用重定向到新的页面,会保留发送了该请求的页面,不产生任何文档视图上的变化,只停留在当前页面。由于204响应被禁止包含任何消息体,因此它始终以消息头后的第一个空行结尾。对提交到服务器进行处理的数据,如果只需要返回是否成功的话,可考虑使用状态码204来作为返回信息,从而减少多余的数据传输。

NoContentResult类在构造函数中调用了父类的构造函数并把Status204NoContent传给了该类。

namespace Microsoft.AspNetCore.Mvc
{
public class NoContentResult : StatusCodeResult
{
public NoContentResult()
: base(StatusCodes.Status204NoContent)
{
}
}
}

更新用户信息(HTTP PATCH)

[HttpPatch("{id}")]
public IActionResult Update([FromBody] UserItem item, string id)
{
if (item == null)
{
return BadRequest();
} var user = UserItems.Find(id);
if (user == null)
{
return NotFound();
}
item.Key = user.Key; UserItems.Update(item);
return new NoContentResult();
}

删除用户

[HttpDelete("{id}")]
public IActionResult Delete(string id)
{
var user = UserItems.Find(id);
if (user == null)
{
return NotFound();
}
UserItems.Remove(id);
return new NoContentResult();
}

这个响应状态码同样是204(No Content)

个人博客

我的个人博客

在Mac下创建ASP.NET Core Web API的更多相关文章

  1. C#实现多级子目录Zip压缩解压实例 NET4.6下的UTC时间转换 [译]ASP.NET Core Web API 中使用Oracle数据库和Dapper看这篇就够了 asp.Net Core免费开源分布式异常日志收集框架Exceptionless安装配置以及简单使用图文教程 asp.net core异步进行新增操作并且需要判断某些字段是否重复的三种解决方案 .NET Core开发日志

    C#实现多级子目录Zip压缩解压实例 参考 https://blog.csdn.net/lki_suidongdong/article/details/20942977 重点: 实现多级子目录的压缩, ...

  2. ASP.NET Core 实战:使用 ASP.NET Core Web API 和 Vue.js 搭建前后端分离项目

    一.前言 这几年前端的发展速度就像坐上了火箭,各种的框架一个接一个的出现,需要学习的东西越来越多,分工也越来越细,作为一个 .NET Web 程序猿,多了解了解行业的发展,让自己扩展出新的技能树,对自 ...

  3. [译]ASP.NET Core Web API 中使用Oracle数据库和Dapper看这篇就够了

    [译]ASP.NET Core Web API 中使用Oracle数据库和Dapper看这篇就够了 本文首发自:博客园 文章地址: https://www.cnblogs.com/yilezhu/p/ ...

  4. List多个字段标识过滤 IIS发布.net core mvc web站点 ASP.NET Core 实战:构建带有版本控制的 API 接口 ASP.NET Core 实战:使用 ASP.NET Core Web API 和 Vue.js 搭建前后端分离项目 Using AutoFac

    List多个字段标识过滤 class Program{  public static void Main(string[] args) { List<T> list = new List& ...

  5. 在 ASP.NET Core Web API中使用 Polly 构建弹性容错的微服务

    在 ASP.NET Core Web API中使用 Polly 构建弹性容错的微服务 https://procodeguide.com/programming/polly-in-aspnet-core ...

  6. ASP.NET Core Web API 跨域(CORS) Cookie问题

    身为一个Web API,处理来自跨域不同源的请求,是一件十分合理的事情. 先上已有的文章,快速复制粘贴,启用CORS: Microsoft:启用 ASP.NET Core 中的跨域请求 (CORS) ...

  7. 在Mac下运行ASP.NET Core应用程序

    在Mac下运行ASP.NET Core应用程序 通过参照.NET Core相关官方文档,在我的Mac电脑上用Visual Studio Code创建了我的第一个ASP.NET应用. 开发环境搭建 首先 ...

  8. Mac下运行ASP.NET Core应用程序

    Mac下运行ASP.NET Core应用程序 在Mac下运行ASP.NET Core应用程序 通过参照.NET Core相关官方文档,在我的Mac电脑上用Visual Studio Code创建了我的 ...

  9. ASP.NET Core Web API下事件驱动型架构的实现(一):一个简单的实现

    很长一段时间以来,我都在思考如何在ASP.NET Core的框架下,实现一套完整的事件驱动型架构.这个问题看上去有点大,其实主要目标是为了实现一个基于ASP.NET Core的微服务,它能够非常简单地 ...

随机推荐

  1. CSS基础篇之选择符3

    border(边框) 如何用CSS调出边框 我们给p标签加一个边框试一下 p{ border:1px solid #ccc:/*这是缩写*/ } 第一个值是为边框的宽度 第二个值是为边框线样式为直线 ...

  2. Android课程---关于数据存储的学习之总结

  3. SDOI 2016 游戏

    树链剖分 线段树维护区间最小值,区间最大值 更新,对于每一个区间,找到当前区间的最小值的最大值,和要更新的值比较,如果比最大值还大,则此数对于以后的询问无任何贡献,直接返回即可,若有贡献,则一直递归到 ...

  4. 小知识 安卓线程和ui

    *:first-child { margin-top: 0 !important; } body>*:last-child { margin-bottom: 0 !important; } /* ...

  5. 剑指Offer面试题:29.丑数

    一.题目:丑数 题目:我们把只包含因子2.3和5的数称作丑数(Ugly Number).求按从小到大的顺序的第1500个丑数.例如6.8都是丑数,但14不是,因为它包含因子7.习惯上我们把1当做第一个 ...

  6. C++的性能C#的产能?! - .Net Native 系列《二》:.NET Native开发流程详解

    之前一文<c++的性能, c#的产能?!鱼和熊掌可以兼得,.NET NATIVE初窥> 获得很多朋友支持和鼓励,也更让我坚定做这项技术的推广者,希望能让更多的朋友了解这项技术,于是先从官方 ...

  7. WPF +MVVM(Caliburn.Micro)项目框架

    最近做了一个软件,这个软件不是网站,但是与HTML,AJAX等技术密切相关,也不是只有单纯的数据库增删改查,还涉及到线程协调,比较复杂的文本处理…… 这样的软件,用OA,ERP的框架显然是不合适的,因 ...

  8. Chrome插件整理

    本文内容都来源于偶整理的fetool. 想让更多使用Chrome的小伙伴,体验到这些令人愉悦的小工具,所以单独整理了这篇文章. 如果你是 前端/服务端/设计/面向Github编程/视觉控,相信下列的插 ...

  9. [New Portal]Windows Azure Storage (14) 使用Azure Blob的PutBlock方法,实现文件的分块、离线上传

    <Windows Azure Platform 系列文章目录> 相关内容 Windows Azure Platform (二十二) Windows Azure Storage Servic ...

  10. [SDK2.2]SQL Azure (13) Azure的两种关系型数据库服务:SQL Azure与SQL Server VM的不同

    <Windows Azure Platform 系列文章目录> 如果熟悉Windows Azure平台的用户不难发现,对于SQL Server数据库来说,微软提供了两种服务,分别是: -W ...