入參用 JToken 構造,尤其適合參數結構動態(如不確定字段、嵌套層級變化)或需要靈活拼接的場景。JToken 作為 Json.NET 的核心節點類型,可直接序列化為標準 JSON 字符串。

核心思路

  1. JObjectJToken 的子類,專門處理 JSON 對象)構造請求參數(鍵值對、嵌套結構、數組均可);
  2. 直接將 JObject 傳遞給 JsonConvert.SerializeObject()(無需手動轉換,Json.NET 會自動序列化為 JSON 字符串);
  3. 後續請求發送邏輯(HttpWebRequest 配置、流寫入)完全複用之前的代碼,無需修改。

完整實現代碼(JToken 構造入參)

using System;
using System.IO;
using System.Net;
using System.Text;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq; // 引入 JToken/JObject 命名空間

namespace Net20PostJsonWithJTokenParam
{
    class Program
    {
        static void Main(string[] args)
        {
            // 忽略 HTTPS 證書驗證(僅測試環境)
            ServicePointManager.ServerCertificateValidationCallback = delegate { return true; };
            string apiUrl = "https://api.example.com/your-endpoint"; // 替換為實際接口地址

            try
            {
                // 1. 核心步驟:用 JObject(JToken 子類)構造入參
                JObject requestParams = new JObject();
                // 添加基礎字段(字符串、數值、布爾類型)
                requestParams["username"] = "張三";       // 字符串
                requestParams["age"] = 28;               // 數值(自動序列化為無引號)
                requestParams["isVip"] = true;           // 布爾(自動序列化為無引號)
                requestParams["logContent"] = "測試日誌內容"; // 字符串

                // 添加嵌套結構(如 address 嵌套對象)
                JObject address = new JObject();
                address["province"] = "廣東省";
                address["city"] = "廣州市";
                requestParams["address"] = address; // 嵌套 JObject

                // 添加數組(如 hobbies 數組)
                JArray hobbies = new JArray("編程", "籃球", "旅遊"); // 直接初始化數組
                requestParams["hobbies"] = hobbies; // 數組字段

                // 動態添加/刪除字段(靈活調整參數)
                requestParams["gender"] = "男"; // 動態添加
                // requestParams.Remove("gender"); // 按需刪除字段

                // 2. 序列化 JObject 為 JSON 字符串(Json.NET 自動處理格式)
                string jsonData = JsonConvert.SerializeObject(requestParams, Formatting.Indented);
                Console.WriteLine("請求 JSON 數據:\n" + jsonData);

                // 3. 發送 POST 請求
                string responseJson = SendPostJsonRequest(apiUrl, jsonData);
                Console.WriteLine("\n響應原始 JSON:" + responseJson);

                // 4. 解析響應(複用 JToken 方式判斷 code == "200")
                JToken responseToken = JToken.Parse(responseJson);
                if (responseToken.Value<string>("code") == "200")
                {
                    Console.WriteLine("請求成功!提示:" + responseToken["msg"]);
                }
                else
                {
                    Console.WriteLine("請求失敗!");
                }
            }
            catch (JsonReaderException ex)
            {
                Console.WriteLine("JSON 解析異常:" + ex.Message);
            }
            catch (Exception ex)
            {
                Console.WriteLine("請求異常:" + ex.Message);
            }
        }

        /// <summary>
        /// POST 請求核心方法
        /// </summary>
        private static string SendPostJsonRequest(string url, string jsonData)
        {
            if (string.IsNullOrEmpty(url) || string.IsNullOrEmpty(jsonData))
                throw new ArgumentNullException("請求地址或參數不能為空");

            HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
            request.Method = "POST";
            request.ContentType = "application/json; charset=utf-8";
            request.Timeout = 10000; // 10秒超時

            // 寫入請求體
            byte[] postBytes = Encoding.UTF8.GetBytes(jsonData);
            request.ContentLength = postBytes.Length; // .NET 2.0 必須設置長度

            using (Stream requestStream = request.GetRequestStream())
            {
                requestStream.Write(postBytes, 0, postBytes.Length);
                requestStream.Flush();
            }

            // 讀取響應
            using (HttpWebResponse response = (HttpWebResponse)request.GetResponse())
            {
                using (StreamReader reader = new StreamReader(response.GetResponseStream(), Encoding.UTF8))
                {
                    return reader.ReadToEnd();
                }
            }
        }
    }
}

JToken 構造入參的核心用法

