【问题标题】:How to post JSON to a server using C#?如何使用 C# 将 JSON 发布到服务器?
【发布时间】:2012-02-27 01:48:30
【问题描述】:

这是我正在使用的代码:

// 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 内部服务器错误。

我做错了什么?

【问题讨论】:

  • 首先,确保您发布的数据是服务器所期望的。
  • 其实,我好像发布了无效数据...
  • 为方便工作,您也可以将 json 库添加到您的视觉工作室
  • @Arsen - 服务器不应因格式错误的数据而崩溃。提交错误报告。

标签: c# json post httpwebrequest


【解决方案1】:

我的做法和工作方式是:

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

【讨论】:

  • 我认为json字符串行应该是:string json = "{\"user\":\"test\"," + "\"password\":\"bla\"}" ;看起来你缺少一个 \
  • 始终使用“application/json”(除非出于其他原因需要 text/json,例如:entwicklungsgedanken.de/2008/06/06/…)。信用转至:stackoverflow.com/questions/477816/…
  • 我会认为 streamWriter.Flush();和 streamWriter.Close();没有必要,因为您在 using 块内。在 using 块结束时,流写入器无论如何都会关闭。
  • 不要手动构建 JSON。允许 JSON 注入很容易出错。
  • @user3772108 见stackoverflow.com/a/16380064/2279059。使用 JSON 库,例如 Newtonsoft JSON.Net,并从对象呈现 JSON 字符串,或使用序列化。我知道为了简单起见,这里省略了这一点(尽管简单性增益很小),但是格式化结构化数据字符串(JSON,XML,......)即使在微不足道的情况下也太危险了,并且鼓励人们复制这样的代码.
【解决方案2】:

Ademar 的解决方案可以通过利用JavaScriptSerializerSerialize 方法提供对象到JSON 的隐式转换来改进。

此外,可以利用using 语句的默认功能来省略显式调用FlushClose

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

【讨论】:

  • 这个和上面的代码有什么区别,我是不是漏了什么?
  • 这使用 JavaScriptSerializer 的 Serialize 方法来创建有效的 JSON 而不是手工制作。
  • 请参阅下面 Jean F 的回答 - 应该是评论。注意内容类型application/json 是否正确。
  • @SeanAnderson 我一直有“无法连接到远程服务器”错误。
  • @LuzanBaral 你只需要一个程序集:System.Web.Extensions
【解决方案3】:

HttpClient 类型是比WebClientHttpWebRequest 更新的实现。 WebClientWebRequest 都已被标记为已过时。 [1]

您可以简单地使用以下几行。

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[2]

对于 FTP,由于 HttpClient 不支持,我们建议使用第三方库。

@docs.microsoft.com [3]


从 dotnet core 3.1 开始,您可以使用来自 System.Text.JsonJsonSerializer 创建您的 json 字符串。

string myJson = JsonSerializer.Serialize(credentialsObj);

【讨论】:

  • 关于 HttpClient 的一点说明,普遍的共识是你不应该丢弃它。即使它实现了 IDisposable,该对象也是线程安全的,并且可以重用。 stackoverflow.com/questions/15705092/…
  • @JeanF。嘿感谢您的输入。正如我已经注意到的,您应该只创建一个实例或使用HttpClientFactory。我没有阅读链接问题中的所有答案,但我认为它需要更新,因为它没有提到工厂。
【解决方案4】:

在 Sean 的帖子中,没有必要嵌套 using 语句。通过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();
}

【讨论】:

  • 现在这个答案和肖恩安德森的答案完全一样,因为肖恩编辑了他的帖子。
  • 嘿,这太棒了。谢谢。但是如果我们的 json 上有子节点,我们将如何传递数据?
  • 序列化程序可以处理 json 中的子节点 - 您只需为其提供一个有效的 json 对象。
【解决方案5】:

如果你需要异步调用,那么使用

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

    }

【讨论】:

  • 感谢您发布此解决方案 Vivek。在我们的场景中,我们在这篇文章中尝试了另一种解决方案,最后在我们的应用程序中看到了 System.Threading 异常,因为我认为同步帖子阻塞了线程。您的代码解决了我们的问题。
  • 请注意,您可能不必转换为字节。您应该可以使用 postStream.Write(postData); - 并且根据 API,可能必须使用 request.ContentType = "application/json"; 而不是 text/json
【解决方案6】:

我最近想出了一种更简单的方法来发布 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)
{
    // ...
}

