System.Net.WebException when sending JSON using POST request to a Jira API

Alright guys, I have been wrestling with this issue for a day or so with no clear resolution. I will start with the exception:

The remote server returned an error: NotFound.
    at System.Net.Browser.AsyncHelper.BeginOnUI(SendOrPostCallback beginMethod, Object state)
    at System.Net.Browser.ClientHttpWebRequest.EndGetResponse(IAsyncResult asyncResult)

I am attempting to connect to the JIRA rest API for logging in a user. Our JIRA system is currently running 4.4.1, and the API information I am attempting to hit is documented here: https://developer.atlassian.com/static/rest/jira/4.4.1.html. (See the POST request for the "/auth/1/session" API)

The API calls for a POST request, with a JSON body for the user credentials. I have tried both building the JSON manually, as well as using a JSON library, and the results were the same. The json I am sending is:

{ 
    "username": "test",
    "password": "test"
}

I have attempted to change the content type and encoding to anything I can imagine. This includes "text/json", "application/json", adding Encoding.UTF8 to the stream writer, etc. All the results are the same.

Perhaps the most frustrating part of this entire ordeal, is that I was able to write this in Java for Android in no time at all, so I do not believe it is an API misunderstanding as so much as a Windows Phone 8 and/or C# misunderstanding.

A few final things to point out:

  • If I change the code to use a GET request, point to "http://www.google.com", and remove the request callback (skipping directly to the response), everything works and I get the result I expect.
  • I am confused by the "BeginX" "EndX" methods for the HttpWebRequest. I understand asynchronous tasks, but just not exactly how C# manages this. Most of the MSDN documentation does not use these, and instead has methods for "GetRequest()" and "GetResponse()" which seem far more straight forward. And most recent examples I have sifted through also use these methods. I am under the assumption that these methods were removed in the Windows Phone 8 SDK to ensure everything that can run asynchronously does.
  • If I hit the JIRA URL directly from any browser except the Windows Phone 8 emulator, I get a valid 403 as outlined by the documentation. However, if I hit the URL directly in the emulator, it prompts me for login credentials. This made me think that basic auth was required, so I have tried adding that but I get the same results.
  • Below is the code as I currently have it. I have taken out my Jira host name

    class LoginService
    {
        public static UserSession login(string aUsername, string aPassword)
        {
            String loginUrl = "http://{myjiraurl}/rest/auth/1/session/";
            HttpWebRequest request = (HttpWebRequest) WebRequest.Create(loginUrl);
    
            string jsonBody = JsonHelper.GenerateLoginJson(aUsername, aPassword);
    
            RequestInformation requestInfo = new RequestInformation();
            requestInfo.request = request;
            requestInfo.JsonBody = jsonBody;
    
            requestInfo.request.Method = "POST";
            requestInfo.request.ContentType = "text/json";
            requestInfo.request.ContentLength = (long)jsonBody.Length;
    
            request.BeginGetRequestStream(new AsyncCallback(LoginRequestCallback), requestInfo);
            return null;
        }
    
        private static void LoginRequestCallback(IAsyncResult result)
        {
            RequestInformation requestInfo = (RequestInformation)result.AsyncState;
            HttpWebRequest webRequest = requestInfo.request;
    
            // End the Asynchronus request.
            Stream requestSream = webRequest.EndGetRequestStream(result);
    
            StreamWriter requestWriter = new StreamWriter(requestSream);
            requestWriter.Write(requestInfo.JsonBody);
            requestWriter.Flush();
            requestWriter.Close();
            requestSream.Close();
    
            webRequest.BeginGetResponse(new AsyncCallback(LoginResponseCallback), requestInfo);
        }
    
        private static void LoginResponseCallback(IAsyncResult result)
        {
            RequestInformation requestInfo = (RequestInformation)result.AsyncState;
            HttpWebRequest webRequest = requestInfo.request;
            try
            {
    
                HttpWebResponse response = (HttpWebResponse)webRequest.EndGetResponse(result);
    
                if (response.StatusCode == HttpStatusCode.OK)
                {
    
                    Stream streamResponse = response.GetResponseStream();
    
                    string responseResult = StreamHelper.ReadStreamToString(streamResponse);
                    streamResponse.Close();
                }
                response.Close();
            }
            catch (Exception e)
            {
                System.Diagnostics.Debug.WriteLine(e.Message);
                System.Diagnostics.Debug.WriteLine(e.StackTrace);
            }
        }
    }
    
    public class RequestInformation
    {
        // This class stores the request state of the request and any necessary information for the request body
        public HttpWebRequest request;
    
        public string JsonBody { get; set; }
        public string Result { get; set; }
    
        public RequestInformation()
        {
            request = null;
        }
    }
    

    Edit: For some clarification, the code is failing when attempting to generate the response object on this line...

    HttpWebResponse response = (HttpWebResponse)webRequest.EndGetResponse(result);
    

    Update 1:

    I have discovered that I can cast the response of the WebException into an HttpWebResponse . This allowed me to see what the exact status code was, which was HttpStatusCode.UnsupportedMediaType or 415. This now points directly at an issue with the JSON encoding that is being sent to the server.


    You guys are going to think I am a lunatic, but as of about 3:00pm I have been getting the expected results.

    I will be editing this answer with the updated code once I refactor it a little bit.

    Updated working code:

    public static async Task<HttpWebResponse> SendHttpPostRequest(string url, string content, string contentType, string acceptType)
        {
            HttpWebRequest request = HttpWebRequest.CreateHttp(new Uri(url, UriKind.Absolute));
            HttpWebResponse response = new HttpWebResponse();
            string responseText = "";
    
            request.Method = "POST";
            request.ContentType = contentType;
            request.Accept = acceptType;
    
            Task<Stream> requestTask = Task.Factory.FromAsync(request.BeginGetRequestStream, asyncResult => request.EndGetRequestStream(asyncResult), (object)null);
            await requestTask.ContinueWith(t =>
            {
                using (Stream stream = requestTask.Result)
                using (StreamWriter requestWriter = new StreamWriter(stream))
                {
                    requestWriter.Write(content);
                }
            });
    
            Task<WebResponse> responseTask = Task.Factory.FromAsync(request.BeginGetResponse, asyncResult => request.EndGetResponse(asyncResult), (object)null);
            await responseTask.ContinueWith(t =>
            {
                try
                {
                    response = (HttpWebResponse)responseTask.Result;
                }
                catch (AggregateException ae)
                {
                    foreach (Exception e in ae.InnerExceptions)
                    {
                        if (e is WebException)
                        {
                            response = (HttpWebResponse)((WebException)e).Response;
                            System.Diagnostics.Debug.WriteLine(e.Message);
                            System.Diagnostics.Debug.WriteLine(e.StackTrace);
                        }
                    }
                }
            });
    
            return response;
        }
    }
    
    链接地址: http://www.djcxy.com/p/45882.html

    上一篇: 从C#代码调用REST服务

    下一篇: System.Net.WebException在使用POST请求向Jira API发送JSON时