ASP. NET Web API Synthesis Example

Source: Internet
Author: User
Tags local time visual studio 2010

Directory
    1. Overview
    2. function Introduction
    3. Program Structure
    4. Server-Side Introduction
    5. Client Introduction
    6. Contract
    7. WEB API Design Rules
    8. Parallel write conflicts and timestamps
    9. Authentication detailed
    10. WEB API Validation rules
    11. Introduction to Client MVVM
    12. Web. config
    13. Some questions about this demo

Overview

I wrote some of the blog about ASP. NET Web API, got some friends of the response, I have always wanted to tidy up the code for your reference, but later found that the whole project from a separate part of the code is really not easy, a blink of an eye on this thing to forget, Recently finally resolved to make a make, so this article, although the demo is not perfect, but has included all of my current knowledge of the Web API related technology, as to where there is still need to improve, I will at the end of the article one by one point out that because the Web API server side is no interface, This is not easy to demonstrate, so I've also provided a client that is written in WPF, first a glimpse of the fast:

function Introduction

The following is an introduction to the relevant technologies or features that the program will demonstrate:

Server-side:

    • Complete, well-structured (at least I think so) the server side of the ASP.
    • Model validation using the DataAnnotations
    • Custom Model Validation
    • Layering (separate UI layer and business logic layer)
    • Excellent logging methods
    • High safety factor authentication (well, I'm writing to use dared to elicit a master to pick me up)
    • Sensitive information Encryption
    • Pure Web API code (removal of CSS/JS and unwanted view engines)

For the idea of authentication, you can refer to "How to implement the authentication of RESTful Web API"

Client:

    • Self-designed MVVM simple Framework
    • A large number of WPF practical tips
    • Using DataAnnotations for client model validation
    • Complete example of httpclient

Other:

    • Automatic object mapping (using AutoMapper)
    • Run standalone, 0 configuration, open ready with Visual Studio 2010
    • I've tried to minimize duplication of code ... (In fact, it's not enough.)
    • Upload and download binary files
Program Structure

The main purpose of this program is to do a complete document, the function of a comprehensive and 0 configuration of the demo, so does not involve the use of the DBMS, although the actual use of the DBMS is almost necessary, but this time I use an XML to replace the DBMS.

The program is divided into two parts, one is the server side, the other is the client, and is divided into two different solution, this is done for the convenience of debugging. But the problem is that there will be some duplication of things, such as these three libraries: commlib,webapikit,webapicontract, they are public libraries, but they exist in different solution, and I use SVN as a tool to avoid them in real work. " Changed this to forget the ", and this time I used a long time ago I wrote a tool to make them" synchronous ":

This tool will also be available for download later in this article.

Server-Side Introduction

Server-side file structure

BLL-Business Logic Layer Userinfo_bll.cs-is the user information class, the suffix "BLL" means that it belongs to the business logic layer, I am accustomed to distinguish between different levels of the model UserManager.cs-business logic layer of the main class, provide a variety of "adding and deleting" methodCommlib-Public libraries, including DES encryption classes, MD5 classes, log classes, some regular expressions, global constants, etc...Server-The main project of the ASP. AutoMapperConfig.cs-The configuration class for automatic object mapping, such as converting USERINFO_BLL directly to userinfo_api_get without the need to assign a value to a property Webapiconfig.cs-asp.net WEB API Routing Configuration Class AvatarsController.cs-GET, modify and delete avatar EntranceController.cs-log in and get your own information Passwordcon Troller.cs-Modify your password UsersInfoController.cs-Get individual user information, get a list of users, modify user information, add users (not implemented), and delete users (not implemented) ModelValidationFilter.cs- Global model validation filter for all requests WebApiAuthFilter.cs-authenticator for the majority of controllers that do not exclude authentication in some places WebApiExceptionFilter.cs-Global exception handler WebApiRoleFilter.cs-a role permission filter for some actions, such as some action that can only be done by an administrator GuidSet.cs-GUID collection to prevent the re-attack WebApiPrincipal.cs-The identity class of the logged-on user GlobalServerData.cs-Inside includes a static Guidset Managers.cs-inside includes a static Usermanagerwebapicontract-This library is used to "negotiate" with the client.Webapikit-some tools that can be used on the client/server side

Client Introduction

Project structure diagram for the client:

