Implementation of the SMS Service-SIKIRO.SMS.API service in the. NET Core Practice Series

Source: Internet
Author: User
Tags representational state transfer rabbitmq log4net
Objective

The ". NET core Practice series of SMS Service-Architecture Design" introduces my architecture design of SMS service, and analyzes my design concept for the scene. This article continues to explain the implementation of API services.

Source Address: Github.com/skychensky/sikiro.sms

This service is built using. NET core Webapi, and the. NET core WEBAPI base prototype is restful, but what is restful?

Rest API Introduction Rest

Representational state Transfer's abbreviation, translated as "presentation level transition", was by Roy Thomas Fieding in his doctoral dissertation architectural Styles and the Design of network-based software architectures, an architectural idea proposed in the paper.

And his thesis puts forward a few constraints that a restful application should have.

    • Each resource should have a unique identity
      • Each object or resource can be addressed by a unique URI, and the structure of the URI should be simple.
    • Use standard methods to change the state of a resource
      • GET, POST, PUT, PATCH, DELETE
    • Self-description of request and response
    • Multiple representations of resources
      • Each resource accessed by a URI can be represented in a different form (XML or JSON)
    • Non-stateful service
      • There is no need to save session state (sessions), the resource itself is a natural state, it needs to be saved.
Restful

When a Web service adheres to the rest of these constraints and principles, then we can call it design style is RESTful.

Three features

Rest has three main features:

    • Resources (noun)
    • Action (verb)
    • Presentation (hypertext)

Resources

The abstract is that he can be audio, can also be video, and can be orders. More lectures is actually the entity, closer to what we normally call "class." In addition, rest emphasizes that the resource has a unique URI. Here's a comparison.

Action

Main actions:

    • GET: Retrieves a single resource;
    • POST: The main is to create resources, but get parameter length is limited, so can also be used in complex parameters of the retrieval resource scene;
    • PUT: Updates all properties of a resource, or it can be called a replacement resource;
    • PATCH: Update resource section properties;
    • Delete: Deletes the resource;
Expression

For the self-description of request and response, there are many ways to express it: XML, JSON, etc., emphasizing the semantic visibility of HTTP communication.

Compare RPC

Smsapi.com/api/getsms

Smsapi.com/api/createsms

The traditional interface design is process-oriented and each action has a specific URI.

REST

Smsapi.com/api/sms GET

Smsapi.com/api/sms POST

REST API Each resource has only a unique URI, and the resource can have different actions to execute the corresponding interface

RPC is more prone to process-oriented, while restful is designed with object-oriented thinking.

Interface definition

Back to our SMS service, starting with the above three features, SMS does not need to be deleted by external services, modify resources so:

Resources: SMS

Action: GET, POST

How to express: we agree to request, response in JSON format

 /// <summary>    ///SMS Interface/// </summary>[Route ("Api/[controller]")] [Apicontroller] Public classSmscontroller:controllerbase {Private ReadOnlySMSService _smsservice; Private ReadOnlyIBus _bus;  PublicSmscontroller (SMSService smsservice, IBus bus) {_smsservice=SMSService; _bus=bus; }        /// <summary>        ///get an SMS record/// </summary>        /// <param name= "id" >PRIMARY Key</param>        /// <returns></returns>[HttpGet ("{ID}")]         PublicActionresult<smsmodel> Get (stringID) {if(string. IsNullOrEmpty (ID))returnNotFound (); varSMSService =_smsservice.get (ID); returnsmsservice.sms; }        /// <summary>        ///Send SMS/// </summary>        /// <param name= "model" ></param>        /// <returns></returns>[HttpPost] PublicActionResult 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);            }); returnOk (); }        /// <summary>        ///Query SMS Records/// </summary>        /// <param name= "model" ></param>        /// <returns></returns>[HttpPost ("_search")]         PublicActionresult<list<smsmodel>>Post ([frombody] Searchmodel model) {_smsservice.search (model. Mapto<searchmodel, searchsmsmodel>()); return_smsservice.smslist; }    }
Function description

Altogether three interfaces defined by the above

    • Get http://localhost:port/api/sms/id get an SMS record
    • Post Http://localhost:port/api/sms Send SMS
    • POST http://localhost:port/api/sms/_search Query SMS Records

Get a text message record doesn't have much to parse

Query SMS Records

I used the post, some people will ask to retrieve resources not with Get? Yes, but the get parameters are limited in the URL, so in the context of complex parameters should be selected post, but I am a complex query to imitate Elasticsearch definition, add one more node/_search declare this URI is to do the query.

Send SMS

This interface implements logic primarily for two things, persisting to MongoDB, filtering out the timely sending of SMS records sent to RABBITMQ.

Before the persistence I did a paging action, we provide out of the interface, the same text message content support n mobile phone number, but the different SMS operators support one-time send mobile phone number is limited.

When I started to implement, I sent paging to the queue consumer service to send SMS logic, but there is a problem, if the page after the partial send success, partial send failed, then this aggregation to fail or success status indicator? In other words, we cannot guarantee the consistency of the data within the aggregation.

