【C#】【Call Web API, 泛型Generic, Post With Data, Determine Has ? [Optional] Parameter, Has ? Data Model Property】Call Web API,取得JSON。[Optional]選擇性傳入參數、判斷是否有傳入此參數。判斷Data Model Object是否有某欄位(Property),若有則取其值。

【C#】【Call Web API, 泛型Generic, Post With Data, Determine Has ?  [Optional] Parameter, Has ?  Data Model Property】Call Web API,取得JSON。[Optional]選擇性傳入參數、判斷是否有傳入此參數。判斷Data Model Object是否有某欄位(Property),若有則取其值。

using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Runtime.InteropServices;
using System.Text;

namespace Call_API
{
    public enum RequestMethod
    {
        GET,
        POST
    }

    public class Form_Data
    {
        public int FormNo { get; set; }
        public string FormKind { get; set; }
        public string EmpID { get; set; }
        public string SecurityCode { get; set; }
    }

    public class Base_of_Request<T_DM_Response>
    {
        string sUri = string.Empty;
        bool bUseFormKind = false;
        bool bUseSecurityCode = false;

        public Base_of_Request()
        {
        }

        public string Uri{set{sUri = value;}}

        /// <summary>
        /// Request: 是否使用formKind
        /// </summary>
        public bool RequestUseFormKind{set {bUseFormKind = value;}}

        /// <summary>
        /// Request: 是否使用apiToken or securityCode
        /// </summary>
        public bool RequestUseSecurityCode{ set { bUseSecurityCode = value; } }

        /// <summary>
        /// 表單的公用資訊
        /// </summary>
        public Form_Data Form_Data { get; set; }

        public String PrintJson(string JSON)
        {
            if (string.IsNullOrWhiteSpace(JSON)) return string.Empty;

            const string sp = " \r\n "; //\t

            object rsp = new object();

            JToken jtoken = JToken.Parse(JSON);
            if (jtoken is JArray)
            {
                rsp = JsonConvert.DeserializeObject<List<T_DM_Response>>(JSON);
            }
            else if (jtoken is JObject)
            {
                rsp = JsonConvert.DeserializeObject<T_DM_Response>(JSON);
            }

            if ((Form_Data != null && Form_Data.FormNo == 0) && rsp.GetType().GetProperty("formNo")!=null)
            {
                //如果response的Data Object有formNo欄位的話,將其值傳回,供接下來CALL 其它API使用
                Form_Data.FormNo = (int)rsp.GetType().GetProperty("formNo").GetValue(rsp);
            }

            string result = JSON_to_PairString(rsp, '|');
            result = $"\r\n●Deserialize Json:\r\n {result.Replace("|", sp)}";

            return result;
        }


        /// <summary>
        /// 將JSON字串解析為結構化的字串(seprator傳入換行符號時,可用於視覺化呈現;傳入&時,可用於將postdata轉為QueryString)
        /// </summary>
        /// <param name="dataObject"></param>
        /// <param name="seprator"></param>
        /// <returns></returns>
        public string JSON_to_PairString(object dataObject, char seprator)
        {
            string result = string.Empty;
            try
            {
                string sDataObject = JsonConvert.SerializeObject(dataObject);
                StringBuilder sb = new StringBuilder();

                object rsp = new object();
                JToken jtoken = JToken.Parse(sDataObject);
                if (jtoken is JArray)
                {
                    /*
                    //例如這樣的JSON結構,一開始就是JArray(中括號的數組[]):
                    "[{'ID':0,'List_Item_Type':'ApplyBu','CodeCategory_Name':null},
                    {'ID':1,'List_Item_Type':'ApplyBu','CodeCategory_Name':null},
                    {'ID':2,'List_Item_Type':'ApplyBu','CodeCategory_Name':null}]"
                    */
                    foreach (JObject jObject in ((JArray)jtoken).ToList())
                    {
                        foreach (var item in jObject)
                        {
                            sb.Append($"{item.Key}={item.Value}{seprator}");
                        }
                        sb.Append($"{seprator}");
                    }
                }
                else if (jtoken is JObject)
                {
                    /*
                    //例如這樣的JSON結構,一開始是JObject(大括號的數組{}),內部可能再包含JArray或JObject(巢狀):
                    "{ 'context_name': { 'lower_bound': 'value', 'upper_bound': 'value', 'values': [ 'value1', 'valueN' ] } }"
                    或"{'id':2,'name':'root','descendants':[{'id':4,'name':'node2','descendants':[{'id':7,'name':'node21'},{'id':8,'name':'node22'}]},{'id':3,'name':'node1','descendants':[{'id':5,'name':'node11'},{'id':6,'name':'node12'}]}]}"
                    */
                    foreach (var item in (JObject)jtoken)
                    {
                        sb.Append($"{item.Key}={item.Value}{seprator}");
                    }
                }

                result = sb.ToString();
            }
            catch (Exception err)
            {
                Console.WriteLine($"\r\n●Error={err.Message}");
            }

            result = result.TrimEnd(seprator);
            return result;
        }