Client-the main project PasswordHelper.cs-the password control's help class, which binds the password text of the password control to the view MODEL,WPF the need for security is not provided by default for this binding support UIVisibleConverter.cs-some WPF interface converters for controlling the display and hiding of interface elements based on some properties of the view model Changepassword_vm.cs-Modify the password interface with the view model, suffix "VM "Is the meaning of the view model. Login_vm.cs-The view Model for the login interface. Userinfo_vm.cs-View Model for displaying/modifying user information on the main interface. ViewModelBase.cs-The base class for all view model implements the INotifyPropertyChanged interface, IDataErrorInfo interface, and some helper methods

Contract

The word contract (contract) actually comes from a Web service, but Web service is a very heavy-weight technology that I personally don't dislike. In fact, the contract simply says, is: How does the Web API work? The contract should include: What the calling address is, what the method is, what the content is, what validation it has. Take Userinfo_api_put as an example:

    public class Userinfo_api_base    {        [Required (errormessage = verifier.errmsg_cannot_be_null)]        [ RegularExpression (verifier.reg_exp_chinese_name, errormessage = verifier.errmsg_reg_exp_chinese_name)] public        String Realname {get; set;}     Real name Public        float Height {get; set;}        Height public        DateTime Birthday {get; set;}   Birthday    }    //modify user information (ordinary users can only modify their own information)    //put api/usersinfo/{username} public    class Userinfo_api_put: Userinfo_api_base    {        [Enuvaluevalidator (Roletype.administartor, Roletype.normal)] public        string Role {get; set;}         Role Administrator, normal, normal user cannot modify this field    }

If you want to modify the "Guogangj" This user's information, then go to "api/usersinfo/guogangj" this URI address put such an object, where realname this property must not be empty, but also has to be 2-10 Chinese characters, of course, Neither height nor birthday is nullable, because both float and datetime are non-nullable types, and the Role property performs a custom validation to ensure that its value must be "Administrator" or "Normal".

Such a contract must be both server side and client understanding, so the form of a class library, the server side and the client reference to this class library, the biggest problem is that the class library has been changed in the case of updating one side but forget the other side, I am currently using some tools to try to avoid this situation, such as the svn externals parameter setting. What better way do you have in this respect? Hope to share.

WEB API Design Rules

Although I have mentioned the "Law" of the Web API in the understanding and design of the RESTful Web API, here is a few more additions.

RESTful core content is "R", that is, resources, we have to change the deletion of resources into the four actions of http: POST, DELETE, get and put. Now there is a question: if my user name is GUOGANGJ, I want to get my information, is "Get/api/myinfo", or "get/api/usersinfo/guogangj" it? Technically no problem, now the key is to consider from a "resource" perspective, if you think "/api/myinfo" is a resource, it means that each user will get a different result for this resource, and for "/api/usersinfo/guogangj" Such resources, regardless of who, get the content should be consistent (if you have access to the words), from this point of view, "/API/USERSINFO/GUOGANGJ" this way more restful, this is my understanding, not necessarily correct, but also invited expert analysis.

Parallel write conflicts and timestamps

When a resource is put and deleted, it needs to be written in parallel to the conflict check, because when writing, the resource may have been moved by someone else, this check is usually done with a "timestamp", I am using the datetime type of ticks, which is a long type, Enough to reflect the time of the resource change. For example, I now want to modify the user Guogangj information:

PUT Http://localhost.:57955/api/usersinfo/guogangj? updateticks=635054404507843749 {"Role": "Administrator", "Realname": "Ching", "Height": 1.67, "Birthday": "1981-11-12t00 : 00:00 "}

Perhaps carefully you notice that there seems to be a "." Behind localhost, which is added to allow Fiddler to capture this HTTP packet.

I will take the updateticks parameter in the URI, the server side of the business logic layer in the execution of the update, will determine whether the timestamp and the current database timestamp is consistent, if not consistent, throw a parallel write conflict exception.

The reason I put updateticks in the URI is that this updateticks can also be a part of the resource. For example, for this put action, my intention is: I want to update the "/API/USERSINFO/GUOGANGJ" Resource with timestamp "635054404507843749", if its timestamp is not "635054404507843749", That's not the resource I want to update.

This is my method, another way I can think of is to put a timestamp in the HTTP header, such as:

PUT http://localhost.:57955/api/usersinfo/guogangj updateticks:635054404507843749 {"Role": "Administrator", " Realname ":" Ching "," Height ": 1.67," Birthday ":" 1981-11-12t00:00:00 "}

So the server side in the processing time can take out timestamps, but the method is slightly different, that better? As far as I am concerned, it is biased to the former, here also please expert advice.

Authentication detailed

OK, finally to the play, that is the authentication of the Web API, in order to make everyone immediately have a direct understanding, I use Fiddler to intercept a package, see my request in the end what?

