【问题标题】:Send JSON via POST in C# and Receive the JSON returned?在 C# 中通过 POST 发送 JSON 并接收返回的 JSON?
【发布时间】:2014-05-10 20:23:18
【问题描述】:

这是我第一次在我的任何应用程序中使用 JSON 以及 System.NetWebRequest。我的应用程序应该向身份验证服务器发送一个类似于下面的 JSON 有效负载:

{
  "agent": {                             
    "name": "Agent Name",                
    "version": 1                                                          
  },
  "username": "Username",                                   
  "password": "User Password",
  "token": "xxxxxx"
}

为了创建这个有效载荷,我使用了JSON.NET 库。我如何将此数据发送到身份验证服务器并接收其 JSON 响应?这是我在一些示例中看到的,但没有 JSON 内容:

var http = (HttpWebRequest)WebRequest.Create(new Uri(baseUrl));
http.Accept = "application/json";
http.ContentType = "application/json";
http.Method = "POST";

string parsedContent = "Parsed JSON Content needs to go here";
ASCIIEncoding encoding = new ASCIIEncoding();
Byte[] bytes = encoding.GetBytes(parsedContent);

Stream newStream = http.GetRequestStream();
newStream.Write(bytes, 0, bytes.Length);
newStream.Close();

var response = http.GetResponse();

var stream = response.GetResponseStream();
var sr = new StreamReader(stream);
var content = sr.ReadToEnd();

但是,与我过去使用过的其他语言相比,这似乎是很多代码。我这样做正确吗?以及如何获取 JSON 响应以便进行解析?

谢谢,精英。

更新代码

// Send the POST Request to the Authentication Server
// Error Here
string json = await Task.Run(() => JsonConvert.SerializeObject(createLoginPayload(usernameTextBox.Text, password)));
var httpContent = new StringContent(json, Encoding.UTF8, "application/json");
using (var httpClient = new HttpClient())
{
    // Error here
    var httpResponse = await httpClient.PostAsync("URL HERE", httpContent);
    if (httpResponse.Content != null)
    {
        // Error Here
        var responseContent = await httpResponse.Content.ReadAsStringAsync();
    }
}

【问题讨论】:

  • 你可以试试WebClient.UploadString(JsonConvert.SerializeObjectobj(yourobj))HttpClient.PostAsJsonAsync

标签: c# .net json httpwebrequest json.net


【解决方案1】:

我发现自己使用HttpClient 库来查询 RESTful API,因为代码非常简单且完全异步。要发送此 JSON 有效负载:

{
  "agent": {                             
    "name": "Agent Name",                
    "version": 1                                                          
  },
  "username": "Username",                                   
  "password": "User Password",
  "token": "xxxxxx"
}

有两个类代表您发布的 JSON 结构,可能如下所示:

public class Credentials
{
    public Agent Agent { get; set; }
    
    public string Username { get; set; }
    
    public string Password { get; set; }
    
    public string Token { get; set; }
}

public class Agent
{
    public string Name { get; set; }
    
    public int Version { get; set; }
}

您可以使用这样的方法来执行您的 POST 请求:

var payload = new Credentials { 
    Agent = new Agent { 
        Name = "Agent Name",
        Version = 1 
    },
    Username = "Username",
    Password = "User Password",
    Token = "xxxxx"
};

// Serialize our concrete class into a JSON String
var stringPayload = JsonConvert.SerializeObject(payload);

// Wrap our JSON inside a StringContent which then can be used by the HttpClient class
var httpContent = new StringContent(stringPayload, Encoding.UTF8, "application/json");

var httpClient = new HttpClient()
    
// Do the actual request and await the response
var httpResponse = await httpClient.PostAsync("http://localhost/api/path", httpContent);

// If the response contains content we want to read it!
if (httpResponse.Content != null) {
    var responseContent = await httpResponse.Content.ReadAsStringAsync();
    
    // From here on you could deserialize the ResponseContent back again to a concrete C# type using Json.Net
}

【讨论】:

  • 完美,但是 await Task.run(() 是什么?
  • 您不应该在同步 CPU 绑定方法上使用 Task.Run,​​因为您只是启动一个新线程而没有任何好处!
  • 您不必为每个属性都输入JsonProperty。只需使用 Json.Net 内置的CamelCasePropertyNamesContractResolvercustom NamingStrategy 来自定义序列化过程
  • 旁注:不要将usingHttpClient 一起使用。见:aspnetmonsters.com/2016/08/2016-08-27-httpclientwrong
  • 使用 System.Net.Http.Formatting 您定义了扩展方法:"await httpClient.PostAsJsonAsync("api/v1/domain", csObjRequest)"
【解决方案2】:

使用 JSON.NET NuGet 包和匿名类型,您可以简化其他发帖人的建议:

// ...

string payload = JsonConvert.SerializeObject(new
{
    agent = new
    {
        name    = "Agent Name",
        version = 1,
    },

    username = "username",
    password = "password",
    token    = "xxxxx",
});

var client = new HttpClient();
var content = new StringContent(payload, Encoding.UTF8, "application/json");

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

// ...

【讨论】:

    【解决方案3】:

    您可以使用JObject 的组合来构建您的HttpContent 来避免和JProperty,然后在构建StringContent 时调用ToString()

            /*{
              "agent": {                             
                "name": "Agent Name",                
                "version": 1                                                          
              },
              "username": "Username",                                   
              "password": "User Password",
              "token": "xxxxxx"
            }*/
    
            JObject payLoad = new JObject(
                new JProperty("agent", 
                    new JObject(
                        new JProperty("name", "Agent Name"),
                        new JProperty("version", 1)
                        ),
                    new JProperty("username", "Username"),
                    new JProperty("password", "User Password"),
                    new JProperty("token", "xxxxxx")    
                    )
                );
    
            using (HttpClient client = new HttpClient())
            {
                var httpContent = new StringContent(payLoad.ToString(), Encoding.UTF8, "application/json");
    
                using (HttpResponseMessage response = await client.PostAsync(requestUri, httpContent))
                {
                    response.EnsureSuccessStatusCode();
                    string responseBody = await response.Content.ReadAsStringAsync();
                    return JObject.Parse(responseBody);
                }
            }
    

    【讨论】:

    • 如何避免Exception while executing function. Newtonsoft.Json: Can not add Newtonsoft.Json.Linq.JProperty to Newtonsoft.Json.Linq.JArray 错误?
    • 不应使用 using 构造创建 HttpClient 实例。该实例应创建一次并在整个应用程序中使用。这是因为它使用自己的连接池。您的代码大多倾向于抛出 SocketException。 docs.microsoft.com/en-us/dotnet/api/…
    【解决方案4】:

    您还可以使用 HttpClient() 中提供的 PostAsJsonAsync() 方法

    var requestObj= JsonConvert.SerializeObject(obj);
    HttpResponseMessage response = await client.PostAsJsonAsync($"endpoint",requestObj);
    

    【讨论】:

    • 您能否解释一下您的代码的作用以及它如何解决问题?
    • 你可以使用你想要发布的任何对象并使用 SerializeObject(); 对其进行序列化。 var obj= new Credentials { Agent = new Agent { Name = "Agent Name", Version = 1 }, Username = "Username", Password = "User Password", Token = "xxxxx" }; 然后无需将其转换为 httpContent,您可以使用 PostAsJsonAsync() 传递端点 URL 和转换后的 JSON 对象本身。
    • 仅供参考,因为 .NET4.5 左右,HttpClient 上没有 PostAsJsonAsync()
    猜你喜欢
    • 2012-01-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-11-16
    • 1970-01-01
    • 2013-12-23
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多