the store in extjs can submit data in batches during sync. The so-called batch refers to if the CREATE, update, and delete objects are recorded in the store at the same time, submit in three installments. At the time of submission, multiple objects will be combined into strings in JSON format. When only one data is to be submitted, the JSON string is as follows:
{< SPAN class = "str"> "ID" : "a6d671ca-5480-4b5b-bf7a-b8459c0f598b" , "mobilepin" : "" , "email" : "111@ee.com" , "password" : "" , "createdate" : null , "lastlogindate" : null , "lastpasswordchangeddate" : null , "comment" : "" , "username" : "user1" , "mobilealias" : "" , "lastactivitydate" : null , "displayname" : "" , "rememberme" : false }
If multiple data entries exist, the JSON string is:
[{ "ID" : "a6d671ca-5480-4b5b-bf7a-b8459c0f598b" , "mobilepin" : "" , "email" : "111@ee.com" , "password" : "" , "createdate" : null , "lastlogindate" : null , "lastpasswordchangeddate" : null , "comment" : "" , "username" : "user1" , "mobilealias" : "" , "lastactivitydate" : null , "displayname" : "" , "rememberme" : false }]
In the action of the controller, if the method signature is public jsonresult createuser (userdataobject user), only 1st data entries can be received when multiple data entries are passed in; when the method signature is private list <userdataobject> processusers (list <userdataobject> users), there is no problem when there are multiple data entries. If there is only one data entry, users is null.
I thought of writing both methods directly in action, but the result is system. reflection. ambiguousmatchexception, that is, the MVC actionselector can no longer distinguish which method to call.
Find the MVCCodeIt is found that in the runselectionfilters method of asyncactionmethodselector, The atrriters method on the action will be searched. attributes such as httppost will be filtered to determine whether they meet the context of the current call.
After knowing this, I think we can write a custom attribute and decide which method is available and which method is unavailable based on the content of the current request, there are two key points to achieve this:
1. How to implement this attribute.
2. How to obtain and solve the post content of the request.
1st problems are well solved, because I have not systematically read MVC information, so I can check httppost to know That it inherits actionmethodselectorattribute, and there is an abstract method isvalidforrequest in this class.
After obtaining the request for 2nd questions, determine whether the current post type is application/JSON and deserialize the post data in JSON format. Tests show that if a single object is used, the deserialized object is a dictionay <string, Object> object, and multiple objects get an object []. The source code is provided below:
Public Class Jsonmodelpostattriattribute: actionmethodselectorattribute { Public Enum Parametertype {single, multiple} Private Parametertype _ parametertype; Public Parametertype methodparametertype {get { Return _ Parametertype;} set {_ parametertype = Value ;}} Public Jsonmodelpostattribute () {_ parametertype = parametertype. Single ;} Public Jsonmodelpostattribute (parametertype type) {_ parametertype = type ;} Public Override Bool Isvalidforrequest (controllercontext, system. reflection. methodinfo) {var c = getdeserializedobject (controllercontext ); If (C = Null ){ Return True ;} If (Methodparametertype = parametertype. Single ){ Return C Is Dictionary < String , Object > ;} Else { Return C Is Object [] ;}} Private Static Object Getdeserializedobject (controllercontext ){ If (! Controllercontext. httpcontext. Request. contenttype. startswith ( "Application/JSON" , Stringcomparison. ordinalignorecase )){// Not JSON request Return Null ;} Controllercontext. httpcontext. Request. inputstream. Seek (0, seekorigin. Begin); streamreader reader = New Streamreader (controllercontext. httpcontext. Request. inputstream ); String Bodytext = reader. readtoend (); controllercontext. httpcontext. Request. inputstream. Seek (0, seekorigin. Begin ); If (String. isnullorempty (bodytext )){ // No JSON data Return Null ;} Javascriptserializer serializer =New Javascriptserializer (); Object Jsondata = serializer. deserializeobject (bodytext ); Return Jsondata ;}}
Note that after inputstream is read, the position must be set to 0 again. Otherwise, the subsequent jsonvalueproviderfactory will not be able to reverse the instance, even if it can enter the correct action, the parameter is also null.
The following is the test code snippet in controller:
[Allowanonymous] [httppost] [jsonmodelpost (jsonmodelpostattriple. parametertype. Multiple)] Public Jsonresult createuser (list <userdataobject> Users) {processusers (users ); Return This . JSON ( New {Success = True , User = users}, jsonrequestbehavior. allowget );} Private List <userdataobject> processusers (list <userdataobject> Users ){ Int I = 1; Foreach (VAR user In Users) {user. ID = guid. Empty. tostring (); User. Username = "Server name" + I ++ ;} Return Users;} [allowanonymous] [httppost] [jsonmodelpost (jsonmodelpostattribute. parametertype. Single)] Public Jsonresult createuser (userdataobject user) {var list = New List <userdataobject> ( New Userdataobject [] {user}); processusers (list ); Return This . JSON ( New {Success = True , User = list [0]}, jsonrequestbehavior. allowget );}