Làm cách nào để chuyển một đối tượng tới HttpClient.PostAsync và tuần tự hóa dưới dạng phần thân JSON?


93

Tôi đang sử dụng System.Net.Http, tôi đã tìm thấy một số ví dụ trên web. Tôi đã quản lý để tạo mã này để thực hiện một POSTyêu cầu:

public static string POST(string resource, string token)
{
    using (var client = new HttpClient())
    {
        client.BaseAddress = new Uri(baseUri);
        client.DefaultRequestHeaders.Add("token", token);

        var content = new FormUrlEncodedContent(new[]
        {
             new KeyValuePair<string, string>("", "")
        });

        var result = client.PostAsync("", content).Result;
        string resultContent = result.Content.ReadAsStringAsync().Result;
        return resultContent;
    }
 }

tất cả đều hoạt động tốt. Nhưng giả sử rằng tôi muốn truyền một tham số thứ ba cho POSTphương thức, một tham số được gọi data. Tham số dữ liệu là một đối tượng như sau:

object data = new
{
    name = "Foo",
    category = "article"
};

làm thế nào tôi có thể làm điều đó mà không cần tạo KeyValuePair? Php của tôi RestAPIđợi một đầu vào json, vì vậy FormUrlEncodedContentsẽ gửi rawjson một cách chính xác. Nhưng làm thế nào tôi có thể làm điều này với Microsoft.Net.Http? Cảm ơn.


Nếu tôi hiểu câu hỏi của bạn, bạn muốn gửi nội dung JSON thay vì nội dung mã hóa biểu mẫu phải không (và bằng cách mở rộng, bạn muốn loại ẩn danh của mình được tuần tự hóa dưới dạng JSON vào nội dung đó)?
CodingGorilla

@CodingGorilla vâng là một kiểu ẩn danh.
IlDrugo

3
Như một lưu ý phụ cho các độc giả trong tương lai, không sử dụng a usingcho HttpClient. aspnetmonsters.com/2016/08/2016-08-27-httpclientwrong
maxshuty 07/08/2016

2
Lưu ý từ Microsoft tại sao usingkhông nên sử dụng: HttpClient is intended to be instantiated once and reused throughout the life of an application. The following conditions can result in SocketException errors: Creating a new HttpClient instance per request. Server under heavy load. Creating a new HttpClient instance per request can exhaust the available sockets. docs.microsoft.com/en-us/aspnet/web-api/overview/advanced/…
Ogglas

Câu trả lời:


155

Câu trả lời thẳng thắn cho câu hỏi của bạn là: Không. Chữ ký của PostAsyncphương pháp như sau:

public Task PostAsync (Uri requestUri, HttpContent content)

Vì vậy, trong khi bạn có thể chuyển một objectđến PostAsyncnó phải thuộc loại HttpContentvà loại ẩn danh của bạn không đáp ứng tiêu chí đó.

Tuy nhiên, có nhiều cách để hoàn thành những gì bạn muốn. Đầu tiên, bạn sẽ cần tuần tự hóa kiểu ẩn danh của mình thành JSON, công cụ phổ biến nhất cho việc này là Json.NET . Và mã cho điều này là khá nhỏ:

var myContent = JsonConvert.SerializeObject(data);

Tiếp theo, bạn sẽ cần phải xây dựng một đối tượng nội dung để gửi dữ liệu này, tôi sẽ sử dụng một ByteArrayContentđối tượng, nhưng bạn có thể sử dụng hoặc tạo một kiểu khác nếu bạn muốn.

var buffer = System.Text.Encoding.UTF8.GetBytes(myContent);
var byteContent = new ByteArrayContent(buffer);

Tiếp theo, bạn muốn đặt loại nội dung để cho API biết đây là JSON.

byteContent.Headers.ContentType = new MediaTypeHeaderValue("application/json");

Sau đó, bạn có thể gửi yêu cầu của mình rất giống với ví dụ trước của bạn với nội dung biểu mẫu:

var result = client.PostAsync("", byteContent).Result

Một lưu ý nhỏ, việc gọi .Resulttài sản như bạn đang làm ở đây có thể có một số tác dụng phụ xấu như khóa chết, vì vậy bạn cần cẩn thận với điều này.


Được rồi, nó rất rõ ràng. Cảm ơn vì câu trả lời này. Chỉ cần một câu hỏi: khi a POST, PUT, DELETEđược thực hiện, thường là API trả về TRUE, tôi đã khai báo phương thức là string, nhưng khi thực hiện: return result;Tôi nhận được : Can't Convert HttpResponseMessage in string, Tôi có nên thay đổi khai báo phương thức không? Tôi cần phản hồi chuỗi vì tôi sẽ cần giải mã hóa nó sau khi trong phương thức lớp khác.
IlDrugo

