Brief introduction
As a business logic provider, the API carries the core logic of the project and thus has a relatively high logical complexity. How to simplify the code writing, how to standardize the unified writing style and the logic specification, how to improve the maintainability and extensibility of the code. High cohesion and low coupling of the construction of the project becomes important.
The example is an enterprise project, as shown in the framework below
API layer. jpg
Security: Overrides the HTTP request (override Delegatinghandler) to make a legitimate judgment on the requested slice, and by the way, the preprocessing of the signature requirement.
Client: Defines a unified interface invocation method, which simplifies and unifies the interface usage.
CTRL layer: As the direct provider of the service, directly on the server to provide similar to the restful style of the interface (feel strict restful style, need to have a complete domain model-driven, in fact, the situation is always not satisfactory, the domain abstraction ability is not enough. ), get request data, invoke filter filter on demand, further judge, call
Model layer: As the business model layer, provides the actual operation of the business logic. Use a unified entity model, and contact the Ibatis for data manipulation.
The specific code structure is as follows:
Api-uml.jpg
The following are detailed descriptions and code examples for each module:
Entity Library Project code example
Project structure such as:
Entity.jpg
Domain module, as the entity model, the simple code is as follows
public class user{Public int Id {get; set;} public string Nickname {get; set;} public string Avatar {get; set;}}
request, requesting the structure model, takes advantage of the generic interface, which links the request class to the return class, and plays a role in controlling the reversal.
Publicly abstract class abstractrequest{ public bool Validateparameters () { //Common Method example, verifying parameter Legality }} public interface irequest<t> where T:abstractresponse { //Gets the interface name string Getapiname (); Gets the interface encoding string Getapicode (); } Gets the user information request structure definition public class getuserrequest:abstractrequest,irequest<getuserresponse> { public int Id {get; set;} public string Getapiname () { return "User.getuserdetail"; } public string Getapicode () { return ' User001 '; } }
The response module, as the return type of the request, defines a unified return structure, which makes it easy for consumers to judge the consistency return code.
Public abstract class Abstractresponse { //Return code public int code {get; set;} Error message Public string Message {get; set} } public class Getuserresponse:abstractresponse {public User User {get; set;} }
Service Project code sample
Project structure such as:
Service.jpg
code example:
Public interface Iuserservice { getuserresponse GetUser (int id), } public class Baseservice { // protected sqlinstance sqlinstance; Public Baseservice () { //sqlinstance=new sqlinstance ();//Instantiate database connection// ... } //... } public class Userservice:baseservice,iuserservice {public getuserresponse GetUser (int id) { // Link database Get Data //... throw new NotImplementedException (); } }
Security Class Library code example
The class library simply handles security issues and adds permission judgments at the API request entrance. Use the way to override HTTP requests.
code example
public class Myhandler:delegatinghandler {protected Async override task& Lt Httpresponsemessage> SendAsync (httprequestmessage request, CancellationToken CancellationToken) {IEn Umerable<string> keyenumerable; var T1 = Request. Headers.trygetvalues ("Key", out keyenumerable); var key = Keyenumerable.firstordefault (); if (!true)//Verify a permission similar to token {return await task.factory.startnew
The abstraction of the permission to judge, can be directly called to the Webapi side, added to the routing configuration code.
WEBAPI Project Examples
As the actual definition of the interface, WEBAPI defines the actual rules of the interface file, and makes the corresponding security management and control of the interface. Learning permissions control, presumably identified several interfaces:
Interface permissions. png
These permissions are judged on the security of the centralized management. The definition of an interface requires only the appropriate logic to use the judgment legitimacy.
code example:
public class Usercontroller:apicontroller { private iuserservice userservice; Public Usercontroller () { userservice=new userservice (); } [signature]//Security Signature filter Judgment [HttpPost] public getuserresponse GetUser (getuserrequest request) { // Parameter determination, safety judgment, etc. var ret = userservice.getuser (Request. ID); return ret; } }
The above is a sample interface to obtain user information, and as the interface entry routing configuration, you need to judge the legality of the request, the routing configuration Code is as follows:
public static void Register (Httpconfiguration config) { //Web API Configuration and Services //Configure Web API To use only bearer token authentication. Config. Suppressdefaulthostauthentication (); Config. Filters.add (New Hostauthenticationfilter (Oauthdefaults.authenticationtype)); Web API routes config. Maphttpattributeroutes (); Config. Routes.maphttproute ( name: "Defaultapi", routetemplate: "Api/{controller}/{action}", defaults:new {ID = routeparameter.optional} ); Add the code to add the HTTP request to the Portal Processing config. Messagehandlers.add (New MyHandler ());}
Client class Library code example
The Client class library defines the public methods for interface invocation.
1, using the generic interface, the request class and the return class are encapsulated, simplifying the invocation of code writing.
2, and make the consumer call interface through the proxy class, to avoid cross-domain problems.
3, the consumer calls all agree to use the Uniform class Library, is the processing of the log is unified, the return error can also be consistent definition.
The code examples are as follows:
Public interface IClient {T execute<t> (irequest<t> request) where t:abstractresponse;} public class Defaultclient:iclient {private readonly string AppKey; Private readonly string Appsecret; Private readonly string baseUrl = "http://localhost:16469/api/"; Private readonly bool Isneedlogfile = FALSE; Private ReadOnly LogFile LogFile; public static readonly String secureheaderappkey = "Secure_head_appkey"; public static readonly String secureheadersignature = "Secure_head_signature"; Public defaultclient () {baseUrl = configurationmanager.appsettings["Service_base_url"]; AppKey = configurationmanager.appsettings["App_key"]; Appsecret = configurationmanager.appsettings["App_secret"]; Isneedlogfile = "1". Equals (configurationmanager.appsettings["Client_log_file"]); LogFile = new LogFile ("Client_log_path"); Logfile.subpath = AppKey; } Public Defaultclient (String serviceBase, String code, string key) {baseUrl = ServiceBase; AppKey = code; Appsecret = key; Public T execute<t> (irequest<t> request) where T:abstractresponse {var webreques t = (HttpWebRequest) webrequest.create (BASEURL + request). Getapiname ()); Webrequest.method = "POST"; String Reqjson; string sign; using (Stream rs = Webrequest.getrequeststream ()) {Reqjson = Jsonconvert.serializeobject (reques T); byte[] reqbytes = Encoding.UTF8.GetBytes (Reqjson); Rs. Write (reqbytes, 0, reqbytes.length); Rs. Close (); } Webrequest.contenttype = "Application/json"; WEBREQUEST.HEADERS.ADD (Secureheaderappkey, AppKey); Sign = ComputeHash (AppKey, Appsecret, Reqjson); WEBREQUEST.HEADERS.ADD (secureheadersignature, sign); Log if (isneedlogfile) {LogFile.Log (string. Format ("[{0}] requested content: {1}", request. Getapicode (), Reqjson)); LogFile.Log (String. Format ("[{0}] requested signature: {1}", request. Getapicode (), sign)); } try {using (var resp = (HttpWebResponse) webrequest.getresponse ()) { try {Stream Respstream = resp. GetResponseStream (); if (Respstream = = null) {throw new WebException ("GetResponseStream Retu rned null "); } var streamReader = new StreamReader (respstream); String respstr = Streamreader.readtoend (); Log if (isneedlogfile) {LogFile.Log (string. Format ("[{0}] response content: {1}", request. Getapicode (), respstr)); } return jsonconvert.deserializeobject<t> (RESPSTR); } catch (Exception e) {//log if (IsN Eedlogfile) {LogFile.Log (string. Format ("[{0}] Response error: {1}", request. Getapicode (), e.message)); } throw new ApplicationException (E.message, E); }}} catch (WebException e) {var errmsg = new Streamreade R (E.response.getresponsestream ()). ReadToEnd (); Log if (isneedlogfile) {LogFile.Log (string. Format ("[{0}] requested error: {1}", request. Getapicode (), errmsg)); } throw new Apiserviceexception (errmsg); }} private string ComputeHash (string key, StringSecret, String body) {return convert.tobase64string (SHA1. Create (). ComputeHash (Encoding.Default.GetBytes (String. Concat (key, Secret, body. Trim ()))); } }