2016-11-03 5 views
-1

Ich habe ein Szenario, wo ich Daten von 10000 Menschen von einer API erhalten müssen. Leider hat der API-Anbieter kein Paging (traurig). Jetzt muss ich beim Umgang mit diesem Fall sehr vorsichtig sein. Alles, was ich tun möchte, ist, diese Daten herunterzuladen und in JArray für den weiteren Prozess zu speichern, den ich für jedes Objekt machen möchte.Erhalten große Antwort von einer API mit HttpClient und Speichern in JArray

Ich habe versucht, jede andere Best Practice zu folgen, um große Daten mit HttpClient zu holen und in JArray zu speichern, aber ich habe System.OutOfMemoryException auf Newtonsoft.Json.

Hier ist, wie mein Code-Block sieht aus wie -

public async Task<JArray> GetContactsObject(ConnectorToken token) 
{ 
     JArray contacts = new JArray(); 

     try 
     { 
      using (var client = new HttpClient()) 
      { 

       client.Timeout = TimeSpan.FromMinutes(10); 

       string requestUrl = "<api_uri>"; 


       client.DefaultRequestHeaders.Add("Authorization", GenearateHeaders("GET", requestUrl, token)); 

       client.DefaultRequestHeaders.TryAddWithoutValidation("Accept", "application/json"); 

       using (Stream s = await client.GetStreamAsync(requestUrl)) 
       using (StreamReader sr = new StreamReader(s)) 
       using (JsonReader reader = new JsonTextReader(sr)) 
       { 
        contacts = JArray.Load(reader); 
       } 
      } 
     } 
     catch (Exception ex) 
     { 
      _logger.Fatal(ex); 
     } 
     return contacts; 
} 

Was genau mache ich falsch? Die API-Antwort ist riesig, es hat 10.000 Kontakte und ca. Größe der Antwort ist ca. 70-80 MB.

Aktualisiert Schnipsel - nach wie vor wirft Ausnahme, sondern eine Verbesserung würde ich

public async Task<MailPlusContacts> GetContactsObject(ConnectorToken token) 
     { 
      MailPlusContacts contacts = new MailPlusContacts(); 

      try 
      { 
       using (var client = new HttpClient()) 
       { 

        client.Timeout = TimeSpan.FromMinutes(10); 

        string requestUrl = "<api_uri>"; 


        client.DefaultRequestHeaders.Add("Authorization", GenearateHeaders("GET", requestUrl, token)); 

        client.DefaultRequestHeaders.TryAddWithoutValidation("Accept", "application/json"); 



        using (Stream s = await client.GetStreamAsync(requestUrl)) 
        using (StreamReader sr = new StreamReader(s)) 
        using (JsonTextReader reader = new JsonTextReader(sr)) 
        { 

         while (reader.Read()) 
         { 
          if (reader.TokenType == JsonToken.StartObject) 
          { 
           // Load each object from the stream and do something with it 
           JObject obj = JObject.Load(reader); 
           contacts.Contacts.Add(obj); 
          } 


         } 
        } 

       } 
      } 
      catch (Exception ex) 
      { 


      } 

      return contacts; 
     } 

Beispiel JSON sagen (1 Objekt, 10k davon betrachten)