【讨论】:

    【解决方案7】:

    注意您正在使用的 Content-Type :

    application/json
    

    来源:

    RFC4627

    Other post

    【讨论】:

      【解决方案8】:

      警告!我对这个问题有非常强烈的看法。

      .NET 现有的 Web 客户端对开发人员不友好! WebRequestWebClient 是“如何挫败开发人员”的主要示例。它们很冗长且使用起来很复杂;当您只想在 C# 中执行一个简单的 Post 请求时。 HttpClient 在解决这些问题方面有所帮助,但仍然不足。最重要的是,微软的文档很糟糕……真的很糟糕;除非您想筛选一页又一页的技术简介。

      开源来拯救。 有三个优秀的开源免费 NuGet 库可供选择。谢天谢地!这些都得到了很好的支持,记录在案,是的,很容易 - 更正......超级容易 - 使用。

      • ServiceStack.Text - 快速、轻便且有弹性。
      • RestSharp - 简单的 REST 和 HTTP API 客户端
      • Flurl- 一个流畅、可移植、可测试的 HTTP 客户端库

      它们之间没有太多区别,但我会给 ServiceStack.Text 一点优势……

      • Github stars大致相同。
      • 未解决的问题以及重要的是解决问题的速度有多快?ServiceStack 在这里获得了最快解决问题且没有未解决问题的奖项。
      • 文档? 都有很好的文档;然而,ServiceStack 将其提升到了一个新的水平,并以其文档的“黄金标准”而闻名。

      好的 - 那么 JSON 格式的 Post 请求在 ServiceStack.Text 中是什么样的?

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

      那是一行代码。简洁轻松!将上述内容与 .NET 的 Http 库进行比较。

      【讨论】:

      • 在 .net 中进行简单的 REST 调用与它一样困难,这是一种犯罪。是什么让我在 Javascript 中花了很短的时间才用一天的大部分时间在 c# 中弄清楚,并且在正确的方式上有十几个不同的意见,但没有一个对我有用? RestSharp 终于挽救了这一天——但我不得不通过他们不完整的文档。
      【解决方案9】:

      This option 未提及:

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

      【讨论】:

      • 此选项自 .Net 4.5.2 起不再可用。看这里stackoverflow.com/a/40525794/2161568
      • 这不是否决这个答案的好理由,因为不是每个人都使用最新版本的 .net,因此这是一个有效的答案。
      【解决方案10】:

      实现此目的的一些不同且干净的方法是像这样使用 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;
           }
      }
      

      【讨论】:

      • 很有帮助,但是自 .NET 4.5.2 起,PostAsJsonAsync 不再可用。请改用PostAsync。更多here
      • HttpClient 通常不应该在这样的using 语句中使用
      • 我认为它实现IDisposable接口是有原因的
      • 这适用于 .net core 2.1,是一个非常干净的选项。如果你注入你的 httpClient,这将变成一个 1 行的 json Post。
      【解决方案11】:

      我最终通过包含 .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");
      }
      

      【讨论】:

        【解决方案12】:

        我发现这是发布读取的 JSON 数据的最友好、最简洁的方式:

        var url = @"http://www.myapi.com/";
        var request = new Request { Greeting = "Hello world!" };
        var json = JsonSerializer.Serialize<Request>(request);
        using (WebClient client = new WebClient())
        {
            var jsonResponse = client.UploadString(url, json);
            var response = JsonSerializer.Deserialize<Response>(jsonResponse);
        }
        

        我正在使用 Microsoft 的 System.Text.Json 对 JSON 进行序列化和反序列化。见NuGet

        【讨论】:

          【解决方案13】:

          点网核心解决方案

          首先使用Newtonsoft.Json,然后写一个这样的方法:

              public static string? LoginToken()
              {
                  var httpWebRequest = (HttpWebRequest)WebRequest.Create("http://url");
                  httpWebRequest.ContentType = "application/json";
                  httpWebRequest.Method = "POST";
          
                  using (var streamWriter = new StreamWriter(httpWebRequest.GetRequestStream()))
                  {
                     //  write your json content here
                      string json = JsonConvert.SerializeObject(new
                      {
                          userName = ApiOptions.Username,
                          password = ApiOptions.Password
                      }
                      );
          
          
                      streamWriter.Write(json);
                  }
          
                  var httpResponse = (HttpWebResponse)httpWebRequest.GetResponse();
                  using (var streamReader = new StreamReader(httpResponse.GetResponseStream()))
                  {
                      var result = streamReader.ReadToEnd();
                      return result;
                  }
          
              }
          

          此方法返回string。如果您想将string 结果反序列化为JSON,只需在方法末尾添加以下行:

          var result = streamReader.ReadToEnd();               
          var json_result = JsonConvert.DeserializeObject<LoginTokenResponse>(result); // + add this code
                  
          

          哪个LoginTokenResponse是你要反序列化字符串结果的自定义类

          【讨论】:

            【解决方案14】:

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

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

            使用 ASCII 代替 UFT8

            【讨论】:

            • 听起来是个很糟糕的主意,我错过了什么吗?
            • JSON 可以包含 UTF8 字符,这似乎是个糟糕的主意。
            【解决方案15】:

            我就是这样做的

            //URL
            var url = "http://www.myapi.com/";
            
            //Request
            using var request = new HttpRequestMessage(HttpMethod.Post, url);
            
            //Headers
            request.Headers.Add("Accept", "application/json");
            request.Headers.Add("Cache-Control", "no-cache");
            
            //Payload
            var payload = JsonConvert.SerializeObject(
                new
                {
                    Text = "Hello world"
                });
            request.Content = new StringContent(payload, Encoding.UTF8, "application/json");
            
            //Send
            var response = await _httpClient.SendAsync(request);
            
            //Handle response
            if (response.IsSuccessStatusCode)
                return;
            

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2021-09-15
              • 1970-01-01
              • 1970-01-01
              相关资源
              最近更新 更多