PUT Http://localhost.:57955/api/usersinfo/guogangj? updateticks=635054404507843749 http/1.1 custom-auth-name:guogangj Custom-auth-key: 58e595ec40a74ff4eef0856d7e59018f6141e12ea3db965f74b416a4dfdb5746e6dcfdedbdf5da0c524254763fee207b1fa8ef6d948132df45c9c89aa 7bf3a7373c509687c03bde5 Accept:application/json Content-type:application/json; Charset=utf-8 host:localhost.:57955 content-length:94 expect:100-continue
{"Role": "Administrator", "Realname": "Ching", "Height": 1.67, "Birthday": "1981-11-12t00:00:00"}

This is a complete HTTP request, in the HTTP header more than two things: "Custom-auth-name" and "Custom-auth-key", Custom-auth-name Needless to say, a look is known as the user ID, who is the initiator, But if he said he is who the server thinks he is, then there is no security, so also Custom-auth-key (hereinafter referred to as Key) this thing to verify that this Key is a long string of things, which is encrypted and transcoded text, Let's talk about how the key came from here.

In Webapikit This library has such a method: Webapiclienthelper.makeprincipleheader, the code is all inside, not much, I one by one explanation:

private static void Makeprincipleheader (Httprequestmessage reqmsg, String struri) {     //even the exact same request content, I would like to generate a different key, Therefore, each time you need to generate a new GUID, to prevent "re-send" with the same GUID, with this GUID so that each request (regardless of URI and content is the same) is unique, non-duplicated and duplicate     guid guid = Guid.NewGuid ();     Get a valid URI, such as this long string of requests for URI gets to the content is "/api/usersinfo/guogangj"     Struri = Internalhelper.geteffectiveuri (Struri);     The valid URI is attached to the GUID, once MD5 encrypted, (in this way to obtain the same length but each time the content is very different) and then connected to the GUID, the result as a symmetric encrypted plaintext     string strtoencrypt = Md5.md5encode ( Struri + GUID) + "" + GUID;     PlainText password executes two times after MD5 as a symmetric encrypted key, encrypt the previously generated string of "plaintext", well, the key generated a     string strtheauthkey = Des.encode (Strtoencrypt, Md5.md5twiceencode (Password));     Add the result to the HEADER of the HTTP request to     ReqMsg.Headers.Add (Consts.http_header_auth_user, UserName);     REQMSG.HEADERS.ADD (Consts.http_header_auth_key, Strtheauthkey);}

Symmetric encryption, no key can not be restored, and the key is not transmitted over the network, it is impossible to be a third party through the interception of packets and other ways to track, so this cipher should be impossible to crack. After the server has taken the request packet, perform a reverse operation:

public static bool Verifyauthkey (string strauthuser, String Strauthkey, String Strrequesturi, string strpwdmd5twicesvr, R EF Guid guidrequest) {try {//decryption of symmetric encryption, key for user password two times MD5, server-side known string strurlandguid = Des.decode (st          Rauthkey, STRPWDMD5TWICESVR); If the decryption is successful, split into two paragraphs with a space, a "valid URI with a GUID, one MD5 encryption," and the other is the GUID string[] Arrurlandguid = Strurlandguid.split (new[] {"          });          if (Arrurlandguid.count ()! = 2) return false;          String strurl = Arrurlandguid[0];          String strguid = Arrurlandguid[1];          The decrypted Guid is returned as a parameter, so that it is added to a global collection to prevent "re-sending" ("re-sending" will be checked in another place) Guidrequest = Guid.parse (strGUID); And then follow the same method as the client to generate a "valid URI connection GUID, do one MD5 encryption" result, the result is compared with the results just decrypted, if consistent, authentication through Strrequesturi = Internalhelper.geteffecti          Veuri (Strrequesturi); if (string.          Compare (Md5.md5encode (Strrequesturi + guidrequest), strurl, true) = = 0) {return true; }} catch (Exception)//SuddenlySlightly this one produces any exception that will be considered to be verified not by {//ignore any exception} return false;} 

This verification method can eliminate the "identity impersonation" and "re-send", and completely independent of the third-party library, the method is very simple, the developer can easily further strengthen it, I think for most occasions, enough. Well, wait for an expert to correct me.

WEB API Validation rules

Validation is always a key feature of the application, as the previously mentioned authentication is also a validation, the purpose of which is to ensure that the right person does the right thing.

Some validation is just a simple rule, such as Chinese name verification: cannot be null, must be 2-10 characters, some authentication needs to access the database to know, such as: Add a user, not with the ID of the existing user, and some comprehensive validation, in this example also embodies: Users can modify their own information , but only administrators can modify other people's information.

is the validation on the UI layer or on the business logic layer? In fact, this is not only the Web API has the problem, all the system, in the design of the time to consider such a problem. I used to do the system, I think the layer and layer is mutual distrust, so the business logic layer to do a complete set of validation, and the UI layer of course, a complete set of validation, the result is to repeat the code to increase, look a bit messy, Then I thought: Why does the business logic layer need to be executed again if the UI layer of the Web site performs validation on the information provided by the user? Should not be needed, because the UI layer and the business logic layer are placed on the server side, which we can control, we only need to the client to verify the data, so I drastically removed the business logic layer of validation code, the program looks neat a lot.

* Note: In this demo, the server site belongs to the UI layer, and the BLL class library belongs to the business logic layer

But some data-related validation is not so easy to do in the UI layer, such as the previous "Add a user, not with the ID of the existing user", this will need to check the database in the end there is no such user ID first.

So, in general, my rule is this: authentication, input validation, and permission judgment can be placed in the UI layer on the UI layer, not the UI layer (such as the validation of specific data), placed in the business logic layer, UI layer validation and business Logic layer validation is best not to repeat.

Introduction to Client MVVM

The focus of this article is on the Web API, but by the way, the client's MVVM model, MVVM, which is "Model-view-viewmodel", ViewModel and view bindings, is bound here to mean: When the View changes, ViewModel to reflect, on the contrary, when the ViewModel changes, the view should be reflected. This is probably the case, the specifics of what will be divided into two-way binding and one-way binding.

The view changes, ViewModel also must change, this does not seem difficult, for example, you enter "Zhangsan" in the username text box, when your input focus leaves the text box, the program will produce an event, It handles the event and assigns the value of the text box to ViewModel, which is not necessarily a loss of focus, it can be typed, or it can be triggered manually.

And ViewModel change, the view must follow the change, this how to achieve it? WPF provides an interface inotifypropertychanged, where only one of the Event,viewmodel called "propertychanged" changes, notifies the view change by triggering the event. I have provided a base class called "ViewModelBase" in the client code to implement this interface, and my other viewmodel are derived from this base class and will trigger the event in this interface when SetValue to their properties. Implement a notification of the view.

There are still a lot of articles on MVVM online, and some pretty heavyweight frameworks, like Prism, are not overnight to grasp these things, but I believe original aim, as I say.

In addition to some of the WPF technology, I do not mention here, after all, this is not the focus of this article, we can refer to some other information.

Web. config

This is probably the simplest web. config you've ever seen, because I've removed all the unused.

<?xml version= "1.0" encoding= "Utf-8"?><!--for more information on what to  Configure your ASP. , please visit  http://go.microsoft.com/fwlink/? linkid=169433  --><configuration>  <system.web>    <compilation debug= "true" targetframework= "4.0"/>    <authentication mode= "None"/>  </system.web></configuration >

Yes, the above is all, the only thing worth mentioning is the authentication mode attribute, we have to use a custom authentication method, so we have to set this to none, otherwise the server side will probably use the Windows authentication mechanism. And this program has been verified under IIS, no problem with normal use.

Some questions about this demo

After all, the demo is demo, I also found some problems in the process of writing, some because of the constraints, some are really problems, so must be listed so that everyone in the formal development of the time to avoid:

    • Is it better to use UTC time instead of local time for timestamps? (Take into account that if you use UTC time, you have a bit more conversion, so I don't need it in this demo)
    • No transactions are used. Transaction functionality is usually the function of the DBMS, this demo does not use the DBMS, and a good system can also do the rollback of files, not just the DBMS, but this is far beyond the scope of this demo.
    • Usersinfo Post and delete functions are not done (lazy)
    • The client's network traffic is blocking the UI thread and the user experience is poor. Improved reference
    • The validation of client ViewModel and API contract is duplicated, how can this repetition of master be eliminated?
    • Authentication requires calling the business logic layer, not caching at the UI level, and without caching in a formal, large-scale application, it's very inefficient, but the cache update is a big problem, and I believe that large Web applications have a rigorous and complex set of rules.
    • Password on the server side of the save format fixed to two times MD5, this is not conducive to future improvements in cryptographic algorithms.
    • Client input validation is not good enough, such as typing "abc" in Age, although there are errors (converted to digital failure), but can also be submitted (the content submitted is the previous number)
    • Because some global data on the server side is static, there may be a thread-safe problem

ASP. NET Web API Synthesis Example

Related Article

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.