WebRequest has no GetResponse method - Windows Phone 8 - c#

I want to send a post request to an API with some parameters they ask for... I ended up just creating a string, it's ugly but I do not know a way of making it work differently. I then found lots of variations on this WebRequest class, but unfortunately I cannot get it to work.
Main problem is probably because I am not really understanding how this is all fitting together but basically, the examples I have been following use WebRequest method GetResponse... even on MSDN it has this, so I am wondering why when I try to call it in my code, I am not getting that choice? Same goes for GetRequestStream.
How to add parameters into a WebRequest?
*****DBContext()
{
data = "grant_type=" + GRANTTYPE + "&username=" + username + "&password=" + password + "&client_id=" + CLIENTID + "&redirect_uri=" + REDIRECTURI + "&client_secret=" + CLIENTSECRET;
}
public bool Authenticate()
{
byte[] dataStream = Encoding.UTF8.GetBytes(data);
WebRequest webRequest = WebRequest.Create(urlPath);
webRequest.Method = "POST";
webRequest.ContentType = "application/json";
webRequest.ContentLength = dataStream.Length;
Stream newStream = webRequest.GetRequestStream();
// Send the data.
newStream.Write(dataStream, 0, dataStream.Length);
newStream.Close();
WebResponse webResponse = webRequest.GetResponse();
return true;
}
I also have the question of when I finally do get this stuff to work, what should I be putting in the callback uri. if it's a phone, is it running off of localhost?

The .NET compilation for Windows Phone contains an implementation of the WebRequest class which does not have synchronous methods for obtaining request stream and response, as these would block execution on the UI thread until the operations completed. You can use the existing Begin/End methods directly with callback delegates, or you can wrap those calls in async extensions that will give you the kind of readability and functionality you're used to (more or less). My preferred method is defining extensions, so I will demonstrate this method, but it has no performance advantage over the callback pattern. It does have the up-side of being easily portable any time you need to make use of a WebRequest.
Async/Await Pattern
Define custom extensions for the WebRequest class:
public static class Extensions
{
public static System.Threading.Tasks.Task<System.IO.Stream> GetRequestStreamAsync(this System.Net.WebRequest wr)
{
if (wr.ContentLength < 0)
{
throw new InvalidOperationException("The ContentLength property of the WebRequest must first be set to the length of the content to be written to the stream.");
}
return Task<System.IO.Stream>.Factory.FromAsync(wr.BeginGetRequestStream, wr.EndGetRequestStream, null);
}
public static System.Threading.Tasks.Task<System.Net.WebResponse> GetResponseAsync(this System.Net.WebRequest wr)
{
return Task<System.Net.WebResponse>.Factory.FromAsync(wr.BeginGetResponse, wr.EndGetResponse, null);
}
}
Use the new extensions (be sure to import the namespace where your static Extensions class was defined):
public async System.Threading.Tasks.Task<bool> AuthenticateAsync()
{
byte[] dataStream = System.Text.Encoding.UTF8.GetBytes("...");
System.Net.WebRequest webRequest = System.Net.WebRequest.Create("...");
webRequest.Method = "POST";
webRequest.ContentType = "application/json";
webRequest.ContentLength = dataStream.Length;
Stream newStream = await webRequest.GetRequestStreamAsync();
// Send the data.
newStream.Write(dataStream, 0, dataStream.Length);
newStream.Close();
var webResponse = await webRequest.GetResponseAsync();
return true;
}
Regarding your final note, at the moment I don't see enough information to make sense of what the callback URI is, where it's defined, and how it affects what you're doing.

Related

HttpWebRequest BeginGetRequestStream callback never called