So my approach is to prioritize paging into multiple document stores, so you can avoid paging out of the database and causing partial success and failure.

 Public voidADD (list<addsmsmodel>smsmodels) {DateTime now=DateTime.Now; varSmsmodel =NewList<smsmodel>(); foreach(varSmsinchsmsmodels) {                varMaxCount =_smsfactory.create (SMS. Type).                MaxCount; Sms. Mobiles=SMS. Mobiles.distinct ().                ToList (); varpage =Getpagecount (SMS.                Mobiles.count, MaxCount); varindex =0;  Do                {                    varTobesendphones = SMS. Mobiles.skip (Index *maxCount). Take (MaxCount).                    ToList (); Smsmodel.add (NewSmsmodel {Content=SMS. Content, Createdatetime=Now , mobiles=Tobesendphones, Timesenddatetime=SMS. Timesenddatetime, Type=SMS.                    Type}); Index++; }  while(Index <page); } smslist=Smsmodel;        _mongoproxy.batchaddasync (smslist); }
Project-related open source framework

Easynetq

EasyNetQ.DI.Microsoft

Sikiro.Nosql.Mongo

Log4net

Mapster

Easynetq

This open source framework is a package for rabbitmq.client that hides a lot of implementation details and simplifies the way you use it. and provides a variety of IOC injection methods

Source Address: Github.com/easynetq/easynetq

Sikiro.Nosql.Mongo

This is my own. A library of common base operations for MONGO drives

Source Address: Github.com/skychensky/sikiro.nosql.mongo

Mapster

Entity mapping framework, to see the evaluation data than automapper and other such as the efficiency is high, and the ease of use is very high.

Github.com/mapstermapper/mapster

Global Exception Log records
 Public classGolbalexceptionattribute:exceptionfilterattribute { Public Override voidonexception (Exceptioncontext context) {if(!context. exceptionhandled) {context.            Exception.writetofile (); }            Base.        Onexception (context); }    }  Public voidconfigureservices (iservicecollection services) {services. ADDMVC (Option={option. Filters.add<GolbalExceptionAttribute>(); })                .        Setcompatibilityversion (Compatibilityversion.version_2_1); }
Loggerhelper

The above writetofile is my extension of the exception method, using the Log4net log framework to record the exception, if necessary can also be written to MongoDB or Elasticsearch

/// <summary>    ///Log Helper Class/// </summary>     Public Static classLoggerhelper {Private Static ReadOnlyIloggerrepository Repository = Logmanager.createrepository ("netcorerepository");  Public Static ReadOnlyILog Log = Logmanager.getlogger (Repository.name,typeof(Loggerhelper)); StaticLoggerhelper () {xmlconfigurator.configure (Repository,NewFileInfo ("Log4net.config")); }        #regionText Log/// <summary>        ///Text Log/// </summary>        /// <param name= "message" ></param>        /// <param name= "ex" ></param>         Public Static voidWriteToFile ( ThisException EX,stringMessage =NULL)        {            if(string. IsNullOrEmpty (message)) message=Ex.            Message;        LOG.ERROR (message, ex); }        #endregion    }
Packaging of the tool library

Both the framework and the tool library are available as libraries, and are reusable, but they differ in that the tool library is available out of the box, most of the calls are made in static methods, and only a few or even a few methods are used.

and framework definition, in order to implement a software component specification, provide the basic functions required by the specification of software products, and he is binding, reusable, normative. He is a semi-finished product that can be rewritten.

Therefore, in order to simplify the use of the framework, the common settings, build a combination of encapsulation, as an extension class or helper class to provide, simplified use, increased readability.

Use of swagger

The advantage of the HTTP protocol is the lightweight, cross-platform, so good flexibility that requires an interface to describe external exposure. Swagger is a good choice, no need to write your own documents and provide a background management interface, you can test, simplifying a lot of work.

I chose the Nswag.aspnetcore Open source component, his use is very simple. Only two steps are required:

1. Configure swagger:
 Public voidConfigure (Iapplicationbuilder app, Ihostingenvironment env) {if(env. Isdevelopment ()) {app.            Usedeveloperexceptionpage (); } app. Useswaggeruiwithapiexplorer (Settings={settings. Generatorsettings.defaultpropertynamehandling=propertynamehandling.camelcase; Settings. PostProcess= Document = ={document.Info.Version="v1"; Document.Info.Title="Sikiro. SMS. API"; Document.Info.Description="SMS Service API"; Document.Info.TermsOfService="None";           };            }); App.        Usemvc (); }
2. Setting up site projects

This setting displays the interface, parameter annotations to the Swagger page

Nswag also has multiple versions of the UI selection:

    • Useswaggerredoc
    • Useswaggerui
    • UseSwaggerUi3

Visit Http://localhost:port/swagger to see the API documentation

Deployment

Because my company is still using Windows Server 2008. Therefore, the environment installation package should be prepared before deployment:

. NET Core 2.1.3 Windows-hosting

After the installation is complete, restart the server, publish the files to the server, and edit the application pool to unmanaged code. You will have access to the

End

This article introduces the design and implementation of SIKIRO.SMS.API, and the next chapter encapsulates the SDK for API calls. If you have any suggestions, please comment the feedback below to me.

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.