Próbuję połączyć się z interfejsem API, który zwraca kod JSON GZip z usługi WCF (usługa WCF do usługi WCF). Używam HTTPClient do łączenia się z interfejsem API i mogłem zwrócić obiekt JSON jako ciąg. Jednak muszę być w stanie przechowywać te zwrócone dane w bazie danych i jako taki doszedłem do wniosku, że najlepszym sposobem byłoby zwrócenie i przechowywanie obiektu JSON w tablicy lub bajcie lub coś w tych wierszach.
W szczególności mam problem z dekompresją kodowania GZip i próbowałem wielu różnych przykładów, ale nadal nie mogę go zdobyć.
Poniższy kod przedstawia sposób nawiązywania połączenia i uzyskiwania odpowiedzi, jest to kod, który zwraca ciąg znaków z interfejsu API.
public string getData(string foo)
{
string url = "";
HttpClient client = new HttpClient();
HttpResponseMessage response;
string responseJsonContent;
try
{
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
response = client.GetAsync(url + foo).Result;
responseJsonContent = response.Content.ReadAsStringAsync().Result;
return responseJsonContent;
}
catch (Exception ex)
{
System.Windows.Forms.MessageBox.Show(ex.Message);
return "";
}
}
Podążałem za kilkoma różnymi przykładami, takimi jak te StackExchange API , MSDN i kilka na stackoverflow, ale nie udało mi się uzyskać żadnego z nich do pracy.
Jaki jest najlepszy sposób na osiągnięcie tego, czy jestem na dobrej drodze?
Dzięki chłopaki.
Odpowiedzi:
Po prostu utwórz wystąpienie HttpClient w następujący sposób:
HttpClientHandler handler = new HttpClientHandler() { AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate }; using (var client = new HttpClient(handler)) { // your code }
Aktualizacja z 19 czerwca 2020 r .: Nie zaleca się używania httpclient w bloku „using”, ponieważ może to spowodować wyczerpanie portu.
private static HttpClient client = null; ContructorMethod() { if(client == null) { HttpClientHandler handler = new HttpClientHandler() { AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate }; client = new HttpClient(handler); } // your code }
Jeśli używasz .Net Core 2.1+, rozważ użycie IHttpClientFactory i wstrzyknięcie w ten sposób w kodzie startowym.
var timeout = Policy.TimeoutAsync<HttpResponseMessage>( TimeSpan.FromSeconds(60)); services.AddHttpClient<XApiClient>().ConfigurePrimaryHttpMessageHandler(() => new HttpClientHandler { AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate }).AddPolicyHandler(request => timeout);
źródło
HttpClient
NIE należy używać wewnątrzusing
Ok, więc ostatecznie rozwiązałem swój problem. Jeśli są lepsze sposoby, daj mi znać :-)
public DataSet getData(string strFoo) { string url = "foo"; HttpClient client = new HttpClient(); HttpResponseMessage response; DataSet dsTable = new DataSet(); try { //Gets the headers that should be sent with each request client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json")); //Returned JSON response = client.GetAsync(url).Result; //converts JSON to string string responseJSONContent = response.Content.ReadAsStringAsync().Result; //deserializes string to list var jsonList = DeSerializeJsonString(responseJSONContent); //converts list to dataset. Bad name I know. dsTable = Foo_ConnectAPI.ExtentsionHelpers.ToDataSet<RootObject>(jsonList); //Returns the dataset return dsTable; } catch (Exception ex) { System.Windows.Forms.MessageBox.Show(ex.Message); return null; } } //deserializes the string to a list. Utilizes JSON.net. RootObject is a class that contains the get and set for the JSON elements public List<RootObject> DeSerializeJsonString(string jsonString) { //Initialized the List List<RootObject> list = new List<RootObject>(); //json.net deserializes string list = (List<RootObject>)JsonConvert.DeserializeObject<List<RootObject>>(jsonString); return list; }
RootObject zawiera zestaw pobierania, który pobierze wartości JSON.
public class RootObject { //These string will be set to the elements within the JSON. Each one is directly mapped to the JSON elements. //This only takes into account a JSON that doesn't contain nested arrays public string EntityID { get; set; } public string Address1 { get; set; } public string Address2 { get; set; } public string Address3 { get; set; } }
Najłatwiejszym sposobem utworzenia powyższych klas jest użycie json2charp, które odpowiednio ją sformatuje i dostarczy również poprawne typy danych.
Poniższy tekst pochodzi z innej odpowiedzi na Stackoverflow i ponownie nie uwzględnia zagnieżdżonego formatu JSON.
internal static class ExtentsionHelpers { public static DataSet ToDataSet<T>(this List<RootObject> list) { try { Type elementType = typeof(RootObject); DataSet ds = new DataSet(); DataTable t = new DataTable(); ds.Tables.Add(t); try { //add a column to table for each public property on T foreach (var propInfo in elementType.GetProperties()) { try { Type ColType = Nullable.GetUnderlyingType(propInfo.PropertyType) ?? propInfo.PropertyType; t.Columns.Add(propInfo.Name, ColType); } catch (Exception ex) { System.Windows.Forms.MessageBox.Show(ex.Message); } } } catch (Exception ex) { System.Windows.Forms.MessageBox.Show(ex.Message); } try { //go through each property on T and add each value to the table foreach (RootObject item in list) { DataRow row = t.NewRow(); foreach (var propInfo in elementType.GetProperties()) { row[propInfo.Name] = propInfo.GetValue(item, null) ?? DBNull.Value; } t.Rows.Add(row); } } catch (Exception ex) { System.Windows.Forms.MessageBox.Show(ex.Message); } insert.insertCategories(t); return ds. } catch (Exception ex) { System.Windows.Forms.MessageBox.Show(ex.Message); return null; } } };
Na koniec, aby wstawić powyższy zestaw danych do tabeli z kolumnami, które zostały zmapowane na JSON, użyłem kopii zbiorczej SQL i następującej klasy
public class insert { public static string insertCategories(DataTable table) { SqlConnection objConnection = new SqlConnection(); //As specified in the App.config/web.config file objConnection.ConnectionString = System.Configuration.ConfigurationManager.ConnectionStrings["foo"].ToString(); try { objConnection.Open(); var bulkCopy = new SqlBulkCopy(objConnection.ConnectionString); bulkCopy.DestinationTableName = "dbo.foo"; bulkCopy.BulkCopyTimeout = 600; bulkCopy.WriteToServer(table); return ""; } catch (Exception ex) { System.Windows.Forms.MessageBox.Show(ex.Message); return ""; } finally { objConnection.Close(); } } };
Więc powyższe działa, aby wstawić JSON z interfejsu webAPI do bazy danych. To jest coś, co zabieram do pracy. Ale w żadnym wypadku nie oczekuję, że będzie doskonały. Jeśli masz jakieś ulepszenia, zaktualizuj je odpowiednio.
źródło
HttpClient
i swoje oświadczenieHttpResponse
wewnętrzne,using()
aby zapewnić właściwe, terminowe usunięcie i zamknięcie podstawowych strumieni.Użyłem kodu z poniższego linku, aby zdekompresować strumień GZip, a następnie użyłem zdekompresowanej tablicy bajtów, aby uzyskać wymagany obiekt JSON. Mam nadzieję, że to komuś pomoże.
var readTask = result.Content.ReadAsByteArrayAsync().Result; var decompressedData = Decompress(readTask); string jsonString = System.Text.Encoding.UTF8.GetString(decompressedData, 0, decompressedData.Length); ResponseObjectClass responseObject = Newtonsoft.Json.JsonConvert.DeserializeObject<ResponseObjectClass>(jsonString);
https://www.dotnetperls.com/decompress
static byte[] Decompress(byte[] gzip) { using (GZipStream stream = new GZipStream(new MemoryStream(gzip), CompressionMode.Decompress)) { const int size = 4096; byte[] buffer = new byte[size]; using (MemoryStream memory = new MemoryStream()) { int count = 0; do { count = stream.Read(buffer, 0, size); if (count > 0) { memory.Write(buffer, 0, count); } } while (count > 0); return memory.ToArray(); } } }
źródło