In my Xamarin application I use HttpWebRequest class to send POST messages to the server (I use it because it is available out-of-the box in PCL libraries).
Here is some request preparation code:
request.BeginGetRequestStream (asyncResult => {
Mvx.Trace ("BeginGetRequestStream callback");
request = (HttpWebRequest)asyncResult.AsyncState;
Stream postStream = request.EndGetRequestStream (asyncResult);
string postData = jsonConverter.SerializeObject (objectToSend);
Mvx.Trace ("Posting following JSON: {0}", postData);
byte[] byteArray = Encoding.UTF8.GetBytes (postData);
postStream.Write (byteArray, 0, byteArray.Length);
MakeRequest (request, timeoutMilliseconds, successAction, errorAction);
}, request);
When I start application and execute this code for the first and the second time everything works fine. But when this is executed for the 3rd time (exactly!) the callback is not called and line "BeginGetRequestStream callback" is never printed to log. Is it a bug in class implementation or maybe I do something incorrectly?
If it is not possible to make this working in Xamarin please suggest reliable and convenient class for sending Http GET and POST request with timeout.
Also created related, more general question: Sending Http requests from Xamarin Portable Class Library
My solution to send and receive messages JSON in Xamarin PCL:
public async Task<string> SendMessageJSON(string message, string url)
{
HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create(new Uri(url));
request.ContentType = "application/json";
request.Method = "POST";
// Send data to server
IAsyncResult resultRequest = request.BeginGetRequestStream(null, null);
resultRequest.AsyncWaitHandle.WaitOne(30000); // 30 seconds for timeout
Stream streamInput = request.EndGetRequestStream(resultRequest);
byte[] byteArray = Encoding.UTF8.GetBytes(message);
await streamInput.WriteAsync(byteArray, 0, byteArray.Length);
await streamInput.FlushAsync();
// Receive data from server
IAsyncResult resultResponse = request.BeginGetResponse(null, null);
resultResponse.AsyncWaitHandle.WaitOne(30000); // 30 seconds for timeout
HttpWebResponse response = (HttpWebResponse)request.EndGetResponse(resultResponse);
Stream streamResponse = response.GetResponseStream();
StreamReader streamRead = new StreamReader(streamResponse);
string result = await streamRead.ReadToEndAsync();
await streamResponse.FlushAsync();
return result;
}
Finally solved this by switching to Profile 78 and HttpClient, which works well in all cases.

HttpWebRequest.GetResponse() keeps getting timed out

