Як розмістити JSON на сервері за допомогою C #?


269

Ось код, який я використовую:

// create a request
HttpWebRequest request = (HttpWebRequest)
WebRequest.Create(url); request.KeepAlive = false;
request.ProtocolVersion = HttpVersion.Version10;
request.Method = "POST";


// turn our request string into a byte stream
byte[] postBytes = Encoding.UTF8.GetBytes(json);

// this is important - make sure you specify type this way
request.ContentType = "application/json; charset=UTF-8";
request.Accept = "application/json";
request.ContentLength = postBytes.Length;
request.CookieContainer = Cookies;
request.UserAgent = currentUserAgent;
Stream requestStream = request.GetRequestStream();

// now send it
requestStream.Write(postBytes, 0, postBytes.Length);
requestStream.Close();

// grab te response and print it out to the console along with the status code
HttpWebResponse response = (HttpWebResponse)request.GetResponse();
string result;
using (StreamReader rdr = new StreamReader(response.GetResponseStream()))
{
    result = rdr.ReadToEnd();
}

return result;

Під час цього я завжди отримую 500 внутрішніх помилок сервера.

Що я роблю неправильно?


1
Спочатку переконайтеся, що дані, які ви публікуєте, - це те, що очікує сервер.
LB

насправді, схоже, я публікував недійсні дані ...
Арсен Захрай

Для зручності роботи ви можете додати бібліотеку json у свою візуальну студію
Аліреза Табатабайський

@Arsen - Сервер не повинен збої з неправильно сформованими даними. Подайте звіт про помилку.
jww

Відповіді:


396

Те, як я це роблю і працює:

var httpWebRequest = (HttpWebRequest)WebRequest.Create("http://url");
httpWebRequest.ContentType = "application/json";
httpWebRequest.Method = "POST";

using (var streamWriter = new StreamWriter(httpWebRequest.GetRequestStream()))
{
    string json = "{\"user\":\"test\"," +
                  "\"password\":\"bla\"}";

    streamWriter.Write(json);
}

var httpResponse = (HttpWebResponse)httpWebRequest.GetResponse();
using (var streamReader = new StreamReader(httpResponse.GetResponseStream()))
{
    var result = streamReader.ReadToEnd();
}

Я написав бібліотеку для виконання цього завдання більш простим способом, це тут: https://github.com/ademargomes/JsonRequest

Сподіваюся, це допомагає.


3
Я думаю, що рядок рядка json повинен бути: string json = "{\" user \ ": \" test \ "," + "\" password \ ": \" bla \ "}"; Схоже, вам не вистачає \
Dream Lane

3
Завжди використовуйте "application / json" (якщо з іншої причини не потрібен текст / json, наприклад: entwicklungsgedanken.de/2008/06/06/… ). Creding йде в: stackoverflow.com/questions/477816 / ... .
Янів

34
Я б подумав, що streamWriter.Flush (); та streamWriter.Close (); не потрібно, оскільки ви знаходитесь всередині використовуючого блоку. Після закінчення використання блоку запис потоку все одно закриється.
Ручіра

1
Не створюйте JSON вручну. Зробити помилки, які дозволяють зробити ін'єкцію JSON, легко.
Флоріан Зима

5
@ User3772108 Див stackoverflow.com/a/16380064/2279059 . Використовуйте бібліотеку JSON, таку як Newtonsoft JSON.Net, і виведіть рядок JSON з об'єкта або використовуйте серіалізацію. Я розумію, що це було пропущено тут для простоти (хоча посилення простоти мінімально), але форматування структурованих рядків даних (JSON, XML, ...) занадто небезпечно, щоб це робити навіть у тривіальних сценаріях та спонукати людей копіювати такий код .
Флоріан Зима

149

Рішення Адемар може бути поліпшена за рахунок використання JavaScriptSerializer«з Serializeметодом , щоб забезпечити неявне перетворення об'єкта в JSON.

Додатково, можна використовувати функціональні можливості usingоператора за замовчуванням, щоб опустити явний виклик Flushі Close.

var httpWebRequest = (HttpWebRequest)WebRequest.Create("http://url");
httpWebRequest.ContentType = "application/json";
httpWebRequest.Method = "POST";

using (var streamWriter = new StreamWriter(httpWebRequest.GetRequestStream()))
{
    string json = new JavaScriptSerializer().Serialize(new
                {
                    user = "Foo",
                    password = "Baz"
                });

    streamWriter.Write(json);
}

var httpResponse = (HttpWebResponse)httpWebRequest.GetResponse();
using (var streamReader = new StreamReader(httpResponse.GetResponseStream()))
{
    var result = streamReader.ReadToEnd();
}

1
Яка різниця між цим та вищезазначеним кодом, я щось пропускаю?
JMK

16
Для цього використовується метод серіалізації JavaScriptSerializer, щоб створити дійсний JSON, а не робити його ручним способом.
Шон Андерсон

