I have the following code:
private void GetRequestStreamCallback(IAsyncResult asynchronousResult)
{
HttpWebRequest request = (HttpWebRequest)asynchronousResult.AsyncState;
// End the operation
Stream postStream = request.EndGetRequestStream(asynchronousResult);
//Console.WriteLine("Please enter the input data to be posted:");
//string postData = Console.ReadLine();
string postData = "my data";
// Convert the string into a byte array.
byte[] byteArray = Encoding.UTF8.GetBytes(postData);
// Write to the request stream.
postStream.Write(byteArray, 0, postData.Length);
postStream.Close();
// Start the asynchronous operation to get the response
IAsyncResult result =
(IAsyncResult)request.BeginGetResponse(new AsyncCallback(GetResponseCallback), request);
}
private void GetResponseCallback(IAsyncResult asynchronousResult)
{
HttpWebRequest request = (HttpWebRequest)asynchronousResult.AsyncState;
// End the operation
HttpWebResponse response = (HttpWebResponse)request.EndGetResponse(asynchronousResult);
Stream streamResponse = response.GetResponseStream();
StreamReader streamRead = new StreamReader(streamResponse);
string responseString = streamRead.ReadToEnd();
Console.WriteLine(responseString);
// Close the stream object
streamResponse.Close();
streamRead.Close();
// Release the HttpWebResponse
response.Close();
allDone.Set();
Dispatcher.BeginInvoke((Action)(() => Debug.WriteLine("George")));
}
However when my code hits BeginGetResponse it never exits (and I do not hit a breakpoint in the GetResponseCallback function). I tried adding the BeginInvoke call, but I still never enter this method. This code works in a windows console app - it's on Windows Phone 7 that it doesn'teorg
Can anyone see what I am doing wrong?
Thanks.
If you have created the HttpWebRequest on the UI thread, then make sure you don't block the UI thread, otherwise you can deadlock.
The sample from the desktop .NET you have linked isn't optimized for the current phone networking stack. You should change the code so that you create the HttpWebRequest on a background thread.
I can't see what's wrong with your code (maybe a complete example of what you're trying to do may help) but here's a simple working example of a way of performing the action you want to do.
It posts some data to a URI and then passes the repsonse to a callback function:
Simply execute like this (use of a BackgroundWorker is not necessary but is recommended)
var bw = new BackgroundWorker();
bw.DoWork += (o, args) => PostDataToWebService("http://example.com/something", "key=value&key2=value2", MyCallback);
bw.RunWorkerAsync();
Here's the callback function it refers to:
(You can change this however is appropriate to your needs.)
public static void MyCallback(string aString, Exception e)
{
Deployment.Current.Dispatcher.BeginInvoke(() =>
{
if (e == null)
{
// aString is the response from the web server
MessageBox.Show(aString, "success", MessageBoxButton.OK);
}
else
{
MessageBox.Show(e.Message, "error", MessageBoxButton.OK);
}
});
}
Here's the actual method:
public void PostDataToWebService(string url, string data, Action<string, Exception> callback)
{
if (callback == null)
{
throw new Exception("callback may not be null");
}
try
{
var uri = new Uri(url, UriKind.Absolute);
var req = HttpWebRequest.CreateHttp(uri);
req.ContentType = "application/x-www-form-urlencoded";
req.Method = "POST";
AsyncCallback GetTheResponse = ar =>
{
try
{
var result = ar.GetResponseAsString();
callback(result, null);
}
catch (Exception ex)
{
callback(null, ex);
}
};
AsyncCallback SetTheBodyOfTheRequest = ar =>
{
var request = ar.SetRequestBody(data);
request.BeginGetResponse(GetTheResponse, request);
};
req.BeginGetRequestStream(SetTheBodyOfTheRequest, req);
}
catch (Exception ex)
{
callback(null, ex);
}
}
and here are the extension/helper methods it uses:
public static class IAsyncResultExtensions
{
public static string GetResponseAsString(this IAsyncResult asyncResult)
{
string responseString;
var request = (HttpWebRequest)asyncResult.AsyncState;
using (var resp = (HttpWebResponse)request.EndGetResponse(asyncResult))
{
using (var streamResponse = resp.GetResponseStream())
{
using (var streamRead = new StreamReader(streamResponse))
{
responseString = streamRead.ReadToEnd();
}
}
}
return responseString;
}
public static HttpWebRequest SetRequestBody(this IAsyncResult asyncResult, string body)
{
var request = (HttpWebRequest)asyncResult.AsyncState;
using (var postStream = request.EndGetRequestStream(asyncResult))
{
using (var memStream = new MemoryStream())
{
var content = body;
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);
}
}
return request;
}
}
Related
I'm trying to post a piece of data but it seems to be getting caught and hangs (but not throwing an error).
internal IAsyncResult RequestGet<TPostType>(Action<string> callback, string path, TPostType value)
{
var http = (HttpWebRequest)WebRequest.Create(Connection.GetUri(path).Uri);
http.Accept = "application/json";
http.ContentType = "application/json";
http.Method = "POST";
var parsedContent = JsonConvert.SerializeObject(value);
var encoding = new ASCIIEncoding();
var bytes = encoding.GetBytes(parsedContent);
return http.BeginGetRequestStream(ar =>
{
try
{
var stream = http.EndGetRequestStream(ar);
stream.Write(bytes, 0, bytes.Length);
stream.Close();
http.BeginGetResponse(body =>
{
// its around here that it hangs.
var response = http.EndGetResponse(ar);
var s = response.GetResponseStream();
ReadStream(callback, s);
}, null);
}
catch (WebException webex)
{
WebResponse errResp = webex.Response;
using (Stream respStream = errResp.GetResponseStream())
{
Console.WriteLine(new StreamReader(respStream).ReadToEnd());
}
}
}, null);
}
There were a few times when it didn't hang but told me that the request body was missing, however I didn't make any progress beyond that. Could someone please inform me as to what I'm doing wrong?
The ReadStream method works for GET requests, but for context:
private static IAsyncResult ReadStream(Action<string> callback, Stream stream)
{
var buffer = new byte[5000];
var asyncResult = stream.BeginRead(buffer, 0, 5000, ar2 =>
{
try
{
callback(Encoding.UTF8.GetString(buffer, 0, 5000));
}
catch (Exception ex)
{
// do better error handling
Console.WriteLine("exception reading stream");
Console.WriteLine(ex);
}
}, null);
return asyncResult;
}
For more context on how its being used:
public IAsyncResult BeginGetChainPart(Action<BlockData.BlockList> callback, int height)
{
var asyncResult = new HttpConnector(Connection).RequestGet(body =>
{
callback(JsonConvert.DeserializeObject<BlockData.BlockList>(body));
}, "/local/chain/blocks-after", new BlockData.BlockHeight { Height = height });
return asyncResult;
}
found the solution, posting in case anyone comes across the same issue:
internal IAsyncResult RequestGet<TPostType>(Action<string> callback, string path, TPostType value)
{
var http = (HttpWebRequest)WebRequest.Create(Connection.GetUri(path).Uri);
http.Accept = "application/json";
http.ContentType = "application/json";
http.Method = "POST";
var parsedContent = JsonConvert.SerializeObject(value);
var encoding = new ASCIIEncoding();
var bytes = encoding.GetBytes(parsedContent);
return http.BeginGetRequestStream(ar => {
try
{
var stream = http.EndGetRequestStream(ar);
stream.Write(bytes, 0, bytes.Length);
stream.Close();
var response = http.GetResponse();
var responseStream = response.GetResponseStream();
ReadStream(callback, responseStream);
}
catch (WebException webex)
{
WebResponse errResp = webex.Response;
using (Stream respStream = errResp.GetResponseStream())
{
StreamReader reader = new StreamReader(respStream);
string text = reader.ReadToEnd();
Console.WriteLine(text);
}
}
}, null);
}
I am making an async request, BeginGetRequestStream, where the callback handles the EndRequest. I would like to send any exceptions happening in the callback method ReadCallback(), back to the main calling method InsertSoapEnvelopeIntoWebRequest.
private void InsertSoapEnvelopeIntoWebRequest(XmlDocument soapEnvelopeXml,
HttpWebRequest webRequest)
{
try
{
webRequest.ContentLength = soapEnvelopeXml.InnerXml.Length;
this.soapEnvelopeXml = soapEnvelopeXml;
allDone = new ManualResetEvent(false);
IAsyncResult r = (IAsyncResult)webRequest.BeginGetRequestStream(
new AsyncCallback(ReadCallback), webRequest);
allDone.WaitOne();
}
catch(Exception ex)
{
throw;
}
}
private void ReadCallback(IAsyncResult asynchronousResult)
{
HttpWebRequest myRequestState = (HttpWebRequest)asynchronousResult.AsyncState;
byte[] byteArray = null;
using (Stream streamResponse =
myRequestState.EndGetRequestStream(asynchronousResult))
{
byteArray = Encoding.UTF8.GetBytes(soapEnvelopeXml.InnerXml);
streamResponse.Write(byteArray, 0, byteArray.Length);
}
allDone.Set();
}
How do I achieve this ?
Thanks,
Gagan
This question has been asked a million times, and yet none of the responses work for me. The one I was most excited about was Http Post for Windows Phone 8 but because it requires delegates, it's not right for my code... the Postdata function is called from repositories, it would be nice to get a response straight from this function!
How do I add post parameters to this code? I've been trying to get it to work for a good 10 hours now.
// Repository code
string url = "/bla/bla/" + blaId + "/";
Dictionary<string, string> postParams = new Dictionary<string, string>();
postParams.Add("value", message);
string response = await BlaDataContext.PostData(url, postParams);
// ...
public static async Task<string> PostData(string url, Dictionary<String, String> postParams)
{
HttpWebRequest request = WebRequest.CreateHttp(APIURL + url);
request.ContentType = "application/x-www-form-urlencoded";
request.Method = "POST";
postParams.Add("oauth_token", Contract.AccessToken); // where do I add this to the request??
try
{
HttpWebResponse response = (HttpWebResponse)await request.GetResponseAsync();
Debug.WriteLine(response.ContentType);
Stream responseStream = response.GetResponseStream();
string data;
using (var reader = new StreamReader(responseStream))
{
data = reader.ReadToEnd();
}
responseStream.Close();
return data;
}
catch (Exception e)
{
// whatever
}
}
HttpWebRequest request = WebRequest.CreateHttp("" + url);
//we could move the content-type into a function argument too.
request.ContentType = "application/x-www-form-urlencoded";
request.Method = "POST";
postParams.Add("oauth_token", ""); // where do I add this to the request??
try
{
//this is how you do it
using(var stream = await request.GetRequestStreamAsync())
{
byte[] jsonAsBytes = Encoding.UTF8.GetBytes(string.Join("&", postParams.Select(pp => pp.Key + "=" + pp.Value)));
await stream.WriteAsync(jsonAsBytes, 0, jsonAsBytes.Length);
}
HttpWebResponse response = (HttpWebResponse)await request.GetResponseAsync();
Debug.WriteLine(response.ContentType);
System.IO.Stream responseStream = response.GetResponseStream();
string data;
using (var reader = new System.IO.StreamReader(responseStream))
{
data = reader.ReadToEnd();
}
responseStream.Close();
return data;
}
Async Await HttpWebRequest Extensions:
public static class HttpExtensions
{
public static Task<Stream> GetRequestStreamAsync(this HttpWebRequest request)
{
var tcs = new TaskCompletionSource<Stream>();
try
{
request.BeginGetRequestStream(iar =>
{
try
{
var response = request.EndGetRequestStream(iar);
tcs.SetResult(response);
}
catch (Exception exc)
{
tcs.SetException(exc);
}
}, null);
}
catch (Exception exc)
{
tcs.SetException(exc);
}
return tcs.Task;
}
public static Task<HttpWebResponse> GetResponseAsync(this HttpWebRequest request)
{
var taskComplete = new TaskCompletionSource<HttpWebResponse>();
request.BeginGetResponse(asyncResponse =>
{
try
{
HttpWebRequest responseRequest = (HttpWebRequest)asyncResponse.AsyncState;
HttpWebResponse someResponse =
(HttpWebResponse)responseRequest.EndGetResponse(asyncResponse);
taskComplete.TrySetResult(someResponse);
}
catch (WebException webExc)
{
HttpWebResponse failedResponse = (HttpWebResponse)webExc.Response;
taskComplete.TrySetResult(failedResponse);
}
}, request);
return taskComplete.Task;
}
}
With the extensions, I think it's a little cleaner.
You need to write the parameters to the request body.
You could use an extension method like this one:
public static void AddFormData(this HttpWebRequest request, IDictionary<string, string> data)
{
using (var memStream = new MemoryStream())
using (var writer = new StreamWriter(memStream))
{
bool first = true;
foreach (var d in data)
{
if (!first)
writer.Append("&");
writer.Write(Uri.EscapeDataString(d.Key));
writer.Write("=");
writer.Write(Uri.EscapeDataString(d.Value));
first = false;
}
writer.Flush();
request.ContentLength = memStream.Length;
memStream.Position = 0;
using (var reqStream = request.GetRequestStream())
{
memStream.CopyTo(reqStream);
}
}
}
Call it like this:
request.AddFormData(postParams);
I have class to create user and return the info of user (success).
class POST
{
public HttpWebRequest objRequest = null;
//public static string myRequestData = string.Empty;
public String myRequestData = String.Empty;
public String urlAddress = "http://hackathon.kimhieu.info/flashcard/index.php/api/user";
public String responseString {get;set;}
public void doSend()
{
StringBuilder completeUrl = new StringBuilder(urlAddress);
objRequest = (HttpWebRequest)WebRequest.Create(urlAddress.ToString());
objRequest.ContentType ="application/x-www-form-urlencoded";
objRequest.Method = "POST";
//Adding headers
//objRequest.Headers["Header"]= "Your Value";
//objRequest.Headers["Content-Language"] = "en-US";
myRequestData = "username=abcdef&password=abcdef";
//Begins the asynchronous request
objRequest.BeginGetRequestStream(new AsyncCallback(GetRequestStreamCallback),objRequest);
}
private void GetRequestStreamCallback(IAsyncResult asyncResult)
{
HttpWebRequest objHttpWebRequest = (HttpWebRequest)asyncResult.AsyncState;
// End the operation
Stream postStream = objHttpWebRequest.EndGetRequestStream(asyncResult);
// Convert the string into a byte array.
byte[] byteArray = Encoding.UTF8.GetBytes(myRequestData);
// Write to the request stream.
postStream.Write(byteArray, 0, myRequestData.Length);
postStream.Close();
// Start the asynchronous operation to get the response
objHttpWebRequest.BeginGetResponse(new AsyncCallback(GetResponseCallback), objHttpWebRequest);
}
private void GetResponseCallback(IAsyncResult asyncResult)
{
HttpWebRequest objHttpWebRequest = (HttpWebRequest)asyncResult.AsyncState;
HttpWebResponse objHttpWebResponse = (HttpWebResponse)objHttpWebRequest.EndGetResponse(asyncResult);
Stream objStreamResponse = objHttpWebResponse .GetResponseStream();
StreamReader objStreamReader = new StreamReader(objStreamResponse );
responseString = objStreamReader.ReadToEnd(); // Got response here
myRequestData = "AAA";
//MessageBox.Show("RESPONSE :" + responseString);
// Close the stream object
objStreamResponse .Close();
objStreamReader.Close();
objHttpWebResponse.Close();
}
}
I call in Main.xaml.cs
POST ab = new POST();
ab.doSend();
MessageBox.Show(ab.responseString);
But It return Empty String
I have try to assign some String in class POST myData but it not executed.
I think GetResponseCallback(IAsyncResult asyncResult) not true.
How can I fix it.
Thank for advance !
You write async code, but try to read responseString synchronously. Just add new event to your Post class:
public event Action Completed;
and run it from the end of method GetResponseCallback:
if(Completed != null)
Completed();
and rewrite your code such way:
POST ab = new POST();
ab.Completed += () => { MessageBox.Show(ab.responseString); };
ab.doSend();
It should work
I am new to Windows Phone 7 application development. I am trying to call a URL in my program using POST method which takes some parameters. After the successful post I am supposed to get the response in JSON format. But I am not getting the response. The code I am using is:
public void Submit()
{
// Prepare web request...
HttpWebRequest myRequest = (HttpWebRequest)WebRequest.Create(new Uri(someUrl, UriKind.Absolute));
myRequest.Method = "POST";
myRequest.ContentType = string.Format("multipart/form-data; boundary={0}", boundary);
myRequest.BeginGetRequestStream(new AsyncCallback(GetRequestStreamCallback), myRequest);
}
public string url { get; set; }
private Dictionary<string, string> _parameters = new Dictionary<string, string>();
public Dictionary<string, string> parameters
{
get { return _parameters; }
set { _parameters = value; }
}
string boundary = "----------" + DateTime.Now.Ticks.ToString();
private void GetRequestStreamCallback(IAsyncResult asynchronousResult)
{
HttpWebRequest request = (HttpWebRequest)asynchronousResult.AsyncState;
Stream postStream = request.EndGetRequestStream(asynchronousResult);
parameters.Add("userid", "0");
parameters.Add("locationid", "0");
writeMultipartObject(postStream, parameters);
postStream.Close();
request.BeginGetResponse(new AsyncCallback(GetResponseCallback), request);
}
private void GetResponseCallback(IAsyncResult asynchronousResult)
{
HttpWebRequest request = (HttpWebRequest)asynchronousResult.AsyncState;
HttpWebResponse response = (HttpWebResponse)request.EndGetResponse(asynchronousResult);
Stream streamResponse = response.GetResponseStream();
StreamReader streamRead = new StreamReader(streamResponse);
streamResponse.Close();
streamRead.Close();
// Release the HttpWebResponse
response.Close();
}
public void writeMultipartObject(Stream stream, object data)
{
StreamWriter writer = new StreamWriter(stream);
if (data != null)
{
foreach (var entry in data as Dictionary<string, string>)
{
WriteEntry(writer, entry.Key, entry.Value);
}
}
writer.Write("--");
writer.Write(boundary);
writer.WriteLine("--");
writer.Flush();
}
private void WriteEntry(StreamWriter writer, string key, object value)
{
if (value != null)
{
writer.Write("--");
writer.WriteLine(boundary);
if (value is byte[])
{
byte[] ba = value as byte[];
writer.WriteLine(#"Content-Disposition: form-data; name=""{0}""; filename=""{1}""", key, "sentPhoto.jpg");
writer.WriteLine(#"Content-Type: application/octet-stream");
//writer.WriteLine(#"Content-Type: image / jpeg");
writer.WriteLine(#"Content-Length: " + ba.Length);
writer.WriteLine();
writer.Flush();
Stream output = writer.BaseStream;
output.Write(ba, 0, ba.Length);
output.Flush();
writer.WriteLine();
}
else
{
writer.WriteLine(#"Content-Disposition: form-data; name=""{0}""", key);
writer.WriteLine();
writer.WriteLine(value.ToString());
}
}
}
I cannot find what the real problem is. Anybody out there to help me out?
Maybe not a 'real' answer, but I always use: http://postclient.codeplex.com/ when dealing with Posts. This just to be sure I don't write any faults with the Request code.
Just give it a try.
This example come from http://northernlights.codeplex.com
/// <summary>
/// Send error report (exception) to HTTP endpoint.
/// </summary>
/// <param name="uri">The Endpoint to report to.</param>
/// <param name="exception">Exception to send.</param>
public void SendExceptionToHttpEndpoint(string uri, ExceptionContainer exception)
{
if (!this.AllowAnonymousHttpReporting)
{
return;
}
try
{
HttpWebRequest webRequest = (HttpWebRequest)WebRequest.Create(uri);
webRequest.Method = "POST";
webRequest.ContentType = "application/x-www-form-urlencoded";
webRequest.BeginGetRequestStream(
r =>
{
try
{
HttpWebRequest request1 = (HttpWebRequest)r.AsyncState;
Stream postStream = request1.EndGetRequestStream(r);
string info = string.Format("{0}{1}{2}{1}AppVersion: {3}{1}", exception.Message, Environment.NewLine, exception.StackTrace, exception.AppVersion);
string postData = "&exception=" + HttpUtility.UrlEncode(info);
byte[] byteArray = Encoding.UTF8.GetBytes(postData);
postStream.Write(byteArray, 0, byteArray.Length);
postStream.Close();
request1.BeginGetResponse(
s =>
{
try
{
HttpWebRequest request2 = (HttpWebRequest)s.AsyncState;
HttpWebResponse response = (HttpWebResponse)request2.EndGetResponse(s);
Stream streamResponse = response.GetResponseStream();
StreamReader streamReader = new StreamReader(streamResponse);
string response2 = streamReader.ReadToEnd();
streamResponse.Close();
streamReader.Close();
response.Close();
}
catch
{
}
},
request1);
}
catch
{
}
},
webRequest);
}
catch
{
}
}
It shows you how to post.
WP7 ships with the "Reactive Extensions" that is helpful with asynch interactions in general. This sample http://wp7guide.codeplex.com shows how to use it for HTTP Posts (and other things)
Caveat: the sample is for a rather advanced app, and is meant to show many other things like unit testing, using the MVVM pattern, etc. It might be more sophisticated than what you need.
I got the solution as:
{
Dictionary<string, object> param = new Dictionary<string, object>();
param.Add(DataHolder.USER_ID, "0");
param.Add(DataHolder.DEFAULT_LOCATION_ID, "0");
PostClient proxy = new PostClient(param);
proxy.DownloadStringCompleted += new PostClient.DownloadStringCompletedHandler(proxy_DownloadStringCompleted);
proxy.DownloadStringAsync(new Uri(DataHolder.mainConfigFetchUrl, UriKind.Absolute));
}
void proxy_DownloadStringCompleted(object sender, DownloadStringCompletedEventArgs e)
{
if (e.Error == null)
{
//Process the result...
string data = e.Result;
}
}
For PostClient we will need a WindowsPhonePostClient.dll which can be obtained from http://postclient.codeplex.com/