[ 
    { 
     "externalId": "4D8C802F4DE244248D97E8C80F628AF3", 
     "created": 1471413089000, 
     "encryptedId": "bbhjZi4UYIiYnnZ", 
     "testGroup": false, 
     "lastChanged": 1476683221000, 
     "temporary": false, 
     "properties": { 
      "prop1": "11:09", 
      "birthdate": "1991-07-01", 
      "freeField1": "*1000000000*", 
      "freeField2": "Y", 
      "street": "Shivaji Nagar", 
      "houseNumber": "123", 
      "city": "Pune", 
      "list4": [ 
       { 
        "description": "dropdown item", 
        "bit": 1, 
        "enabled": false 
       }, 
       { 
        "description": "dropdown item 2", 
        "bit": 2, 
        "enabled": false 
       }, 
       { 
        "description": "dropdown item 3", 
        "bit": 4, 
        "enabled": false 
       }, 
       { 
        "description": "dropdown item 23-1-2016", 
        "bit": 8, 
        "enabled": false 
       }, 
       { 
        "description": "dropdown item 2 23-1-2016", 
        "bit": 16, 
        "enabled": false 
       }, 
       { 
        "description": "dropdown item 2 27-1-2016", 
        "bit": 32, 
        "enabled": false 
       }, 
       { 
        "description": "Meeloopdagen", 
        "bit": 64, 
        "enabled": false 
       }, 
       { 
        "description": "dropdown item 2 5-3-2016", 
        "bit": 128, 
        "enabled": false 
       }, 
       { 
        "description": "dropdown item 5-3-2016", 
        "bit": 256, 
        "enabled": true 
       }, 
       { 
        "description": "dropdown item 2 Chemie 1-3-2016", 
        "bit": 512, 
        "enabled": false 
       }, 
       { 
        "description": "dropdown item 2 Chemie 8-3-2016", 
        "bit": 1024, 
        "enabled": false 
       }, 
       { 
        "description": "dropdown item 23-4-2016", 
        "bit": 2048, 
        "enabled": false 
       }, 
       { 
        "description": "dropdown item 2 23-4-2016", 
        "bit": 4096, 
        "enabled": false 
       } 
      ], 
      "list5": [ 
       { 
        "description": "Ja", 
        "bit": 1, 
        "enabled": true 
       }, 
       { 
        "description": "Nee", 
        "bit": 2, 
        "enabled": false 
       } 
      ], 
      "list2": [ 
       { 
        "description": "Test Werk en Test", 
        "bit": 1, 
        "enabled": false 
       }, 
       { 
        "description": "Test Test Test", 
        "bit": 2, 
        "enabled": false 
       }, 
       { 
        "description": "Test Psychologie", 
        "bit": 4, 
        "enabled": false 
       }, 
       { 
        "description": "Test Therapie", 
        "bit": 8, 
        "enabled": false 
       }, 
       { 
        "description": "Test", 
        "bit": 16, 
        "enabled": false 
       }, 
       { 
        "description": "Test", 
        "bit": 32, 
        "enabled": false 
       }, 
       { 
        "description": "Bio-Test", 
        "bit": 64, 
        "enabled": false 
       }, 
       { 
        "description": "Test", 
        "bit": 128, 
        "enabled": false 
       }, 
       { 
        "description": "Test Economie", 
        "bit": 256, 
        "enabled": false 
       }, 
       { 
        "description": "Test", 
        "bit": 512, 
        "enabled": false 
       }, 
       { 
        "description": "HBO-Test", 
        "bit": 1024, 
        "enabled": false 
       }, 
       { 
        "description": "Sociaal Test Test", 
        "bit": 2048, 
        "enabled": false 
       }, 
       { 
        "description": "Human Test Test", 
        "bit": 4096, 
        "enabled": false 
       }, 
       { 
        "description": "Test en Test", 
        "bit": 8192, 
        "enabled": false 
       }, 
       { 
        "description": "Test", 
        "bit": 16384, 
        "enabled": false 
       } 
      ], 
      "postalCode": "1201AX", 
      "list3": [ 
       { 
        "description": "Test 1", 
        "bit": 1, 
        "enabled": false 
       }, 
       { 
        "description": "Test 1", 
        "bit": 2, 
        "enabled": false 
       }, 
       { 
        "description": "DTest 1", 
        "bit": 4, 
        "enabled": false 
       }, 
       { 
        "description": "Test 1", 
        "bit": 8, 
        "enabled": false 
       }, 
       { 
        "description": "LTest 1", 
        "bit": 16, 
        "enabled": false 
       }, 
       { 
        "description": "Test 1", 
        "bit": 32, 
        "enabled": false 
       }, 
       { 
        "description": "PTest 1", 
        "bit": 64, 
        "enabled": false 
       }, 
       { 
        "description": "Test 1", 
        "bit": 128, 
        "enabled": false 
       }, 
       { 
        "description": "STest 1", 
        "bit": 256, 
        "enabled": false 
       }, 
       { 
        "description": "TTest 1", 
        "bit": 512, 
        "enabled": false 
       }, 
       { 
        "description": "MTest 1", 
        "bit": 1024, 
        "enabled": false 
       }, 
       { 
        "description": "KTest 1", 
        "bit": 2048, 
        "enabled": false 
       }, 
       { 
        "description": "Test 1", 
        "bit": 4096, 
        "enabled": false 
       }, 
       { 
        "description": "Test 1e", 
        "bit": 8192, 
        "enabled": false 
       }, 
       { 
        "description": "Test 1", 
        "bit": 16384, 
        "enabled": false 
       }, 
       { 
        "description": "Test 1n", 
        "bit": 32768, 
        "enabled": false 
       }, 
       { 
        "description": "PTest 1jk", 
        "bit": 65536, 
        "enabled": false 
       }, 
       { 
        "description": "BTest 1a", 
        "bit": 131072, 
        "enabled": false 
       }, 
       { 
        "description": "BTest 1ek ", 
        "bit": 262144, 
        "enabled": false 
       }, 
       { 
        "description": "Test 1", 
        "bit": 524288, 
        "enabled": false 
       }, 
       { 
        "description": "Test 1", 
        "bit": 1048576, 
        "enabled": false 
       }, 
       { 
        "description": "Test 1 Economie", 
        "bit": 2097152, 
        "enabled": false 
       }, 
       { 
        "description": "Test ", 
        "bit": 4194304, 
        "enabled": true 
       }, 
       { 
        "description": "HBO-Test", 
        "bit": 8388608, 
        "enabled": false 
       }, 
       { 
        "description": "Test Test Test", 
        "bit": 16777216, 
        "enabled": false 
       }, 
       { 
        "description": "Test in de Test", 
        "bit": 33554432, 
        "enabled": false 
       }, 
       { 
        "description": "Test Resource Test", 
        "bit": 67108864, 
        "enabled": false 
       }, 
       { 
        "description": "Test Test", 
        "bit": 134217728, 
        "enabled": false 
       } 
      ], 
      "phoneNumber": "0793631212", 
      "initials": "Rahul", 
      "list1": [ 
       { 
        "description": "Test 1", 
        "bit": 1, 
        "enabled": false 
       }, 
       { 
        "description": "Test 2", 
        "bit": 2, 
        "enabled": false 
       }, 
       { 
        "description": "Test 3", 
        "bit": 4, 
        "enabled": true 
       }, 
       { 
        "description": "Test 4", 
        "bit": 8, 
        "enabled": false 
       }, 
       { 
        "description": "Test 5", 
        "bit": 16, 
        "enabled": false 
       }, 
       { 
        "description": "Test 6", 
        "bit": 32, 
        "enabled": false 
       }, 
       { 
        "description": "tet7 ", 
        "bit": 64, 
        "enabled": false 
       }, 
       { 
        "description": "Test 8", 
        "bit": 128, 
        "enabled": false 
       }, 
       { 
        "description": "Test 1", 
        "bit": 256, 
        "enabled": false 
       }, 
       { 
        "description": "Test 1", 
        "bit": 512, 
        "enabled": false 
       }, 
       { 
        "description": "Test 1", 
        "bit": 1024, 
        "enabled": false 
       }, 
       { 
        "description": "Test 1", 
        "bit": 2048, 
        "enabled": false 
       }, 
       { 
        "description": "Test 1", 
        "bit": 4096, 
        "enabled": false 
       }, 
       { 
        "description": "Test 1", 
        "bit": 8192, 
        "enabled": false 
       }, 
       { 
        "description": "Test 1", 
        "bit": 16384, 
        "enabled": false 
       }, 
       { 
        "description": "Test 1", 
        "bit": 32768, 
        "enabled": false 
       }, 
       { 
        "description": "Test 1", 
        "bit": 65536, 
        "enabled": false 
       }, 
       { 
        "description": "Test 1", 
        "bit": 131072, 
        "enabled": false 
       }, 
       { 
        "description": "Test 1", 
        "bit": 262144, 
        "enabled": false 
       }, 
       { 
        "description": "Test 1", 
        "bit": 524288, 
        "enabled": false 
       }, 
       { 
        "description": "Test 1", 
        "bit": 1048576, 
        "enabled": true 
       }, 
       { 
        "description": "Test 1 Economie", 
        "bit": 2097152, 
        "enabled": false 
       }, 
       { 
        "description": "Test 1", 
        "bit": 4194304, 
        "enabled": false 
       }, 
       { 
        "description": "HBO-Test 1", 
        "bit": 8388608, 
        "enabled": false 
       }, 
       { 
        "description": "Test 1 ", 
        "bit": 16777216, 
        "enabled": false 
       }, 
       { 
        "description": "Test 1", 
        "bit": 33554432, 
        "enabled": false 
       }, 
       { 
        "description": "Test 1", 
        "bit": 67108864, 
        "enabled": false 
       }, 
       { 
        "description": "Test 1", 
        "bit": 134217728, 
        "enabled": false 
       } 
      ], 
      "gender": "M", 
      "firstName": "Rahul Patil", 
      "list6": [ 
       { 
        "description": "Test", 
        "bit": 1, 
        "enabled": false 
       }, 
       { 
        "description": "Test ", 
        "bit": 2, 
        "enabled": false 
       }, 
       { 
        "description": "Test ", 
        "bit": 4, 
        "enabled": false 
       }, 
       { 
        "description": "Test ", 
        "bit": 8, 
        "enabled": false 
       }, 
       { 
        "description": "Test Test", 
        "bit": 16, 
        "enabled": false 
       }, 
       { 
        "description": "Test", 
        "bit": 32, 
        "enabled": false 
       }, 
       { 
        "description": "Test Test Test", 
        "bit": 64, 
        "enabled": false 
       }, 
       { 
        "description": "Test-Test Test", 
        "bit": 128, 
        "enabled": false 
       }, 
       { 
        "description": "Test in de Test", 
        "bit": 256, 
        "enabled": false 
       }, 
       { 
        "description": "Test Test Test Test", 
        "bit": 512, 
        "enabled": false 
       }, 
       { 
        "description": "Test Test", 
        "bit": 1024, 
        "enabled": false 
       }, 
       { 
        "description": "Test Test en Test", 
        "bit": 2048, 
        "enabled": false 
       }, 
       { 
        "description": "Test Therapie", 
        "bit": 4096, 
        "enabled": false 
       }, 
       { 
        "description": "Test", 
        "bit": 8192, 
        "enabled": false 
       }, 
       { 
        "description": "Test Resource Test", 
        "bit": 16384, 
        "enabled": false 
       }, 
       { 
        "description": "HBO-Test", 
        "bit": 32768, 
        "enabled": false 
       }, 
       { 
        "description": "Test", 
        "bit": 65536, 
        "enabled": false 
       }, 
       { 
        "description": "Test Test", 
        "bit": 131072, 
        "enabled": false 
       }, 
       { 
        "description": "Test", 
        "bit": 262144, 
        "enabled": false 
       }, 
       { 
        "description": "Test", 
        "bit": 524288, 
        "enabled": false 
       }, 
       { 
        "description": "Bio-Test", 
        "bit": 1048576, 
        "enabled": false 
       }, 
       { 
        "description": "Test en Test Test", 
        "bit": 2097152, 
        "enabled": false 
       } 
      ], 
      "date1": "2016-09-30", 
      "lastName": "Patil", 
      "organisation": "Test Organization", 
      "email": "[email protected]", 
      "vrij15": "N", 
      "profileFields": [ 
       { 
        "description": "testField", 
        "bit": 1, 
        "enabled": false 
       }, 
       { 
        "description": "test1", 
        "bit": 2, 
        "enabled": true 
       } 
      ], 
      "profileField2": "asd", 
      "numeric1": "10", 
      "profileField1": "asd", 
      "profileField3": "asd" 
     }, 
     "channels": [ 
      { 
       "name": "EMAIL", 
       "value": true 
      }, 
      { 
       "name": "SMS", 
       "value": false 
      } 
     ] 
    } 
] 
+0