Дивіться відповідь Жана Ф нижче - має бути коментар. Подбайте про те, щоб тип вмісту application/jsonбув правильним.
Лукас

@SeanAnderson У мене не виникає помилка "Не вдається підключитися до віддаленого сервера".
ralphgabb

3
@LuzanBaral вам просто потрібна збірка: System.Web.Extensions
Norbrecht

60

HttpClientТип нова реалізація , ніж WebClientта HttpWebRequest.

Ви можете просто використовувати наступні рядки.

string myJson = "{'Username': 'myusername','Password':'pass'}";
using (var client = new HttpClient())
{
    var response = await client.PostAsync(
        "http://yourUrl", 
         new StringContent(myJson, Encoding.UTF8, "application/json"));
}

введіть тут опис зображення

Коли вам потрібен ваш HttpClientне раз, рекомендується створити лише один екземпляр і повторно використовувати його або використовувати новий HttpClientFactory.


5
Невелика примітка про HttpClient, загальний консенсус полягає в тому, що не слід розпоряджатися цим. Навіть він реалізує IDisposable, об'єкт є Thread-Safe і призначений для повторного використання. stackoverflow.com/questions/15705092/…
Жан Ф.

1
@JeanF. Ей, дякую за вклад. Як я вже зазначав, ви повинні створити лише один екземпляр або використовувати HttpClientFactory. Я не прочитав усіх відповідей у ​​пов'язаному питанні, але думаю, що це потребує оновлення, оскільки це не згадує про завод.
NtFreX

33

Далі до посади Шона не потрібно вкладати висловлювання з використанням. За usingдопомогою StreamWriter він буде очищений і закритий в кінці блоку, тому не потрібно чітко викликати Flush()і Close()методи:

var request = (HttpWebRequest)WebRequest.Create("http://url");
request.ContentType = "application/json";
request.Method = "POST";

using (var streamWriter = new StreamWriter(request.GetRequestStream()))
{
    string json = new JavaScriptSerializer().Serialize(new
                {
                    user = "Foo",
                    password = "Baz"
                });

    streamWriter.Write(json);
}

var response = (HttpWebResponse)request.GetResponse();
using (var streamReader = new StreamReader(response.GetResponseStream()))
{
        var result = streamReader.ReadToEnd();
}

1
тепер ця відповідь і відповідь Шона Андерсона точно такі ж, як і Шон редагував свою посаду.
фаза

Гей, це так чудово. Дякую.Але як ми будемо передавати дані, якщо у нас на json є дочірні вузли?
користувач2728409

1
Серіалізатор може обробляти дочірні вузли в json - просто потрібно надати йому дійсний об’єкт json.
Девід Кларк

14

Якщо вам потрібно дзвонити асинхронно, тоді використовуйте

var request = HttpWebRequest.Create("http://www.maplegraphservices.com/tokkri/webservices/updateProfile.php?oldEmailID=" + App.currentUser.email) as HttpWebRequest;
            request.Method = "POST";
            request.ContentType = "text/json";
            request.BeginGetRequestStream(new AsyncCallback(GetRequestStreamCallback), request);

private void GetRequestStreamCallback(IAsyncResult asynchronousResult)
    {
        HttpWebRequest request = (HttpWebRequest)asynchronousResult.AsyncState;
        // End the stream request operation

        Stream postStream = request.EndGetRequestStream(asynchronousResult);


        // Create the post data
        string postData = JsonConvert.SerializeObject(edit).ToString();

        byte[] byteArray = Encoding.UTF8.GetBytes(postData);


        postStream.Write(byteArray, 0, byteArray.Length);
        postStream.Close();

        //Start the web request
        request.BeginGetResponse(new AsyncCallback(GetResponceStreamCallback), request);
    }

    void GetResponceStreamCallback(IAsyncResult callbackResult)
    {
        HttpWebRequest request = (HttpWebRequest)callbackResult.AsyncState;
        HttpWebResponse response = (HttpWebResponse)request.EndGetResponse(callbackResult);
        using (StreamReader httpWebStreamReader = new StreamReader(response.GetResponseStream()))
        {
            string result = httpWebStreamReader.ReadToEnd();
            stat.Text = result;
        }

    }

3
Дякуємо за публікацію цього рішення Vivek. У нашому сценарії ми спробували інше рішення у цій публікації і побачили System.Threading винятки в нашому додатку, через те, що я припускаю, що це синхронні повідомлення, що блокують потоки. Ваш код вирішив нашу проблему.
Кен Палмер

Зауважте, що вам, ймовірно, не потрібно конвертувати в байти. Ви повинні мати можливість postStream.Write(postData);- і залежно від API, можливо, доведеться використовувати request.ContentType = "application/json";замість text/json.
vapcguy


11

Нещодавно я придумав набагато простіший спосіб розмістити JSON з додатковим кроком перетворення з моделі в моєму додатку. Зауважте, що вам потрібно зробити модель [JsonObject] для вашого контролера, щоб отримати значення та здійснити перетворення.

