.net core实践系列之短信服务-Sikiro.SMS.Api服务的实现(一)

本文涉及的产品
数字短信套餐包(仅限零售电商行业),100条 12个月
短信服务,100条 3个月
短信服务,200条 3个月
简介: .net core实践系列之短信服务-Sikiro.SMS.Api服务的实现(一)

前言


上篇《.net core实践系列之短信服务-架构设计》介绍了我对短信服务的架构设计,同时针对场景解析了我的设计理念。本篇继续讲解Api服务的实现过程。


源码地址:https://github.com/SkyChenSky/Sikiro.SMS


此服务会使用.NET Core WebApi进行搭建,.NET Core WebApi基础原型就是RESTful风格,然而什么叫RESTful呢。


REST API简介


REST


Representational State Transfer的缩写,翻译为“表现层状态转化”,是由Roy Thomas Fieding在他的博士论文《Architectural Styles and the Design of Network-based Software Architectures》中提出的一种架构思想。


而他的论文中提出了一个RESTful应用应该具备的几点约束。


  • 每个资源都应该有一个唯一的标识
  • 每一个对象或资源都可以通过一个唯一的URI进行寻址,URI的结构应该是简单的。
  • 使用标准的方法来更改资源的状态
  • GET、POST、PUT、PATCH、DELETE
  • Request和Response的自描述
  • 资源多重表述
  • URI所访问的每个资源都可以使用不同的形式加以表示(XML或JSON)
  • 无状态的服务
  • 不需要保存会话状态(SESSION),资源本身就是天然的状态,是需要被保存的。


RESTful


当某Web服务遵守了REST这些约束条件和原则,那么我们可以称它设计风格就是 RESTful。


三特点


REST有三大特点:

  • 资源(名词)
  • 动作(动词)
  • 表述(超文本)



1650718264(1).png


资源


抽象的说他可以是音频、也可以是视频,更可以是订单。更俗讲其实就是实体,更接*我们*常说的“类(class)”。另外REST强调资源有唯一的URI。下面有对比


动作


主要动作:

  •  GET:检索单个资源;
  •  POST:主要是创建资源,但是GET的参数长度受限,因此也可以用在复杂参数的检索资源场景;
  •  PUT:更新资源所有属性,也可以称为替换资源;
  •  PATCH:更新资源部分属性;
  •  DELETE:删除资源;


表述


对于Request与Response的自描述,而表述方式有多种:XML、JSON等,强调HTTP通信的语义可见性。


对比


RPC


SMSApi.com/api/GetSMS


SMSApi.com/api/CreateSMS


传统的接口设计面向过程的,每个动作有特定的URI。


REST


SMSApi.com/api/SMS  GET


SMSApi.com/api/SMS  POST


REST API每个资源只有唯一的URI,而资源可以有不同的动作执行相应的接口


RPC的更加倾向于面向过程,而RESTful则以面向对象的思想进行设计。


接口定义


回到我们的短信服务,以上面的三特点进行出发,SMS不需要由外部服务进行删除、修改资源因此:


资源:SMS

动作:GET、POST

表述方式:我们约定Request、Response为JSON格式


/// <summary>
    /// 短信接口
    /// </summary>
    [Route("api/[controller]")]
    [ApiController]
    public class SmsController : ControllerBase
    {
        private readonly SmsService _smsService;
        private readonly IBus _bus;
        public SmsController(SmsService smsService, IBus bus)
        {
            _smsService = smsService;
            _bus = bus;
        }
        /// <summary>
        /// 获取一条短信记录
        /// </summary>
        /// <param name="id">主键</param>
        /// <returns></returns>
        [HttpGet("{id}")]
        public ActionResult<SmsModel> Get(string id)
        {
            if (string.IsNullOrEmpty(id))
                return NotFound();
            var smsService = _smsService.Get(id);
            return smsService.Sms;
        }
        /// <summary>
        /// 发送短信
        /// </summary>
        /// <param name="model"></param>
        /// <returns></returns>
        [HttpPost]
        public ActionResult Post([FromBody] List<PostModel> model)
        {
            _smsService.Add(model.MapTo<List<PostModel>, List<AddSmsModel>>());
            _smsService.SmsList.Where(a => a.TimeSendDateTime == null)
                .ToList().MapTo<List<SmsModel>, List<SmsQueueModel>>().ForEach(item =>
                {
                    _bus.Publish(item);
                });
            return Ok();
        }
        /// <summary>
        /// 查询短信记录
        /// </summary>
        /// <param name="model"></param>
        /// <returns></returns>
        [HttpPost("_search")]
        public ActionResult<List<SmsModel>> Post([FromBody] SearchModel model)
        {
            _smsService.Search(model.MapTo<SearchModel, SearchSmsModel>());
            return _smsService.SmsList;
        }
    }


