Giải nén GZip Stream từ HTTPClient Response


93

Tôi đang cố gắng kết nối với một api trả về JSON được mã hóa GZip, từ dịch vụ WCF (dịch vụ WCF đến dịch vụ WCF). Tôi đang sử dụng HTTPClient để kết nối với API và có thể trả về đối tượng JSON dưới dạng một chuỗi. Tuy nhiên, tôi cần có khả năng lưu trữ dữ liệu trả về này trong cơ sở dữ liệu và như vậy, tôi đã tìm ra cách tốt nhất là trả lại và lưu trữ đối tượng JSON trong một mảng hoặc byte hoặc thứ gì đó dọc theo các dòng đó.

Điều tôi đang gặp khó khăn cụ thể là giải nén mã GZip và đã thử rất nhiều ví dụ khác nhau nhưng vẫn không thể hiểu được.

Đoạn mã dưới đây là cách tôi thiết lập kết nối của mình và nhận được phản hồi, đây là mã trả về một chuỗi từ 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 "";
    }
}

Tôi đã theo dõi một số ví dụ khác nhau như API StackExchange , MSDN và một vài ví dụ trên stackoverflow, nhưng tôi không thể làm cho bất kỳ ví dụ nào trong số này hoạt động cho mình.

Cách tốt nhất để thực hiện điều này là gì, liệu tôi có đang đi đúng hướng không?

Cảm ơn các bạn.


"cách tốt nhất là trả về và lưu trữ đối tượng JSON trong một mảng hoặc byte" Lưu ý rằng một chuỗi là một mảng các byte.
user3285954 18/09/18

Câu trả lời:


232

Chỉ cần tạo HttpClient như thế này:

HttpClientHandler handler = new HttpClientHandler()
{
    AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate
};

using (var client = new HttpClient(handler))
{
    // your code
}

Cập nhật ngày 19 tháng 6 năm 2020: Không nên sử dụng httpclient trong khối 'đang sử dụng' vì nó có thể gây cạn kiệt cổng.

private static HttpClient client = null;

ContructorMethod()
{
   if(client == null)
   {
        HttpClientHandler handler = new HttpClientHandler()
        {
            AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate
        };        
        client = new HttpClient(handler);
   }
// your code            
 }

Nếu sử dụng .Net Core 2.1+, hãy cân nhắc sử dụng IHttpClientFactory và chèn như thế này vào mã khởi động của bạn.

 var timeout = Policy.TimeoutAsync<HttpResponseMessage>(
            TimeSpan.FromSeconds(60));

 services.AddHttpClient<XApiClient>().ConfigurePrimaryHttpMessageHandler(() => new HttpClientHandler
        {
            AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate
        }).AddPolicyHandler(request => timeout);

Nếu tôi sử dụng cấu trúc này, làm cách nào để truy xuất nội dung phản hồi của tôi từ httpClient? Tôi siêu mới với c # và tôi không nghĩ rằng tôi đang hiểu nó.
FoxDeploy

1
@FoxDeploy không cần thay đổi mã để lấy nội dung khi bạn sử dụng giải pháp này. Xem ở đây để tham khảo: stackoverflow.com/questions/26597665/…
DIG,

1
mặc dù nó là một bài viết cũ, câu trả lời này chỉ giải quyết được vấn đề của tôi trong .netcore, chuyển từ 1.1 sang 2.0 có vẻ như khách hàng đã tự động thực hiện giải nén, vì vậy tôi đã phải thêm mã này vào 2.0 để làm cho nó hoạt động ... Cảm ơn !
Sebastian Castaldi

3
Chỉ để lấy lại @SebastianCastaldi, nhưng .net core 1.1 đã được đặt AutomaticDecompression đúng cách, nhưng trong .net core 2.0, nó được đặt thành KHÔNG. Này đã cho tôi quá nhiều thời gian để tìm ra ...
KallDrexx

5
Lưu ý: HttpClientkhông nên sử dụng bên trongusing
imba TJD-

1

Tôi đã sử dụng mã từ liên kết bên dưới để giải nén luồng GZip, sau đó sử dụng mảng byte đã giải nén để lấy đối tượng JSON cần thiết. Hy vọng nó có thể giúp một số người.

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();
        }
    }
}

0

Ok vì vậy cuối cùng tôi đã giải quyết được vấn đề của mình. Nếu có cách nào tốt hơn, vui lòng cho tôi biết :-)

        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 chứa tập hợp get sẽ nhận các giá trị của 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; }

}

Cách dễ nhất để tạo (các) lớp trên là sử dụng json2charp sẽ định dạng nó cho phù hợp và cũng cung cấp các kiểu dữ liệu chính xác.

Sau đây là từ một câu trả lời khác trên Stackoverflow, nó không tính đến JSON lồng nhau.

    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;
        }
    }
};

Sau đó, cuối cùng để chèn tập dữ liệu ở trên vào một bảng có các cột được ánh xạ tới JSON, tôi đã sử dụng bản sao hàng loạt SQL và lớp sau

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();
        }         
    }
};

Vì vậy, ở trên hoạt động để chèn JSON từ webAPI vào cơ sở dữ liệu. Đây là điều mà tôi phải làm việc. Nhưng không có nghĩa là tôi mong đợi nó hoàn hảo. Nếu bạn có bất kỳ cải tiến nào thì hãy cập nhật nó cho phù hợp.


2
Bạn nên tạo một câu lệnh bên trong HttpClientcủa mình và của bạn để đảm bảo việc xử lý đúng, kịp thời và đóng các luồng bên dưới. HttpResponseusing()
Ian Mercer
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.