Wie auch immer, Sie sollten jedes JSON-Token mit 'reader' verarbeiten und nur die notwendigen Werte in einer Liste oder einem Dictionary speichern, anstatt das gesamte Array zu analysieren. Werfen Sie einen Blick [Lesen Sie JSON mit JsonTextReader] (http: //www.newtonsoft.com).com/json/help/html/readjsonwithjsontextreader.htm) – wdosanjos

+0

@wdosanjos sollten Sie eine echte Antwort schreiben. – Soviut

+1

Ich denke, das ist "Kontakte = JArray.Load (Leser);" ist der Schuldige. Deine Erinnerung geht weit über 80 MB. Vielleicht möchten Sie [Flat buffers] (https://google.github.io/flatbuffers/) betrachten – peter

Antwort

0

Die Antwort sein kann "nur" 80MB (das ist eine enorme Textantwort), aber um dies als eine Hierarchie von Objekten im Speicher darzustellen, kann erheblich mehr Platz beansprucht werden.

JSON.NET kann aus einem Stream deserialisieren, sodass die gesamte Zeichenfolge nicht in den Speicher geladen wird. Stattdessen ist der wahrscheinlichste Täter die Tatsache, dass Sie alles in einer einzigen contacts Variablen speichern und eine JArray höchstwahrscheinlich jeden Kindknoten darin analysiert.

Hier sind einige JSON.NET performance tips zum Schutz vor zu wenig Arbeitsspeicher.

1

Höchstwahrscheinlich müssen Sie das Objekt manuell aufteilen. Das Parsing, das bei der Erstellung von 'JObject.Load (reader) auftritt;' ist in diesem Fall massiv.

Oder ihre Probleme mit dem JObject sein, das eine bestimmte Menge wächst, die dynamische Größenänderung für wirklich große Gegenstände kann Probleme verursachen.

Ich würde wetten, dass Sie mehr Glück haben, es als eine Schnur hereinzuziehen.

//Read raw json as a string from the body of the HTTP post, and don’t parse it 
string results = await Request.Content.ReadAsStringAsync(); 

Es ist möglich, dass die Analyse dieser massiven Zeichenfolge würde besser analysieren, wenn es eine Zeichenfolge zuerst ist.

Aber Sie könnten finden, es ist immer noch zu groß, zu welcher Zeit Sie einen Teil der Analyse selbst tun wollen. Tun es die „Spaß“ Art und Weise, wie ich es nennen:

ein Startobjekt des Arrays finden Sie dann die Klammern Beispiel zählen: wenn Ihre Daten

{"employees":[ 
    {"firstName":"John", "lastName":"Doe"}, 
    {"firstName":"Anna", "lastName":"Smith"}, 
    {"firstName":"Peter", "lastName":"Jones"} 
]} 

zurück Sie würden dies tun wollen:

var headerIndex = '{"employees":['.Length; 
var startIndex = result.IndexOf('{',headerIndex); 
if(startIndex != -1) 
{ 
    var bracketcount = 1; 
    int rowCount; 
    for(rowCount = 0; i < int.MaxValue && bracketcount != 0) 
    { 
     if (result[i] == '{') bracketcount++; 
     if(result[i] == '}') bracketcount--; 
    } 

    var smallerObjectString = result.SubString(0,rowCount); 
    //create a single object and handle it 
+0

Ich werde es versuchen ... ;-) –

Verwandte Themen