如何使用C#将JSON发布到服务器?


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 2012年

实际上,看来我正在发布无效数据...
Arsen Zahray 2012年

为了便于工作,你可以添加JSON库到Visual Studio太
阿里Tabatabaeian

@Arsen-服务器不应因格式错误的数据而崩溃。提交错误报告。
jww

Answers:


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 \“}”; 它看起来像你缺少一个\
梦巷

3
始终使用“ application / json”(除非出于某些其他原因需要text / json,例如:entwicklungsgedanken.de/2008/06/06/…)。撰写文章至:stackoverflow.com/questions/477816/…
亚尼夫

34
我本以为streamWriter.Flush(); 和streamWriter.Close(); 不需要,因为您位于using块内。在using块的结尾,流编写器将始终关闭。
Ruchira

1
不要手动构建JSON。容易犯允许JSON注入的错误。
弗洛里安(Florian Winter)

5
@ user3772108请参阅stackoverflow.com/a/16380064/2279059。使用JSON库(例如Newtonsoft JSON.Net),并从对象渲染JSON字符串,或使用序列化。我知道这里为简化起见省略了此操作(尽管简单性获得的好处很小),但是格式化结构化数据字符串(JSON,XML等)太危险了,即使在琐碎的情况下也无法做到这一点,并且鼓励人们复制此类代码。
弗洛里安冬季

149

通过利用JavaScriptSerializerSerialize方法可以将对象隐式转换为JSON,从而可以改善Ademar的解决方案。

另外,可以利用using语句的默认功能来省略显式调用Flushand 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 2014年

16
它使用JavaScriptSerializer的Serialize方法创建有效的JSON,而不是手工制作。
肖恩·安德森

请参阅下面的Jean F的答案-应该是评论。注意内容类型application/json是否正确。
2015年

@SeanAnderson我一直遇到“无法连接到远程服务器”错误。
ralphgabb15年

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多个实例,建议仅创建一个实例并重用它或使用new HttpClientFactory


5
关于HttpClient的一点说明,一般的共识是您不应该丢弃它。即使实现了IDisposable对象,该对象也是线程安全的,可以重用。stackoverflow.com/questions/15705092/...
吉恩F.

1
@JeanF。谢谢您的输入。正如我已经指出的那样,您应该只创建一个实例或使用HttpClientFactory。我没有阅读链接问题中的所有答案,但我认为它需要更新,因为它没有提及工厂。
NtFreX

33

在Sean的帖子之后,没有必要嵌套using语句。通过usingStreamWriter,它将在块的末尾刷新并关闭,因此无需显式调用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
现在,这个答案和肖恩·安德森的答案完全一样,就像肖恩编辑了他的帖子一样。
faza

嘿,太好了,谢谢,但是如果我们在json上有子节点,我们该如何传递数据呢?
user2728409 '19

1
序列化程序可以处理json中的子节点-您只需为其提供有效的json对象。
David Clarke

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 2013年

根据上面的评论投下赞成票-由于此评论不可用,因此应该删除答案。
NovaDev

1
那不是拒绝这个答案的好理由,因为不是每个人都使用最新版本的.net,因此这是一个有效的答案。
Ellisan

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 '18

我认为,它实现IDisposable接口是有原因的
迪马达伦

4

警告!在这个问题上,我有很强烈的看法。

.NET的现有Web客户端对开发人员不友好! WebRequestWebClient是“如何挫败开发人员”的主要示例。它们冗长而复杂。当您要做的只是在C#中执行一个简单的Post请求。HttpClient可以解决这些问题,但是仍然不足。最重要的是,Microsoft的文档很糟糕……确实很糟糕;除非您要浏览技术性页面和页面。

开源拯救。有三种出色的开源免费NuGet库可供选择。谢天谢地!这些都得到很好的支持和记录,是的,很容易-纠正...超级容易-可以使用。

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

  • Github的星星大致相同。
  • 未解决的问题,重要的是,任何问题关闭的速度有多快?ServiceStack在这里以最快的问题解决速度和没有未解决的问题获得奖项。
  • 文档?所有人都有很好的文档。但是,ServiceStack将其提升到一个新的水平,并以其“黄金标准”而闻名。

好的-在ServiceStack.Text中,JSON中的Post Request看起来如何?

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

那是一行代码。简洁易用!将以上内容与.NET的Http库进行比较。


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
听起来是个坏主意,我想念什么吗?
Cyber​​Fox

JSON可以包含UTF8字符,这似乎是一个糟糕的主意。
阿德里安·史密斯
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.