HttpWebRequest.EndGetResponse создает исключение NotSupportedException в Windows Phone 7
В проекте Silverlight-Windows Phone 7 я создаю запрос HttpWebRequest, получаю RequestStream, что-то записываю в поток и пытаюсь получить ответ, но всегда получаю NotSupportedException: "System.Net.Browser.OHWRAsyncResult.AsyncWaitHandle бросил исключение типа 'System.NotSupportedException'
Мой производственный код намного сложнее, но я могу сузить его до этого небольшого фрагмента кода:
public class HttpUploadHelper
{
private HttpWebRequest request;
private RequestState state = new RequestState();
public HttpUploadHelper(string url)
{
this.request = WebRequest.Create(url) as HttpWebRequest;
state.Request = request;
}
public void Execute()
{
request.Method = "POST";
this.request.BeginGetRequestStream(
new AsyncCallback(BeginRequest), state);
}
private void BeginRequest(IAsyncResult ar)
{
Stream stream = state.Request.EndGetRequestStream(ar);
state.Request.BeginGetResponse(
new AsyncCallback(BeginResponse), state);
}
private void BeginResponse(IAsyncResult ar)
{
// BOOM: NotSupportedException was unhandled;
// {System.Net.Browser.OHWRAsyncResult}
// AsyncWaitHandle = 'ar.AsyncWaitHandle' threw an
// exception of type 'System.NotSupportedException'
HttpWebResponse response = state.Request.EndGetResponse(ar) as HttpWebResponse;
Debug.WriteLine(response.StatusCode);
}
}
public class RequestState
{
public WebRequest Request;
}
}
Кто-нибудь знает, что не так с этим кодом?
4 ответа
NotSupportedException
может быть брошено, когда поток запроса не закрыт перед вызовом EndGetResponse
, Поток WebRequest все еще открыт и отправляет данные на сервер, когда вы пытаетесь получить ответ. Поскольку поток реализует IDisposable
интерфейс, простое решение состоит в том, чтобы обернуть ваш код, используя поток запросов в using
блок:
private void BeginRequest(IAsyncResult ar)
{
using (Stream stream = request.EndGetRequestStream(ar))
{
//write to stream in here.
}
state.Request.BeginGetResponse(
new AsyncCallback(BeginResponse), state);
}
Блок using гарантирует, что поток будет закрыт, прежде чем вы попытаетесь получить ответ от веб-сервера.
Проблема в том, как вы имеете дело с доступом к исходным запросам в обратном вызове из BeginGetResponse
,
Вместо того чтобы хранить ссылку на состояние, верните ссылку на исходный запрос с помощью:
var request = (HttpWebRequest)asynchronousResult.AsyncState;
Взгляните на этот очень простой (но работающий) пример реализации входа в систему, публикуя учетные данные электронной почты и пароли на веб-сайте.
public static string Email;
public static string Password;
private void LoginClick(object sender, RoutedEventArgs e)
{
Email = enteredEmailAddress.Text.Trim().ToLower();
Password = enteredPassword.Password;
var request = (HttpWebRequest)WebRequest.Create(App.Config.ServerUris.Login);
request.ContentType = "application/x-www-form-urlencoded";
request.Method = "POST";
request.BeginGetRequestStream(ReadCallback, request);
}
private void ReadCallback(IAsyncResult asynchronousResult)
{
var request = (HttpWebRequest)asynchronousResult.AsyncState;
using (var postStream = request.EndGetRequestStream(asynchronousResult))
{
using (var memStream = new MemoryStream())
{
var content = string.Format("Password={0}&Email={1}",
HttpUtility.UrlEncode(Password),
HttpUtility.UrlEncode(Email));
var bytes = System.Text.Encoding.UTF8.GetBytes(content);
memStream.Write(bytes, 0, bytes.Length);
memStream.Position = 0;
var tempBuffer = new byte[memStream.Length];
memStream.Read(tempBuffer, 0, tempBuffer.Length);
postStream.Write(tempBuffer, 0, tempBuffer.Length);
}
}
request.BeginGetResponse(ResponseCallback, request);
}
private void ResponseCallback(IAsyncResult asynchronousResult)
{
var request = (HttpWebRequest)asynchronousResult.AsyncState;
using (var resp = (HttpWebResponse)request.EndGetResponse(asynchronousResult))
{
using (var streamResponse = resp.GetResponseStream())
{
using (var streamRead = new StreamReader(streamResponse))
{
string responseString = streamRead.ReadToEnd();
// do something with responseString to check if login was successful
}
}
}
}
NotSupportedException
также может быть брошено, когда string url
слишком долго Я испортил и прикрепил данные поста к URL, а не к телу поста. Когда данные были короткими, они работали просто отлично, но как только они становились слишком большими - EndGetResponse
разбился.
Изменить это:
state.Request.BeginGetResponse(
new AsyncCallback(BeginResponse), state);
К этому:
state.Request.BeginGetResponse(BeginResponse, state);