Dynamics CRM2016 解決C#呼叫web api報錯無法顯示錯誤詳情的問題

vic0228發表於2017-07-14

    在js中呼叫web api如果報錯,比如400 bad request,比如500都會在response中看到具體的錯誤,方便我們及時修正,但是在c#中通過httpwebrequest呼叫報錯是看不到的,所以往往需要我們把url拷出來在瀏覽器裡檢視,甚至需要藉助第三方工具來檢視非get請求類的錯誤,還是比較麻煩的。

    先來看下普通的httprequest方式報錯返回是什麼樣的,示例程式碼很簡單,建立一條name為DTCC的account記錄

 HttpWebRequest req = (HttpWebRequest)HttpWebRequest.
                Create("http://121.40.75.24:5555/origin/api/data/v8.0/accounts");
            req.Credentials = new NetworkCredential(username, pwd, domain);
            req.Method = "post";
            req.Accept = "application/json";
            req.ContentType = "application/json; charset=utf-8";
            byte[] data = Encoding.UTF8.GetBytes("{\"name\":\"DTCC\"}");
            Stream newStream = req.GetRequestStream();
            newStream.Write(data, 0, data.Length);
            newStream.Close();
            using (HttpWebResponse res = (HttpWebResponse)req.GetResponse())
            {
                StreamReader read = new StreamReader(res.GetResponseStream());
                string result = read.ReadToEnd();
            }
   

    因為我寫了個create的pre外掛阻止了建立,所以這塊提示是500錯,但看不到具體的錯誤原因

    我們們來換一種方式,示例程式碼如下

public static async Task Demo_API_02()
        {
            HttpClientHandler sHandler = new HttpClientHandler();
            sHandler.Credentials = new NetworkCredential(username, pwd, domain);
            using (var client = new HttpClient(sHandler))
            {
                client.BaseAddress = new Uri("http://121.40.75.24:5555/origin/api/data/v8.0/accounts");
                client.DefaultRequestHeaders.Accept.Clear();
                HttpRequestMessage createRequest2 = new HttpRequestMessage(HttpMethod.Post, "");
                client.DefaultRequestHeaders.Add("ContentType", "application/json; charset=utf-8");
                client.DefaultRequestHeaders.Add("OData-MaxVersion", "4.0");
                client.DefaultRequestHeaders.Add("OData-Version", "4.0");
                createRequest2.Content = new StringContent("{\"name\":\"DTCC\"}", Encoding.UTF8, "application/json");
                HttpResponseMessage createResponse2 = await client.SendAsync(createRequest2);

                if (createResponse2.StatusCode == HttpStatusCode.NoContent)
                {
                    var demoUri = createResponse2.Headers.GetValues("OData-EntityId").FirstOrDefault();
                }
                else
                {
                    var exception = new CrmHttpResponseException(createResponse2.Content);
                }
            }
        }
  看下結果,準確的抓到了我外掛中丟擲的exception錯


   示例程式碼中用到的CrmHttpResponseException類程式碼如下

 public class CrmHttpResponseException : System.Exception
        {
            #region Properties
            private static string _stackTrace;
            /// <summary>
            /// Gets a string representation of the immediate frames on the call stack.
            /// </summary>
            public override string StackTrace
            {
                get { return _stackTrace; }
            }

            #endregion Properties
            #region Constructors
            /// <summary>
            /// Initializes a new instance of the CrmHttpResponseException class.
            /// </summary>
            /// <param name="content">The populated HTTP content in Json format.</param>

            public CrmHttpResponseException(HttpContent content) : base(ExtractMessageFromContent(content)) { }


            /// <summary>
            /// Initializes a new instance of the CrmHttpResponseException class.
            /// </summary>
            /// <param name="content">The populated HTTP content in Json format.</param>
            /// <param name="innerexception">The exception that is the cause of the current exception,or a null reference
            /// if no innerexception is specified.</param>

            public CrmHttpResponseException(HttpContent content, Exception innerexception) : base(ExtractMessageFromContent(content), innerexception) { }

            #endregion Constructors
            #region Methods
            /// <summary>
            /// Extracts the CRM specific error message and stack trace from an HTTP content. 
            /// </summary>
            /// <param name="content">The HTTP content in Json format.</param>
            /// <returns>The error message.</returns>


            private static string ExtractMessageFromContent(HttpContent content)
            {
                string message = String.Empty;
                string downloadedContent = content.ReadAsStringAsync().Result;
                if (content.Headers.ContentType.MediaType.Equals("text/plain"))
                {
                    message = downloadedContent;
                }
                else if (content.Headers.ContentType.MediaType.Equals("application/json"))
                {
                    JObject jcontent = (JObject)JsonConvert.DeserializeObject(downloadedContent);
                    IDictionary<string, JToken> d = jcontent;

                    // An error message is returned in the content under the 'error' key. 

                    if (d.ContainsKey("error"))
                    {
                        JObject error = (JObject)jcontent.Property("error").Value;
                        message = (String)error.Property("message").Value;
                    }
                    else if (d.ContainsKey("Message"))
                        message = (String)jcontent.Property("Message").Value;
                    if (d.ContainsKey("StackTrace"))
                        _stackTrace = (String)jcontent.Property("StackTrace").Value;
                }
                else if (content.Headers.ContentType.MediaType.Equals("text/html"))
                {
                    message = "HTML content that was returned is shown below.";
                    message += "\n\n" + downloadedContent;
                }
                else
                {
                    message = String.Format("No handler is available for content in the {0} format.", content.Headers.ContentType.MediaType.ToString());
                }
                return message;
                #endregion Methods
            }
        }
    最後感謝路人甲提供的參考程式碼。



相關文章