Запит:

 var model = new MyModel(); 

 using (var client = new HttpClient())
 {
     var uri = new Uri("XXXXXXXXX"); 
     var json = new JavaScriptSerializer().Serialize(model);
     var stringContent = new StringContent(json, Encoding.UTF8, "application/json");
     var response = await Client.PutAsync(uri,stringContent).Result;
     ...
     ...
  }

Модель:

[JsonObject]
[Serializable]
public class MyModel
{
    public Decimal Value { get; set; }
    public string Project { get; set; }
    public string FilePath { get; set; }
    public string FileName { get; set; }
}

Сторона сервера:

[HttpPut]     
public async Task<HttpResponseMessage> PutApi([FromBody]MyModel model)
{
    ...
    ... 
}

6

Цей параметр не згадується:

using (var client = new HttpClient())
{
    client.BaseAddress = new Uri("http://localhost:9000/");
    client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));

    var foo = new User
    {
        user = "Foo",
        password = "Baz"
    }

    await client.PostAsJsonAsync("users/add", foo);
}

2
Ця опція більше не доступна, оскільки .Net 4.5.2. дивіться тут stackoverflow.com/a/40525794/2161568
Downhillski

Коротка відповідь на вищезазначений коментар - оскільки це недоступно, відповідь, ймовірно, має видалити.
NovaDev

1
Це не вагомий привід спростовувати цю відповідь, оскільки не всі використовують найновіші версії .net, і тому це правильна відповідь.
Еллісан

4

Якийсь інший і чистий спосіб досягти цього - використовуючи такий HttpClient:

public async Task<HttpResponseMessage> PostResult(string url, ResultObject resultObject)
{
    using (var client = new HttpClient())
    {
        HttpResponseMessage response = new HttpResponseMessage();
        try
        {
            response = await client.PostAsJsonAsync(url, resultObject);
        }
        catch (Exception ex)
        {
            throw ex
        }
        return response;
     }
}

4
Корисна, однак PostAsJsonAsyncбільше не доступна, оскільки .NET 4.5.2. Використовуйте PostAsyncзамість цього. Більше тут
Захарій Кінер

Як правило, HttpClient не повинен використовуватися в такому usingвикладі
p3tch

Я думаю, що він реалізує IDisposableінтерфейс чомусь
Діма Дарон

4

УВАГА! У мене дуже сильний погляд на цю тему.

Існуючі веб-клієнти .NET не зручні для розробників! WebRequest & WebClient - найважливіші приклади того, як "розчарувати розробника". Вони багатослівні та складні для роботи; коли все, що ви хочете зробити, це простий запит на пошту в C #. HttpClient певним чином вирішує ці проблеми, але він все ще не відповідає. Крім того, документація Microsoft погана ... дуже погано; якщо ви не хочете просіювати сторінки та сторінки технічного розмиття.

Відкритий джерело на допомогу. Є три чудові відкриті, безкоштовні бібліотеки NuGet як альтернативи. Дякувати Богові! Це все добре підтримується, задокументовано, і так, легко - виправлення… супер легко - працювати.

  • ServiceStack.Text - швидкий, легкий і стійкий.
  • RestSharp - простий REST і HTTP API клієнт
  • Flurl - вільна, портативна, перевірена бібліотека клієнтів HTTP

Між ними не так багато, але я хотів би дати ServiceStack.Текст невеликий край ...

  • Зірки Гітуба приблизно однакові.
  • Відкриті питання & важливо, як швидко будь-які проблеми закриваються? ServiceStack приймає нагороду за найшвидше вирішення проблеми та відсутність відкритих питань.
  • Документація? Всі мають чудову документацію; проте ServiceStack піднімає його на новий рівень і відомий своїм «Золотим стандартом» для документації.

Гаразд - так як виглядає Запит на поступ у JSON у ServiceStack.Text?

var response = "http://example.org/login"
    .PostJsonToUrl(new Login { Username="admin", Password="mypassword" });

Це один рядок коду. Коротко та просто! Порівняйте вище з бібліотеками Http .NET.


3

Нарешті я викликав режим синхронізації, включивши .Result

HttpResponseMessage response = null;
try
{
    using (var client = new HttpClient())
    {
       response = client.PostAsync(
        "http://localhost:8000/....",
         new StringContent(myJson,Encoding.UTF8,"application/json")).Result;
    if (response.IsSuccessStatusCode)
        {
            MessageBox.Show("OK");              
        }
        else
        {
            MessageBox.Show("NOK");
        }
    }
}
catch (Exception ex)
{
    MessageBox.Show("ERROR");
}

1

var data = Encoding.ASCII.GetBytes(json);

byte[] postBytes = Encoding.UTF8.GetBytes(json);

Використовуйте ASCII замість UFT8


2
звучить як досить погана ідея, я щось пропускаю?
CyberFox

JSON може містити символи UTF8, це здається жахливою ідеєю.
Адріан Сміт
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.