功能描述


由上可见一共定义了三个接口


  • GET   http://localhost:port/api/sms/id 获取一条短信记录
  • POST http://localhost:port/api/sms 发送短信
  • POST http://localhost:port/api/sms/_search 查询短信记录


获取一条短信记录就不多解析了


查询短信记录


动作我使用了POST,有人会问检索资源不是用GET么?对,但是GET的参数在URL里是受限的,因此在复杂参数的场景下应该选择POST,然而我是模仿elasticsearch的复杂查询时定义,添加多一个节点/_search申明此URI是做查询的。


发送短信


此接口的实现逻辑主要两件事,持久化到MongoDB,过滤出及时发送的短信记录发送到RabbitMQ。


在持久化之前我做了一个分页的动作,我们提供出去的接口,同一条短信内容支持N个手机号,但是不同的短信运营商的所支持一次性发送的手机数量是有限的。


开始实现时,我把分页发送写到队列消费服务的发送短信逻辑里,但是这里有个问题,如果分页后部分发送成功,部分发送失败,那么这个聚合究竟以失败还是成功的状态标示呢?换句话来说我们无法保证聚合内的数据一致性。


因此我的做法就是优先在分页成多个文档存储,那么就可以避免从数据库取出后分页导致部分成功、失败。


public void Add(List<AddSmsModel> smsModels)
        {
            DateTime now = DateTime.Now;
            var smsModel = new List<SmsModel>();
            foreach (var sms in smsModels)
            {
                var maxCount = _smsFactory.Create(sms.Type).MaxCount;
                sms.Mobiles = sms.Mobiles.Distinct().ToList();
                var page = GetPageCount(sms.Mobiles.Count, maxCount);
                var index = 0;
                do
                {
                    var toBeSendPhones = sms.Mobiles.Skip(index * maxCount).Take(maxCount).ToList();
                    smsModel.Add(new SmsModel
                    {
                        Content = sms.Content,
                        CreateDateTime = now,
                        Mobiles = toBeSendPhones,
                        TimeSendDateTime = sms.TimeSendDateTime,
                        Type = sms.Type
                    });
                    index++;
                } while (index < page);
            }
            SmsList = smsModel;
            _mongoProxy.BatchAddAsync(SmsList);
        }


目录
相关文章
|
3月前
|
API
阿里云短信服务文档与实际API不符
阿里云短信服务文档与实际API不符
|
2月前
|
JSON 关系型数据库 测试技术
使用Python和Flask构建RESTful API服务
使用Python和Flask构建RESTful API服务
|
3月前
|
API
阿里云短信平台API错误码提示错误天级流控显示小时级错误码
阿里云短信平台API错误码提示错误天级流控显示小时级错误码
|
3月前
|
开发框架 .NET API
Windows Forms应用程序中集成一个ASP.NET API服务
Windows Forms应用程序中集成一个ASP.NET API服务
111 9
|
4月前
|
人工智能 Serverless API
一键服务化:从魔搭开源模型到OpenAI API服务
在多样化大模型的背后,OpenAI得益于在领域的先发优势,其API接口今天也成为了业界的一个事实标准。
一键服务化:从魔搭开源模型到OpenAI API服务
|
4月前
|
Go API 开发者
深入探讨:使用Go语言构建高性能RESTful API服务
在本文中,我们将探索Go语言在构建高效、可靠的RESTful API服务中的独特优势。通过实际案例分析,我们将展示Go如何通过其并发模型、简洁的语法和内置的http包,成为现代后端服务开发的有力工具。
|
3月前
|
开发框架 缓存 算法
开源且实用的C#/.NET编程技巧练习宝库(学习,工作,实践干货)
开源且实用的C#/.NET编程技巧练习宝库(学习,工作,实践干货)
|
3月前
|
Cloud Native API C#
.NET云原生应用实践(一):从搭建项目框架结构开始
.NET云原生应用实践(一):从搭建项目框架结构开始
|
3月前
|
API
使用`System.Net.WebClient`类发送HTTP请求来调用阿里云短信API
使用`System.Net.WebClient`类发送HTTP请求来调用阿里云短信API
46 0
|
5月前
|
API Java Python
API的神秘面纱:从零开始构建你的RESTful服务
【8月更文挑战第31天】在现代网络应用开发中,RESTful API已成为数据交互的标准。本文通过比较流行的技术栈(如Node.js、Python的Django和Flask、Java的Spring Boot)及其框架,帮助你理解构建RESTful API的关键差异,涵盖性能、可扩展性、开发效率、社区支持、安全性和维护性等方面,并提供示例代码和最佳实践,指导你选择最适合项目需求的工具,构建高效、安全且易维护的API服务。
66 0