在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 } }最后感谢路人甲提供的参考代码。