使用POST请求向Jira API发送JSON时的System.Net.WebException

时间:2013-01-17 14:34:52

标签: c# http rest windows-phone-8 jira

好吧,伙计们,我已经在这个问题上挣扎了一天左右,没有明确的解决方案。我将从例外开始:

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)

我正在尝试连接到JIRA rest API以登录用户。我们的JIRA系统目前运行4.4.1,我试图点击的API信息在此处记录:https://developer.atlassian.com/static/rest/jira/4.4.1.html。 (请参阅“/ auth / 1 / session”API的POST请求)

API调用POST请求,其中包含用户凭据的JSON正文。我已经尝试手动构建JSON,以及使用JSON库,结果是相同的。我发送的json是:

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

我试图将内容类型和编码更改为我能想象到的任何内容。这包括“text / json”,“application / json”,将Encoding.UTF8添加到流编写器等。所有结果都是相同的。

也许这整个考验中最令人沮丧的部分是,我能够立刻用Java编写这个Android版本,所以我不认为这是一个API误解,就像Windows Phone 8和/或C#误解。

最后要指出的几点:

  • 如果我更改代码以使用GET请求,请指向“http://www.google.com”,并删除请求回调(直接跳转到响应),一切正常,我得到了我期望的结果
  • 我对HttpWebRequest的“BeginX”“EndX”方法感到困惑。我理解异步任务,但不完全是C#如何管理它。大多数MSDN文档都不使用这些文档,而是使用“GetRequest()”和“GetResponse()”方法,这些方法看起来更加直接。我筛选过的最新例子也使用了这些方法。我假设在Windows Phone 8 SDK中删除了这些方法,以确保可以异步运行的所有内容。
  • 如果我直接从除Wi​​ndows Phone 8模拟器之外的任何浏览器点击JIRA URL,我会得到文档中概述的有效403。但是,如果我直接在模拟器中点击URL,它会提示我输入登录凭据。这让我觉得需要基本的auth,所以我尝试添加它,但我得到了相同的结果。

以下是我目前拥有的代码。我已经取出了我的Jira主机名

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;
    }
}

编辑:为了澄清一下,尝试在此行上生成响应对象时代码失败...

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

更新1:

我发现我可以将WebException的回复转换为HttpWebResponse。这使我能够看到确切的状态代码是什么,HttpStatusCode.UnsupportedMediaType或者415.这现在直接指向发送到服务器的JSON编码的问题。

1 个答案:

答案 0 :(得分:0)

你们会认为我是一个疯子,但截至下午3点左右,我已经得到了预期的结果。

一旦我重构了一下,我将用更新的代码编辑这个答案。

更新了工作代码:

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;
    }
}