i wrote a simple C# function to retrieve trade history from MtGox with following API call:
https://data.mtgox.com/api/1/BTCUSD/trades?since=<trade_id>
documented here: https://en.bitcoin.it/wiki/MtGox/API/HTTP/v1#Multi_currency_trades
here's the function:
string GetTradesOnline(Int64 tid)
{
Thread.Sleep(30000);
// communicate
string url = "https://data.mtgox.com/api/1/BTCUSD/trades?since=" + tid.ToString();
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
HttpWebResponse response = (HttpWebResponse)request.GetResponse();
StreamReader reader = new StreamReader(response.GetResponseStream());
string json = reader.ReadToEnd();
reader.Close();
reader.Dispose();
response.Close();
return json;
}
i'm starting at tid=0 (trade id) to get the data (from the very beginning). for each request, i receive a response containing 1000 trade details. i always send the trade id from the previous response for the next request. it works fine for exactly 4 requests & responses. but after that, the following line throws a "System.Net.WebException", saying that "The operation has timed out":
HttpWebResponse response = (HttpWebResponse)request.GetResponse();
here are the facts:
catching the exception and retying keeps causing the same exception
the default HttpWebRequest .Timeout and .ReadWriteTimeout are already high enough (over a minute)
changing HttpWebRequest.KeepAlive to false didn't solve anything either
it seems to always work in the browser even while the function is failing
it has no problems retrieveing the response from https://www.google.com
the amount of successful responses before the exceptions varies from day to day (but browser always works)
starting at the trade id that failed last time causes the exception immediately
calling this function from the main thread instead still caused the exception
running it on a different machine didn't work
running it from a different IP didn't work
increasing Thread.Sleep inbetween requests does not help
any ideas of what could be wrong?
I had the very same issue.
For me the fix was as simple as wrapping the HttpWebResponse code in using block.
using (HttpWebResponse response = (HttpWebResponse) request.GetResponse())
{
// Do your processings here....
}
Details: This issue usually happens when several requests are made to the same host, and WebResponse is not disposed properly. That is where using block will properly dispose the WebResponse object properly and thus solving the issue.
There are two kind of timeouts. Client timeout and server timeout. Have you tried doing something like this:
request.Timeout = Timeout.Infinite;
request.KeepAlive = true;
Try something like this...
I just had similar troubles calling a REST Service on a LINUX Server thru ssl. After trying many different configuration scenarios I found out that I had to send a UserAgent in the http head.
Here is my final method for calling the REST API.
private static string RunWebRequest(string url, string json)
{
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
// Header
request.ContentType = "application/json";
request.Method = "POST";
request.AllowAutoRedirect = false;
request.KeepAlive = false;
request.Timeout = 30000;
request.ReadWriteTimeout = 30000;
request.UserAgent = "test.net";
request.Accept = "application/json";
request.ProtocolVersion = HttpVersion.Version11;
request.Headers.Add("Accept-Language","de_DE");
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls;
ServicePointManager.ServerCertificateValidationCallback = delegate { return true; };
byte[] bytes = Encoding.UTF8.GetBytes(json);
request.ContentLength = bytes.Length;
using (var writer = request.GetRequestStream())
{
writer.Write(bytes, 0, bytes.Length);
writer.Flush();
writer.Close();
}
var httpResponse = (HttpWebResponse)request.GetResponse();
using (var streamReader = new StreamReader(httpResponse.GetResponseStream()))
{
var jsonReturn = streamReader.ReadToEnd();
return jsonReturn;
}
}
This is not a solution, but just an alternative:
These days i almost only use WebClient instead of HttpWebRequest. Especially WebClient.UploadString for POST and PUT and WebClient.DownloadString. These simply take and return strings. This way i don't have to deal with streams objects, except when i get a WebException. i can also set the content type with WebClient.Headers["Content-type"] if necessary. The using statement also makes life easier by calling Dispose for me.
Rarely for performance, i set System.Net.ServicePointManager.DefaultConnectionLimit high and instead use HttpClient with it's Async methods for simultaneous calls.
This is how i would do it now
string GetTradesOnline(Int64 tid)
{
using (var wc = new WebClient())
{
return wc.DownloadString("https://data.mtgox.com/api/1/BTCUSD/trades?since=" + tid.ToString());
}
}
2 more POST examples
// POST
string SubmitData(string data)
{
string response;
using (var wc = new WebClient())
{
wc.Headers["Content-type"] = "text/plain";
response = wc.UploadString("https://data.mtgox.com/api/1/BTCUSD/trades", "POST", data);
}
return response;
}
// POST: easily url encode multiple parameters
string SubmitForm(string project, string subject, string sender, string message)
{
// url encoded query
NameValueCollection query = HttpUtility.ParseQueryString(string.Empty);
query.Add("project", project);
query.Add("subject", subject);
// url encoded data
NameValueCollection data = HttpUtility.ParseQueryString(string.Empty);
data.Add("sender", sender);
data.Add("message", message);
string response;
using (var wc = new WebClient())
{
wc.Headers[HttpRequestHeader.ContentType] = "application/x-www-form-urlencoded";
response = wc.UploadString( "https://data.mtgox.com/api/1/BTCUSD/trades?"+query.ToString()
, WebRequestMethods.Http.Post
, data.ToString()
);
}
return response;
}
Error handling
try
{
Console.WriteLine(GetTradesOnline(0));
string data = File.ReadAllText(#"C:\mydata.txt");
Console.WriteLine(SubmitData(data));
Console.WriteLine(SubmitForm("The Big Project", "Progress", "John Smith", "almost done"));
}
catch (WebException ex)
{
string msg;
if (ex.Response != null)
{
// read response HTTP body
using (var sr = new StreamReader(ex.Response.GetResponseStream())) msg = sr.ReadToEnd();
}
else
{
msg = ex.Message;
}
Log(msg);
}
For what it's worth, I was experiencing the same issues with timeouts every time I used it, even though calls went through to the server I was calling. The problem in my case was that I had Expect set to application/json, when that wasn't what the server was returning.

Windows Phone 8 Http request with custom header

I want to send a HTTP PUT request to a WCF server from Windows Phone 8, and for identification I have to send a custom header. (assume "mycustomheader" = "abc")
I was using WebClient so far, but the Webclient.Headers seems not to have an Add method, so it is not possible to send headers other then the ones in HttpRequestHeader enum. Is there any way to do this with WebClient?
I saw it is possible to set a custom header with HttpWebRequest class, but I just can't get it to do anything at all. My test code (basically the sample copied from http://msdn.microsoft.com/en-us/library/system.net.httpwebrequest.begingetrequeststream.aspx):
public void dosth()
{
HttpWebRequest wr = (HttpWebRequest)WebRequest.Create("http://mycomputer/message");
wr.Method = "PUT";
wr.ContentType = "application/x-www-form-urlencoded";
wr.BeginGetRequestStream(new AsyncCallback(GetRequestStreamCallback), wr);
allDone.WaitOne();
}
private static void GetRequestStreamCallback(IAsyncResult asynchronousResult)
{
HttpWebRequest request = (HttpWebRequest)asynchronousResult.AsyncState;
Stream postStream = request.EndGetRequestStream(asynchronousResult);
string postData = "{'Command': { 'RequestType' : 'Status', 'Test' : '1' }}";
byte[] byteArray = Encoding.UTF8.GetBytes(postData);
postStream.Write(byteArray, 0, postData.Length);
postStream.Close();
request.BeginGetResponse(new AsyncCallback(GetResponseCallback), request);
}
private static void GetResponseCallback(IAsyncResult asynchronousResult)
{
HttpWebRequest request = (HttpWebRequest)asynchronousResult.AsyncState;
HttpWebResponse response = (HttpWebResponse)request.EndGetResponse(asynchronousResult);
Stream streamResponse = response.GetResponseStream();
StreamReader streamRead = new StreamReader(streamResponse);
string responseString = streamRead.ReadToEnd();
streamResponse.Close();
streamRead.Close();
response.Close();
allDone.Set();
}
As I can see with wireshark: nothing is arriving at my computer (same url and everything works fine with WebClient .. except for the custom header). In debugging I can see the GetRequestStreamCallback being fired and running through. But it never arrives in the GetResponseCallback. Most stuff I find regarding this refers to methods like GetResponse() that seem not to be available on
Whats is the way to go here? Is it possible to get the HttpWebRequest to work, or is there some workaround to get the custom header set in WebClient or is there even another better way?
edit: webclient code:
WebClient wc = new WebClient();
wc.Headers[HttpRequestHeader.ContentLength] = data.Length.ToString();
wc.Headers[HttpRequestHeader.ContentType] = "application/x-www-form-urlencoded";
wc.UploadStringAsync(new Uri("http://mycomputer/message"), "PUT", data);
sends the correct data to the correct url. However setting custom header seems not to be possible. (even tried \r\n inside a header ... but this is not allowed and throws exception)
Where do you set the header?
Here is how to do it:
request.Headers["mycustomheader"] = "abc";

GET and POST to ASP.NET MVC via C#

I have a Windows app written in C#. This app will be deployed to my user's desktops. It will interact with a back-end that has already been created. The back-end is written in ASP.NET MVC 3. It exposes a number of GET and POST operations as shown here:
[AcceptVerbs(HttpVerbs.Get)]
public ActionResult GetItem(string id, string caller)
{
// Do stuff
}
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult SaveItem(string p1, string p2, string p3)
{
// Do stuff
}
The web developers on my team are successfully interacting with these operations via JQuery. So I know they work. But I need to figure out how to interact with them from my Windows C# app. I was using the WebClient, but ran into some performance problems so I was consulted to use the WebRequest object. In an honest effort to attempt this, I tried the following:
WebRequest request = HttpWebRequest.Create("http://www.myapp.com/actions/AddItem");
request.Method = "POST";
request.ContentType = "application/x-www-form-urlencoded";
request.BeginGetResponse(new AsyncCallback(AddItem_Completed), request);
My problem is, I'm not sure how to actually send the data (the parameter values) back to my endpoints. How do I send the parameter values back to my GET and POST operations? Can someone give me some help? Thank you!
One way is to write the input to request stream. You need to serialize input to byte array
Please see below sample code
string requestXml = "someinputxml";
byte[] bytes = Encoding.UTF8.GetBytes(requestXml);
var request = (HttpWebRequest)WebRequest.Create(url);
request.Method = "POST";
request.ContentLength = bytes.Length;
request.ContentType = "application/xml";
using (var requestStream = request.GetRequestStream())
{
requestStream.Write(bytes, 0, bytes.Length);
}
using (var response = (HttpWebResponse)request.GetResponse())
{
statusCode = response.StatusCode;
if (statusCode == HttpStatusCode.OK)
{
responseString = new StreamReader(response.GetResponseStream()).ReadToEnd();
}
}
Well, with WebClient the simplest example would be something like this:
NameValueCollection postData = new NameValueCollection();
postData["field-name-one"] = "value-one";
postData["field-name-two"] = "value-two";
WebClient client = new WebClient();
byte[] responsedata = webClient.UploadValues("http://example.com/postform", "POST", postData);
Have you tried this?

GetRequestStream() is throwing time out exception when posting data to HTTPS url

I'm calling an API hosted on Apache server to post data. I'm using HttpWebRequest to perform POST in C#.
API has both normal HTTP and secure layer (HTTPS) PORT on the server. When I call HTTP URL it works perfectly fine. However, when I call HTTPS it gives me time-out exception (at GetRequestStream() function). Any insights? I'm using VS 2010, .Net framework 3.5 and C#. Here is the code block:
string json_value = jsonSerializer.Serialize(data);
HttpWebRequest request = (HttpWebRequest)System.Net.WebRequest.Create("https://server-url-xxxx.com");
request.Method = "POST";
request.ProtocolVersion = System.Net.HttpVersion.Version10;
request.ContentType = "application/x-www-form-urlencoded";
byte[] buffer = Encoding.ASCII.GetBytes(json_value);
request.ContentLength = buffer.Length;
System.IO.Stream reqStream = request.GetRequestStream();
reqStream.Write(buffer, 0, buffer.Length);
reqStream.Close();
EDIT:
The console program suggested by Peter works fine. But when I add data (in JSON format) that needs to be posted to the API, it throws out operation timed out exception. Here is the code that I add to console based application and it throws error.
byte[] buffer = Encoding.ASCII.GetBytes(json_value);
request.ContentLength = buffer.Length;
I ran into the same issue. It seems like it is solved for me. I went through all my code making sure to invoke webResponse.Close() and/or responseStream.Close() for all my HttpWebResponse objects. The documentation indicates that you can close the stream or the HttpWebResponse object. Calling both is not harmful, so I did. Not closing the responses may cause the application to run out of connections for reuse, and this seems to affect the HttpWebRequest.GetRequestStream as far as I can observe in my code.
I don't know if this will help you with your specific problem but you should consider Disposing some of those objects when you are finished with them. I was doing something like this recently and wrapping stuff up in using statements seems to clean up a bunch of timeout exceptions for me.
using (var reqStream = request.GetRequestStream())
{
if (reqStream == null)
{
return;
}
//do whatever
}
also check these things
Is the server serving https in your local dev environment?
Have you set up your bindings *.443 (https) properly?
Do you need to set credentials on the request?
Is it your application pool account accessing the https resources or is it your account being passed through?
Have you thought about using WebClient instead?
using (WebClient client = new WebClient())
{
using (Stream stream = client.OpenRead("https://server-url-xxxx.com"))
using (StreamReader reader = new StreamReader(stream))
{
MessageBox.Show(reader.ReadToEnd());
}
}
EDIT:
make a request from console.
internal class Program
{
private static void Main(string[] args)
{
new Program().Run();
Console.ReadLine();
}
public void Run()
{
var request = (HttpWebRequest)System.Net.WebRequest.Create("https://server-url-xxxx.com");
request.Method = "POST";
request.ProtocolVersion = System.Net.HttpVersion.Version10;
request.ContentType = "application/x-www-form-urlencoded";
using (var reqStream = request.GetRequestStream())
{
using(var response = new StreamReader(reqStream )
{
Console.WriteLine(response.ReadToEnd());
}
}
}
}
Try this:
WebRequest req = WebRequest.Create("https://server-url-xxxx.com");
req.Method = "POST";
string json_value = jsonSerializer.Serialize(data); //Body data
ServicePointManager.Expect100Continue = false;
using (var streamWriter = new StreamWriter(req.GetRequestStream()))
{
streamWriter.Write(json_value);
streamWriter.Flush();
streamWriter.Close();
}
HttpWebResponse resp = req.GetResponse() as HttpWebResponse;
Stream GETResponseStream = resp.GetResponseStream();
StreamReader sr = new StreamReader(GETResponseStream);
var response = sr.ReadToEnd(); //Response
resp.Close(); //Close response
sr.Close(); //Close StreamReader
And review the URI:
Reserved characters. Send reserved characters by the URI can bring
problems ! * ' ( ) ; : # & = + $ , / ? # [ ]
URI Length: You should not exceed 2000 characters
I ran into this, too. I wanted to simulate hundreds of users with a Console app. When simulating only one user, everything was fine. But with more users came the Timeout exception all the time.
Timeout occurs because by default the ConnectionLimit=2 to a ServicePoint (aka website).
Very good article to read: https://venkateshnarayanan.wordpress.com/2013/04/17/httpwebrequest-reuse-of-tcp-connections/
What you can do is:
1) make more ConnectionGroups within a servicePoint, because ConnectionLimit is per ConnectionGroups.
2) or you just simply increase the connection limit.
See my solution:
private HttpWebRequest CreateHttpWebRequest<U>(string userSessionID, string method, string fullUrl, U uploadData)
{
HttpWebRequest req = (HttpWebRequest)HttpWebRequest.Create(fullUrl);
req.Method = method; // GET PUT POST DELETE
req.ConnectionGroupName = userSessionID; // We make separate connection-groups for each user session. Within a group connections can be reused.
req.ServicePoint.ConnectionLimit = 10; // The default value of 2 within a ConnectionGroup caused me always a "Timeout exception" because a user's 1-3 concurrent WebRequests within a second.
req.ServicePoint.MaxIdleTime = 5 * 1000; // (5 sec) default was 100000 (100 sec). Max idle time for a connection within a ConnectionGroup for reuse before closing
Log("Statistics: The sum of connections of all connectiongroups within the ServicePoint: " + req.ServicePoint.CurrentConnections; // just for statistics
if (uploadData != null)
{
req.ContentType = "application/json";
SerializeToJson(uploadData, req.GetRequestStream());
}
return req;
}
/// <summary>Serializes and writes obj to the requestStream and closes the stream. Uses JSON serialization from System.Runtime.Serialization.</summary>
public void SerializeToJson(object obj, Stream requestStream)
{
DataContractJsonSerializer json = new DataContractJsonSerializer(obj.GetType());
json.WriteObject(requestStream, obj);
requestStream.Close();
}
You may want to set timeout property, check it here http://www.codeproject.com/Tips/69637/Setting-timeout-property-for-System-Net-WebClient

Categories