如何向REST服务器发送带有自定义头的任意JSON数据?

8
TL;DR -- 如何在带有授权标头的REST主机上发送JSON字符串?我已经尝试了3种不同的方法,找到了一种使用匿名类型的方法可以工作。为什么不能使用匿名类型?我需要设置一个名为“Group-Name”的变量,而连字符不是有效的C#标识符。
背景
我需要POST JSON,但无法正确获取正文和内容类型
函数#1 - 可以使用匿名类型
内容类型和数据是正确的,但我不想使用匿名类型。我想使用一个字符串
  static void PostData(string restURLBase, string RESTUrl, string AuthToken, string postBody)
    {
        HttpClient client = new HttpClient();
        client.BaseAddress = new Uri(restURLBase);
        client.DefaultRequestHeaders.Add("Auth-Token", AuthToken);
        client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));

        // StringContent content = new StringContent(postBody);

        var test1 = "data1";
        var test2 = "data2";
        var test3 = "data3";

        var response = client.PostAsJsonAsync(RESTUrl, new { test1, test2, test3}).Result;  // Blocking call!
        if (!response.IsSuccessStatusCode)
        {
            Console.WriteLine("{0} ({1})", (int)response.StatusCode, response.ReasonPhrase);
            return;
        } 
    }

输出 #1

使用匿名类型+ PostAsJsonAsync 时,内容类型和数据正确,但我不想使用匿名类型。

POST https://api.dynect.net/REST/Zone/ABCqqqqqqqqqqqqYYYYYtes3ss.com HTTP/1.1
Auth-Token: --- REDACTED -----
Accept: application/json
Content-Type: application/json; charset=utf-8
Host: api.dynect.net
Content-Length: 49
Expect: 100-continue

{"test1":"data1","test2":"data2","test3":"data3"}

功能#2 - 无法按预期工作

将字符串放入StringContent对象中。这会改变内容类型,有一个副作用。

  static void PostData(string restURLBase, string RESTUrl, string AuthToken, string postBody)
    {
        HttpClient client = new HttpClient();
        client.BaseAddress = new Uri(restURLBase);
        client.DefaultRequestHeaders.Add("Auth-Token", AuthToken);
        client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));

        StringContent content = new StringContent(postBody);

        var response = client.PostAsync(RESTUrl, content).Result;  // Blocking call!
        if (!response.IsSuccessStatusCode)
        {
            Console.WriteLine("{0} ({1})", (int)response.StatusCode, response.ReasonPhrase);
            return;
        } 
    }

输出 #2

使用StringContent + PostAsync时,内容类型错误。

POST https://api.dynect.net/REST/Zone/ABCqqqqqqqqqqqqYYYYYtes3ss.com HTTP/1.1
Auth-Token: ---- REDACTED -------
Accept: application/json                      // CORRECT
Content-Type: text/plain; charset=utf-8       // WRONG!!!
Host: api.dynect.net
Content-Length: 100
Expect: 100-continue

{"rdata" : ["rname" : "dynect.nfp.com", "zone" : "ABCqqqqqqqqqqqqYYYYYtes3ss.com"], "ttl" : "43200"}
        // ^^ THIS IS CORRECT

功能 #3 - 没有预期的效果

我知道PostAsJsonAsync会正确设置contentType,让我们使用该方法。(无效)

    static void PostData(string restURLBase, string RESTUrl, string AuthToken, string postBody)
    {
        HttpClient client = new HttpClient();
        client.BaseAddress = new Uri(restURLBase);
        client.DefaultRequestHeaders.Add("Auth-Token", AuthToken);
        client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));

        StringContent content = new StringContent(postBody);

        var response = client.PostAsJsonAsync(RESTUrl, content).Result;  // Blocking call!
        if (!response.IsSuccessStatusCode)
        {
            Console.WriteLine("{0} ({1})", (int)response.StatusCode, response.ReasonPhrase);
            return;
        } 
    }

输出 #3

内容类型正确,使用StringContent + PostAsJsonAsync时POST请求体错误。

POST https://api.dynect.net/REST/Zone/ABCqqqqqqqqqqqqYYYYYtes3ss.com HTTP/1.1
Auth-Token: -- REDACTED ---
Accept: application/json
Content-Type: application/json; charset=utf-8
Host: api.dynect.net
Content-Length: 74
Expect: 100-continue

{"Headers":[{"Key":"Content-Type","Value":["text/plain; charset=utf-8"]}]}

问题

我想要做的就是以正确的HTTP内容类型和特殊的“Auth-Token”标头将JSON作为字符串或在运行时定义的动态对象发送到服务器。

如果不使用WebAPI(如servicestack或其他任何东西),请提供示例。


你能展示一下你遇到的错误吗? - G. Stoynev
@G.Stoynev 没有特别的错误,但是我该如何在 PostAsync 中使用“HttpContent”呢? - makerofthings7
2个回答

6
/// <summary>
    /// Creates a new instance of the <see cref="T:System.Net.Http.StringContent"/> class.
    /// </summary>
    /// <param name="content">The content used to initialize the <see cref="T:System.Net.Http.StringContent"/>.</param><param name="encoding">The encoding to use for the content.</param><param name="mediaType">The media type to use for the content.</param>
    [__DynamicallyInvokable]
    public StringContent(string content, Encoding encoding, string mediaType)
      : base(StringContent.GetContentByteArray(content, encoding))
    {
      this.Headers.ContentType = new MediaTypeHeaderValue(mediaType == null ? "text/plain" : mediaType)
      {
        CharSet = encoding == null ? HttpContent.DefaultStringEncoding.WebName : encoding.WebName
      };
    }

这是StringContent的构造函数。看起来你需要指定适当的编码和媒体类型。


3

谢谢,这帮助我得出了上面列出的输出。+1 - makerofthings7

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接