POSTing JsonObject с помощью HttpClient из веб-API

Я пытаюсь JsonObject с помощью HttpClient из веб-API. Я не совсем уверен, как это сделать, и не могу найти много примеров кода.

Вот что у меня так далеко:

var myObject = (dynamic)new JsonObject();
myObject.Data = "some data";
myObject.Data2 = "some more data";

HttpClient httpClient = new HttpClient("myurl");
httpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));

HttpResponseMessage response = httpClient.Post("", ???);

Я думаю, что мне нужно бросить JsonObject как StreamContent но я зацикливаюсь на этом шаге.

12 ответов

Решение

С новой версией HttpClient и без пакета WebApi это будет:

var content = new StringContent(jsonObject.ToString(), Encoding.UTF8, "application/json");
var result = client.PostAsync(url, content).Result;

Или, если вы хотите, чтобы это было асинхронно:

var result = await client.PostAsync(url, content);

Самый простой способ - это использовать StringContent, с представлением JSON вашего объекта JSON.

httpClient.Post(
    "",
    new StringContent(
        myObject.ToString(),
        Encoding.UTF8,
        "application/json"));

В зависимости от вашей версии.NET вы также можете использовать HttpClientExtensions.PostAsJsonAsync метод.

https://msdn.microsoft.com/en-us/library/system.net.http.httpclientextensions.postasjsonasync.aspx

При использовании Newtonsoft.Json:

using Newtonsoft.Json;
using System.Net.Http;
using System.Text;

public static class Extensions
{
 public static StringContent AsJson(this object o)
  => new StringContent(JsonConvert.SerializeObject(o), Encoding.UTF8, "application/json");
}

Пример:

var httpClient = new HttpClient();
var url = "https://www.duolingo.com/2016-04-13/login?fields=";
var data = new { identifier = "username", password = "password" };
var result = await httpClient.PostAsync(url, data.AsJson())