1. 基礎字段構造(JObject

JObject 對應 JSON 對象({}),通過索引器直接添加鍵值對,自動適配類型:

JObject requestParams = new JObject();
requestParams["key1"] = "字符串值";  // 序列化後:"key1":"字符串值"
requestParams["key2"] = 123;        // 序列化後:"key2":123
requestParams["key3"] = true;       // 序列化後:"key3":true
requestParams["key4"] = null;       // 序列化後:"key4":null

2. 嵌套對象構造(JObject 嵌套)

適合參數包含子對象(如 address: {province: "廣東", city: "廣州"}):

JObject address = new JObject();
address["province"] = "廣東省";
address["city"] = "廣州市";
requestParams["address"] = address; // 嵌套後序列化:"address":{"province":"廣東省","city":"廣州市"}

3. 數組構造(JArray

JArray 對應 JSON 數組([]),支持直接初始化或動態添加元素:

// 方式1:直接初始化
JArray hobbies = new JArray("編程", "籃球", "旅遊");
requestParams["hobbies"] = hobbies; // 序列化後:"hobbies":["編程","籃球","旅遊"]

// 方式2:動態添加元素
JArray tags = new JArray();
tags.Add("測試");
tags.Add("日誌");
requestParams["tags"] = tags; // 序列化後:"tags":["測試","日誌"]

4. 動態調整參數

支持運行時添加/刪除/修改字段,靈活性拉滿:

// 添加字段
requestParams["newKey"] = "新值";

// 修改字段
requestParams["age"] = 29; // 覆蓋原有值

// 刪除字段
requestParams.Remove("isVip"); // 移除不需要的參數

5. 序列化(直接序列化 JObject

無需手動轉換,JsonConvert.SerializeObject() 可直接將 JObject/JToken 序列化為標準 JSON 字符串:

JObject requestParams = new JObject();
requestParams["username"] = "張三";
string jsonData = JsonConvert.SerializeObject(requestParams); 
// 結果:{"username":"張三"}

JToken 構造入參的優缺點

優點

  1. 極致靈活:支持動態添加/刪除/修改參數,適合字段不固定、嵌套結構多變的場景;
  2. 類型自動適配:數值、布爾、字符串類型自動序列化(無需手動拼接引號,避免格式錯誤);
  3. 支持複雜結構:輕鬆處理嵌套對象、數組,比 Dictionary 更直觀(無需 Dictionary<string, object> 嵌套);
  4. 無縫銜接:直接序列化 JObject,無需中間轉換,與現有請求流程完全兼容。

缺點

  1. 無編譯時校驗:鍵名拼寫錯誤(如 requestParams["userName"] 而非 requestParams["username"])只能運行時發現;
  2. 代碼略顯繁瑣:簡單鍵值對場景下,比 Dictionary 或實體類多幾行代碼;
  3. 依賴 Json.NET:必須引入 Newtonsoft.Json(但你已在使用,無額外成本)。

關鍵注意事項

  1. Json.NET 版本兼容:確保使用 Newtonsoft.Json 12.0.3 及以下版本(.NET 2.0 不支持更高版本);
  2. 參數類型匹配:接口要求的字段類型需與 JObject 中添加的類型一致(如接口要求 age 是數值,就不能用字符串 requestParams["age"] = "28");
  3. 空值處理:若接口不允許 null 值,需避免添加 requestParams["key"] = null,或在序列化時忽略空值:
    // 序列化時忽略空值字段(可選)
    JsonSerializerSettings settings = new JsonSerializerSettings
    {
        NullValueHandling = NullValueHandling.Ignore
    };
    string jsonData = JsonConvert.SerializeObject(requestParams, settings);
    
  4. 數組元素類型JArray 中可混合類型(如 new JArray("a", 1, true)),但需符合接口要求,避免序列化後格式不兼容。

入參構造方式對比(彙總)

入參構造方式 優點 缺點 適用場景
手動拼接 JSON 無需依賴,原生支持 易出錯,不支持複雜結構 極簡參數,無依賴場景
Dictionary 無需實體類,簡單直觀 嵌套/數組需手動處理類型 簡單鍵值對,無複雜結構
實體類 類型安全,編譯時校驗 不支持動態字段,需提前定義 字段固定,長期維護
JToken(JObject) 動態靈活,支持複雜結構,類型自動適配 無編譯時校驗,依賴 Json.NET 動態字段、嵌套/數組結構,推薦