I am new to silverlight. I am programming in Visual Studio 2010 for Windows phone.
I try to do HttpWebRequest but debugger says ProtocolViolationException.
This my code
private void log_Click(object sender, RoutedEventArgs e)
{
//auth thi is my url for request
string auth;
string login = Uri.EscapeUriString(this.login.Text);
string password = Uri.EscapeUriString(this.pass.Password);
auth = "https://api.vk.com/oauth/token";
auth += "?grant_type=password" + "&client_id=*****&client_secret=******&username=" + login + "&password=" + password + "&scope=notify,friends,messages";
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(auth);
request.BeginGetRequestStream(RequestCallBack, request);//on this line debager say ProtocolViolationExceptio
}
void RequestCallBack(IAsyncResult result)
{
HttpWebRequest request = result.AsyncState as HttpWebRequest;
Stream stream = request.EndGetRequestStream(result);
request.BeginGetResponse(ResponceCallBack, request);
}
void ResponceCallBack(IAsyncResult result)
{
HttpWebRequest request = result.AsyncState as HttpWebRequest;
HttpWebResponse response = request.EndGetResponse(result) as HttpWebResponse;
using (StreamReader sr = new StreamReader(response.GetResponseStream()))
{
string a =sr.ReadToEnd();
MessageBox.Show(a);
}
}
I think the problem is that you aren't using POST, but GET. Try this:
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(auth);
request.Method = "POST";
request.BeginGetRequestStream(RequestCallBack, request);
You aren't even doing anything with the request stream when you get it.
HttpWebRequest is assuming that the reason you tried to get it, was to write content to it (the only reason for getting it, after all).
Since you aren't allowed to include content in a GET request, it realises that the only thing you can do with that stream, is something that would violate the HTTP protocol. As a tool for using the HTTP protocol, it's its job to stop you making that mistake.
So it throws ProtocolViolationException.
Cut out the bit about the request stream - it's only for POST and PUT. Go straight to GetResponse() or BeginGetResponse() at that point.
Related
I am new to silverlight. I am programming in Visual Studio 2010 for Windows phone.
I try to do HttpWebRequest but debugger says ProtocolViolationException.
This my code
private void log_Click(object sender, RoutedEventArgs e)
{
//auth thi is my url for request
string auth;
string login = Uri.EscapeUriString(this.login.Text);
string password = Uri.EscapeUriString(this.pass.Password);
auth = "https://api.vk.com/oauth/token";
auth += "?grant_type=password" + "&client_id=*****&client_secret=******&username=" + login + "&password=" + password + "&scope=notify,friends,messages";
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(auth);
request.BeginGetRequestStream(RequestCallBack, request);//on this line debager say ProtocolViolationExceptio
}
void RequestCallBack(IAsyncResult result)
{
HttpWebRequest request = result.AsyncState as HttpWebRequest;
Stream stream = request.EndGetRequestStream(result);
request.BeginGetResponse(ResponceCallBack, request);
}
void ResponceCallBack(IAsyncResult result)
{
HttpWebRequest request = result.AsyncState as HttpWebRequest;
HttpWebResponse response = request.EndGetResponse(result) as HttpWebResponse;
using (StreamReader sr = new StreamReader(response.GetResponseStream()))
{
string a =sr.ReadToEnd();
MessageBox.Show(a);
}
}
I think the problem is that you aren't using POST, but GET. Try this:
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(auth);
request.Method = "POST";
request.BeginGetRequestStream(RequestCallBack, request);
You aren't even doing anything with the request stream when you get it.
HttpWebRequest is assuming that the reason you tried to get it, was to write content to it (the only reason for getting it, after all).
Since you aren't allowed to include content in a GET request, it realises that the only thing you can do with that stream, is something that would violate the HTTP protocol. As a tool for using the HTTP protocol, it's its job to stop you making that mistake.
So it throws ProtocolViolationException.
Cut out the bit about the request stream - it's only for POST and PUT. Go straight to GetResponse() or BeginGetResponse() at that point.
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.
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";
I have create an Csv File in my phone ( I have this content and this path ) and, url to post this csv...
string path = csv.path;
string content = csv.content;
string urlPost = csv.urlPost;
I want to post my File ( just one csv file ) with the HttpWebRequest, for windows phone, I saw lot of post for HttpWebRequest in C# , and never specific to windows Phone ( HttpWebRequest for windows phone doesn't have all method of "normal" HttpWebRequest) .
I have already saw the msdn page => http://msdn.microsoft.com/en-us/library/debx8sh9.aspx
and this post for HttpWebRequest in c# Upload files with HTTPWebrequest (multipart/form-data) But I don't arrived to translate examples for windows phone.
I arrived to called my server ( with my Url) but, the file are never transmitted...
Also, I don't want use the RestSharp library.
My actually code =>
public void SentPostReport()
{
Uri uri = new Uri(csv.urlPost); //Url is string url
string boundary = "----------------------------" + DateTime.Now.Ticks.ToString("x");
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(uri);
request.ContentType = "multipart/form-data; boundary=" + boundary;
request.Method = "POST";
request.BeginGetRequestStream(new AsyncCallback(GetRequestStreamCallback), request);
}
private void GetRequestStreamCallback(IAsyncResult asynchronousResult)
{
HttpWebRequest request = (HttpWebRequest)asynchronousResult.AsyncState;
// End the operation
Stream postStream = request.EndGetRequestStream(asynchronousResult);
// My File content and path.
string pathReportFile = csv.path;
string CsvContent = csv.content;
// Transmitted The File ????
postStream.Close();
// Start the asynchronous operation to get the response
request.BeginGetResponse(new AsyncCallback(GetResponseCallback), request);
}
private static 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.ReadLine();
//DEBUG => affiche le résultat de la requête.
Debug.WriteLine(responseString);
// Close the stream object
streamResponse.Close();
streamRead.Close();
// Release the HttpWebResponse
response.Close();
}
I have delete my code in the GetRequestStreamCallback's function , and replace by "// transmitted file ? "
I think it's the places where I have to send my file, but I don't find the solution to transmitted this.
I have testing with this code :
byte[] byteArray = Encoding.UTF8.GetBytes(CsvContent);
postStream.Write(byteArray, 0, byteArray.Length);
and other found in different forum, and I every times, teh call with my server is good, but file isn't transmitted...
Have you a solution for use HttpWebRequest and Stream for send my file in my server?
In advance : thanks!!
Well, I just found this project, is just a single helper class, is very simple and helpful.
MultipartHttpClient
Hope this helps
I have create an "csv file" in my windows phone,
I want to post it, in a server, in the web and I don't find how I want to proceed for that,
I don't want just make a "post request" with parameters, I want to post my File in the server...
Actually, I'm connect to this server, but it don't find my file...
public void SentPostReport()
{
//Post response.
string url = this.CurentReportkPI.configXml.gw; // string url
Uri uri = new Uri(url);
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(uri);
request.Accept = "application/CSV";
request.Method = "POST";
request.BeginGetRequestStream(new AsyncCallback(GetRequestStreamCallback), request);
}
private void GetRequestStreamCallback(IAsyncResult asynchronousResult)
{
HttpWebRequest request = (HttpWebRequest)asynchronousResult.AsyncState;
// End the operation
Stream postStream = request.EndGetRequestStream(asynchronousResult);
// I create My csv File
CreateCsv reportCsv = new CreateCsv();
string pathReportFile = reportCsv.CreateNewReport(this.report);
string CsvContent = reportCsv.ReadFile(pathReportFile);
// Convert the string into a byte array.
byte[] byteArray = Encoding.UTF8.GetBytes(CsvContent);
// Write to the request stream.
postStream.Write(byteArray, 0, byteArray.Length);
postStream.Close();
// Start the asynchronous operation to get the response
request.BeginGetResponse(new AsyncCallback(GetResponseCallback), request);
}
private static void GetResponseCallback(IAsyncResult asynchronousResult)
{
Debug.WriteLine("GetResponseCallback");
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.ReadLine();
// Close the stream object
streamResponse.Close();
streamRead.Close();
// Release the HttpWebResponse
response.Close();
}
Have you an idea when I proceed for resolve my problem,and send my CSV File with my request ?
Thanks.
Not sure if this is the problem here, but on a POST request, you are supposed to set the ContentLength and ContentType ("application/x-www-form-urlencoded") headers, amongst other things...
Please check this "how-to" article on a fully correct POST request -- It's not for Windows Phone, but I think you'll still get the full ideia!
On the other hand, I'd suggest you just go with RestSharp that will solve all these problems for you!
you can do this easily using RestSharp or Hammock with the AddFile method. Here's an example of what i did for uploading a photo using Hammock:
var request = new RestRequest("photo", WebMethod.Post);
request.AddParameter("photo_album_id", _album.album_id);
request.AddFile("photo", filename, e.ChosenPhoto);
request.Client.BeginRequest(request, (restRequest, restResponse, userState) =>
{
// handle response
}