У меня недостаточно репутации, чтобы добавить комментарий к ответу от pomber, поэтому я публикую другой ответ. Используя подход pomber, я продолжал получать ответ "400 Bad Request" от API, к которому я отправлял свой запрос JSON (Visual Studio 2017, .NET 4.6.2). В конечном итоге проблема была связана с неправильным заголовком "Content-Type", созданным StringContent() (см. https://github.com/dotnet/corefx/issues/7864).

ТЛ; др

Используйте ответ pomber с дополнительной строкой, чтобы правильно установить заголовок запроса:

var content = new StringContent(jsonObject.ToString(), Encoding.UTF8, "application/json");
content.Headers.ContentType = new MediaTypeHeaderValue("application/json");
var result = client.PostAsync(url, content).Result;

Я часами пытался решить эту проблему. Но ответ @anthls спас мою кожу.

      var data = new StringContent(JsonConvert.SerializeObject(new
                    {
                        abc = "jsjs",
                        xyz = "hhhh"
                    }));
data.Headers.ContentType = new MediaTypeHeaderValue("application/json"); // <-
var response = client.PostAsync(url, data).Result;

В моем случае я использую .NET 7.0; тотStringContentу меня не сработало. Я адаптировал некоторые из уже предоставленных ответов к своему варианту использования. я использовалJsonContentдля предоставления тела запроса POST.

      var jsonContent = JsonContent.Create(new { ... });
var response = await _client.PostAsync("/", jsonContent);

Код над ним в vbnet:

dim FeToSend as new (object--> define class)

Dim client As New HttpClient
Dim content = New StringContent(FeToSend.ToString(), Encoding.UTF8,"application/json")
content.Headers.ContentType = New MediaTypeHeaderValue( "application/json" )
Dim risp = client.PostAsync(Chiamata, content).Result

msgbox(risp.tostring)

Надеюсь это поможет

Я столкнулся с той же проблемой, т.е. var content = new StringContent(jsonObject.ToString(), Encoding.UTF8, "application/json"); выдал «400 Bad Request». Серилизация jsonObject отдельно и передача строки в StringContent() решили проблему для меня, нет необходимости устанавливать Encoding.UTF8 отдельно.

Спасибо, помбер, но за

      var result = client.PostAsync(url, content).Result;

я использовал

      var result = await client.PostAsync(url, content);

потому что Result блокирует приложение для высокого запроса

Вместо этого сделайте следующее:

      var content = new StringContent(jsonObject.ToString(), Encoding.UTF8, "application/json");

var result = client.PostAsync(url, content).Result;

Это то, что я использую. Это безопаснее

      JsonContent content = JsonContent.Create(ObjectData);

HttpResponseMessage response = await client.PostAsync(url, content);

Надеюсь, поможет

Я хочу ответить всем одним ответом, когда выполняю эту работу, в качестве примечания для всех и для себя:

Согласно ответу Сереса, список производных классов HttpContent, как показано ниже, /questions/34455048/kak-nastroit-httpcontent-dlya-moego-vtorogo-parametra-httpclient-postasync/34455055#34455055

HttpClient PostAsync имеет некоторую предысторию в зависимости от контекста, в котором вы работаете!

  • Вы можете публиковать данные по типу, который вы хотите отправить на сервер, в случаях, когда контекст сервера ожидает этого, как показано ниже
           [HttpPost]
    public async Task<IActionResult> Submit(MyModel model)
    [HttpPost]
    public async Task<IActionResult> Submit([FromForm] MyModel model)
    [HttpPost]
    public async Task<IActionResult> Submit([FromBody] MyModel model)

При написании FromForm или Body он работает как FromForm.FromBody требуется содержимое json, в противном случае KeyValuePairs требуется в виде строк. Для них обоих есть несколько реализаций, например, ниже:

Для FromForm : я использовал расширение

      public static class HelperExtensions
    {
        public static FormUrlEncodedContent ToFormData(this object obj)
        {
            var formData = obj.ToKeyValue();

            return new FormUrlEncodedContent(formData);
        }

        public static IDictionary<string, string> ToKeyValue(this object metaToken)
        {
            if (metaToken == null)
            {
                return null;
            }

            // Added by me: avoid cyclic references
            var serializer = new JsonSerializer { ReferenceLoopHandling = ReferenceLoopHandling.Ignore };
            if (metaToken is not JToken token)
            {
                // Modified by me: use serializer defined above
                return ToKeyValue(JObject.FromObject(metaToken, serializer));
            }

            if (token.HasValues)
            {
                var contentData = new Dictionary<string, string>();
                foreach (var child in token.Children().ToList())
                {
                    var childContent = child.ToKeyValue();
                    if (childContent != null)
                    {
                        contentData = contentData.Concat(childContent)
                                                 .ToDictionary(k => k.Key, v => v.Value);
                    }
                }

                return contentData;
            }

            var jValue = token as JValue;
            if (jValue?.Value == null)
            {
                return null;
            }

            var value = jValue?.Type == JTokenType.Date ?
                            jValue?.ToString("o", CultureInfo.InvariantCulture) :
                            jValue?.ToString(CultureInfo.InvariantCulture);

            return new Dictionary<string, string> { { token.Path, value } };
        }
    }

Для FromBody : используйте любую библиотеку конвертера json Newtonsoft или Microsoft.

      using Newtonsoft.Json;

var jsonString = JsonConvert.SerializeObject(obj);

В обоих из них тип контента должен быть определен в соответствии с требованиями, например для json (запись в заголовок)

      request.Headers.Accept.Clear();
request.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));

или другое использование

              using (var content = new StringContent(JsonConvert.SerializeObject(answer), System.Text.Encoding.UTF8, "application/json"))
        {
            var answerResponse = await client.PostAsync(url, content);
            //use await it has moved in some context on .core 6.0
        }

Если вам следует использовать авторизацию в контексте, вы также можете предоставить авторизацию, как показано ниже:

      httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", "Your Oauth token");
Другие вопросы по тегам