        /// <summary>
        /// Call Web API,取得JSON。選擇性傳入參數、判斷是否有傳入此參數。
        /// 若選擇使用GET方法,則將傳入的data object改為Query String;若傳入data object,僅在方法為POST時才可用
        /// </summary>
        /// <returns></returns>
        public string GetJSON(RequestMethod requestMethod, [Optional]object postData)
        {
            #region 如果有傳入PostData,而requestMethod為GET,則將postData改為URI參數
            if (postData != System.Reflection.Missing.Value && requestMethod==RequestMethod.GET)
            {
                string sQueryString = $"?{JSON_to_PairString(postData,'&')}";

                sUri = sUri + sQueryString;
            }
            #endregion 如果有傳入PostData,而requestMethod為GET,則將postData改為URI參數

            /*
            How to Post with data:
            Getting the request stream does not trigger the post, but closing the stream does.Post data is sent to the server in the following way:
            1.A connection is opened to the host
            2.Send request and headers
            3.Write Post data
            4.Wait for a response.
            The act of flushing and closing the stream is the final step, and once the input stream is closed (i.e.the client has sent what it needs to the server), then the server can return a response.
            */

            HttpWebRequest request = (HttpWebRequest)WebRequest.Create(sUri);

            // Set the 'Method' property of the 'Webrequest' to 'POST'.
            //request.Method = WebRequestMethods.Http.Post;
            //request.Method = "POST";
            //由參數設定
            request.Method = requestMethod.ToString();

            // Set the content type of the data being posted.
            request.ContentType = "application/json";

            //formKind
            //由屬性設定是否要加此request.Headers
            if (Form_Data!=null && bUseFormKind) request.Headers.Add("formKind", Form_Data.FormKind);

            //apiToken or securityCode
            //由屬性設定是否要加此request.Headers
            if (Form_Data != null && bUseSecurityCode) request.Headers.Add("securityCode", Form_Data.SecurityCode);

            string json = string.Empty;
            try
            {
                #region ----↓用Object傳參數(僅限POST方法可傳postData object參數;若是用GET方法,須使用URI傳參數)↓--------------------------------------------------------------------------------------
                #region 若請使用者輸入參數,轉成ASCII Code,再傳參數給Server,則這樣做:
                /*
                Console.WriteLine($"\nPlease enter the data to be posted to the ({sSite}{sFunctionName}) Uri :");

                // Create a new string object to POST data to the Url.
                string inputData = Console.ReadLine();

                string postData = "firstone=" + inputData;
                ASCIIEncoding encoding = new ASCIIEncoding();
                byte[] myByteArray = encoding.GetBytes(postData);

                // Set the content length of the string being posted.
                request.ContentLength = myByteArray.Length;
                */
                #endregion 若請使用者輸入參數,轉成ASCII Code,再傳參數給Server,則這樣做

                #region 用Data Model 傳參數
                if (requestMethod==RequestMethod.POST && postData != System.Reflection.Missing.Value)
                {
                    #region Data Model [postData] 填值
                    string sPostData = JsonConvert.SerializeObject(postData);//將匿名物件序列化為json字串
                    byte[] myByteArray = Encoding.UTF8.GetBytes(sPostData);

                    // Set the content length of the string being posted.
                    request.ContentLength = myByteArray.Length;
                    #endregion Data Model [postData] 填值

                    #region 傳出參數給Server
                    if (false)
                    {
                        Stream newStream = request.GetRequestStream();
                        newStream.Write(myByteArray, 0, myByteArray.Length);

                        // Close the Stream object.
                        newStream.Close();
                    }
                    else
                    {
                        //或這樣寫。using相當於在Stream.Write後做stream.Close()
                        using (Stream newStream = request.GetRequestStream())
                        {
                            newStream.Write(myByteArray, 0, myByteArray.Length);
                        }
                    }
                    #endregion 傳出參數給Server
                }
                #endregion 用Data Model 傳參數
                #endregion ----↑用Object傳參數(僅限POST方法可傳postData object參數;若是用GET方法,須使用URI傳參數)↑--------------------------------------------------------------------------------------

                #region 取得Server回應的JSON
                using (HttpWebResponse response = (HttpWebResponse)request.GetResponse())
                {
                    if (response.StatusCode == HttpStatusCode.OK)
                    {
                        using (StreamReader reader = new StreamReader(response.GetResponseStream(), Encoding.UTF8))
                        {
                            json = reader.ReadToEnd();
                            Console.WriteLine($"\r\n●URI={sUri}");
                            Console.WriteLine($"\r\n●JSON={json}");
                        }
                    }
                }
                #endregion 取得Server回應的JSON
            }
            catch (Exception err)
            {
                Console.WriteLine($"\r\n●Error={err.Message}");
            }

            return json;
        }
    }
}