2
Nếu bạn cần giải mã nội dung của câu trả lời, thì việc trả về chuỗi theo cách bạn có trong câu hỏi của mình (sử dụng result.Content.ReadAsStringAsync()) có lẽ là tốt. Tùy thuộc vào cấu trúc ứng dụng của bạn, có thể tốt hơn là trả về Contentđối tượng trực tiếp nếu bạn cần kiểm tra các tiêu đề để xác định loại hình nón là gì (ví dụ: XML hoặc JSON). Nhưng nếu bạn biết nó sẽ luôn trả về JSON (hoặc một số định dạng khác) thì chỉ cần trả về phần thân phản hồi dưới dạng chuỗi là được.
CodingGorilla

Xin lỗi bạn, nhưng bạn có cần phải làm điều này nếu dữ liệu thuộc loại StringContentkhông?
MyDaftQuestions

1
@MyDaftQuestions Tôi không chắc chính xác những gì bạn đang hỏi, nhưng bạn có thể chuyển StringContenttrực tiếp đến PostAsyncvì nó bắt nguồn từ HttpContent.
CodingGorilla

@CodingGorilla, đó những gì tôi đã hỏi. Cảm ơn bạn :)
MyDaftQuestions

67

Bạn cần chuyển dữ liệu của mình vào phần thân yêu cầu dưới dạng một chuỗi thô chứ không phải FormUrlEncodedContent. Một cách để làm như vậy là tuần tự hóa nó thành một chuỗi JSON:

var json = JsonConvert.SerializeObject(data); // or JsonSerializer.Serialize if using System.Text.Json

Bây giờ tất cả những gì bạn cần làm là chuyển chuỗi vào phương thức post.

var stringContent = new StringContent(json, UnicodeEncoding.UTF8, "application/json"); // use MediaTypeNames.Application.Json in Core 3.0+ and Standard 2.1+

var client = new HttpClient();
var response = await client.PostAsync(uri, stringContent);

stringContentgì? Trong trường hợp của tôi stringContentgiá trị là "\"\"". Giá trị này có đúng không?
R15

có thể lấy kết quả chuỗi trong vb từ mã c # của bạn không? tôi phát hiện ra nó khá giống nhau ....
gumuruh

42

Một giải pháp đơn giản là sử dụng Microsoft ASP.NET Web API 2.2 Clienttừ NuGet .

Sau đó, bạn chỉ cần làm điều này và nó sẽ tuần tự hóa đối tượng thành JSON và đặt Content-Typetiêu đề thành application/json; charset=utf-8:

var data = new
{
    name = "Foo",
    category = "article"
};

var client = new HttpClient();
client.BaseAddress = new Uri(baseUri);
client.DefaultRequestHeaders.Add("token", token);
var response = await client.PostAsJsonAsync("", data);

2
chắc chắn PostAsJsonAsync có để sử dụng
Kat Lim Ruiz

25

Bây giờ có một cách đơn giản hơn với .NET Standardhoặc .NET Core:

var client = new HttpClient();
var response = await client.PostAsync(uri, myRequestObject, new JsonMediaTypeFormatter());

LƯU Ý: Để sử dụng JsonMediaTypeFormatterlớp học, bạn sẽ cần cài đặt Microsoft.AspNet.WebApi.Clientgói NuGet, gói này có thể được cài đặt trực tiếp hoặc thông qua một gói khác chẳng hạn Microsoft.AspNetCore.App.

Sử dụng chữ ký này của HttpClient.PostAsync, bạn có thể chuyển vào bất kỳ đối tượng nào và JsonMediaTypeFormattersẽ tự động xử lý việc tuần tự hóa, v.v.

Với phản hồi, bạn có thể sử dụng HttpContent.ReadAsAsync<T>để giải mã nội dung phản hồi thành loại mà bạn đang mong đợi:

var responseObject = await response.Content.ReadAsAsync<MyResponseType>();

1
phiên bản .net này đang sử dụng là gì? Phiên bản của tôi không thể tìm thấy "Định dạng" trong không gian tên System.Net.Http
TemporaryFix

1
@Programmatic Bạn cần sử dụng .NET Standardhoặc .NET Core, như tôi đã đề cập. Có thể bạn đang sử dụng .NET Framework? Trong dự án của tôi, JsonMediaTypeFormatter đang được tải từ đây: C: \ Program Files \ dotnet \ sdk \ NuGetFallbackFolder \ microsoft.aspnet.webapi.client \ 5.2.6 \ lib \ netstandard2.0 \ System.Net.Http.Formatting. dll
Ken Lyon

1
@Programmatic Nếu bạn đang sử dụng một trong các loại dự án đó, có thể bạn cần thêm một gói NuGet bổ sung. Tôi quên chính xác những gì đã được đưa vào tự động cho tôi. Trong trường hợp của tôi, nó được bao gồm như một phần của gói Microsoft.AspNetCore.App NuGet.
Ken Lyon,

1
Tôi đang sử dụng .NET Core, nhưng tôi không nghĩ rằng giải pháp của tôi được thiết lập để sử dụng phiên bản mới nhất của ngôn ngữ c #. Tôi đã cập nhật và nó hoạt động. Cảm ơn bạn
Tạm

1
@Programmatic Bạn được chào đón. Tôi rất vui khi biết rằng bạn đã làm cho nó hoạt động! Tôi đã thêm ghi chú vào câu trả lời của mình về gói NuGet.
Ken Lyon
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.