request.Method = "POST" working but NOT request.ContentLength - c#

Some times the simple things can stump you and here is one for me.
I want to do a simple web request to verify a username and password. Its working just fine in Windows Phone 8 but I can not seem to get the same code to work on Windows 8.
I understand I can not do a GetResponse as I do with Windows Phone so I am using GetResponseAsync and that part if working fine. But the response from the Server is that it did not get the "POST" component in the header.
Here is the Windows Phone 8 code that is working fine on my Phone version
private async void VerifyUser()
{
//System.Diagnostics.Debug.WriteLine("aa");
loginParams = "username=" + username + "&password=" + password;
string teamResponse = "https://mysite.com/mystuff/LoginApp?" + loginParams;
var request = HttpWebRequest.Create(teamResponse) as HttpWebRequest;
request.Method = "POST";
request.Accept = "application/json;odata=verbose";
var factory = new TaskFactory();
var task = factory.FromAsync<WebResponse>(request.BeginGetResponse, request.EndGetResponse, null);
//System.Diagnostics.Debug.WriteLine("bb");
try
{
var response = await task;
System.IO.Stream responseStream = response.GetResponseStream();
string data;
using (var reader = new System.IO.StreamReader(responseStream))
{
data = reader.ReadToEnd();
}
responseStream.Close();
//System.Diagnostics.Debug.WriteLine("cc");
webData = data;
//MessageBox.Show(data);
}
catch (Exception e)
{
MessageBox.Show("There was a network error. Please check your network connectivty and try again " + e);
}
// System.Diagnostics.Debug.WriteLine(webData);
JToken token = JObject.Parse(webData);
string success = (string)token.SelectToken("success");
Here is what I have for Windows 8 using Visual Studio 2013
private async void VerifyUser()
{
string data;
loginParams = "username=" + logInUserIdString + "&password=" + logInPasswordString;
string teamResponse = "https://mysite.com/mystuff/LoginApp?" + loginParams;
Debug.WriteLine(teamResponse);
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(teamResponse);
HttpWebResponse response = (HttpWebResponse)await request.GetResponseAsync();
using (var sr = new StreamReader(response.GetResponseStream()))
{
data = sr.ReadToEnd();
}
Debug.WriteLine(data);
}
That works but I get back a simple response advising only that the user is logged in or not logged in. The Server chap says that the request did not have "POST" in the header.
SO I added the following code:
request.Method = "POST";
request.Accept = "application/json;odata=verbose";
And here is the full code:
private async void VerifyUser()
{
string data;
loginParams = "username=" + logInUserIdString + "&password=" + logInPasswordString;
string teamResponse = "https://mysite.com/mystuff/LoginApp?" + loginParams;
Debug.WriteLine(teamResponse);
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(teamResponse);
request.Method = "POST";
request.Accept = "application/json;odata=verbose";
HttpWebResponse response = (HttpWebResponse)await request.GetResponseAsync();
using (var sr = new StreamReader(response.GetResponseStream()))
{
data = sr.ReadToEnd();
}
Debug.WriteLine(data);
}
And then it just throws the following:
'web1.exe' (CLR v4.0.30319: Immersive Application Domain): Loaded 'C:\Windows\system32\WinMetadata\Windows.Foundation.winmd'. Skipped loading symbols. Module is optimized and the debugger option 'Just My Code' is enabled.
A first chance exception of type 'System.Net.WebException' occurred in mscorlib.dll
An exception of type 'System.Net.WebException' occurred in mscorlib.dll but was not handled in user code
Additional information: The remote server returned an error: (411) Length Required.
So why can I not include the "POST" in the header as the doco says I can? Any help would be much appreciated.
UPDATE: I now know its an issue with the length of the loginParams. In my IOS, Android and WindowsPhone apps I did not have to specify the length and it works great, but the Visual Studio 2013 Windows App does not accept setting the content length for some reason.
Here is the error:
System.Net.HttpWebRequest does not contain a definition for ContentLength and no extension method ContentLength accepting a fist argument of type System.Net.HttpWebRequest could be found (are you missing a using directive or an assembly reference?)
So why can I not add request.ContentLength???
IN Response to Domniks request for the code I have attached a image of the block of code with the error message. Thanks again for helping.
I have attached an image of my screen where it wont acc

You are not really posting information since all your data is in the URL. You can try changing the method to GET, because that is what you are doing. Or you can write the post data to the request object's request stream and really POST. See here for quick example.

GET Parameter are URL-encoded like your URL: "https://mysite.com/mystuff/LoginApp?" + loginParams
That means you are always sending GET Parameter, just changing the Method do POST wont change anything.
If you want to send POST Parameters, do the following:
byte[] bytes = Encoding.UTF8.GetBytes(loginParams);
request.ContentLength = bytes.Length;
Stream stream = request.GetRequestStream();
stream.Write(bytes, 0, bytes.Length);
stream.Close();

Solved!!!
The correct process to do Http web requests and response with Visual Studio 2013 is to use the new HttpClient class. I suspected it would be some new class like this but just could not find it. 2 days of my life have been wasted!!
So here is the correct code to do a Http request to for example log in or in my case to just verify the user is a valid user based on the userID and password.
private async void VerifyUser()
{
loginParams = "username=" + logInUserIdString + "&password=" + logInPasswordString;
string teamResponse = "https:// mySite.com?" + loginParams;
Debug.WriteLine(teamResponse);
HttpClient client = new HttpClient();
try
{
HttpResponseMessage response = await client.PostAsync(new Uri(teamResponse), null);
response.EnsureSuccessStatusCode();
string responseBody = await response.Content.ReadAsStringAsync();
Debug.WriteLine(responseBody);
}
catch (HttpRequestException e)
{
Debug.WriteLine("\nException Caught!");
Debug.WriteLine("Message :{0} ", e.Message);
}
And thanks heaps to dbugger and Dominik for your help as your comments moved me in the direction that got me to this solution.

Related

Webrequest GET Body ViolationException

I'm using SolrExpress to search and index documents within c# (dotnet core). Inserting (indexing) documents works fine since this is a nice post request.
However when i'm trying to do a select query (to retrieve documents) i'm getting aggregation exceptions. By digging down the source in SolrExpress i came upon the following source:
private WebRequest Prepare(SecurityOptions options, string requestMethod, string handler, string data)
{
var baseUrl = $"{this.HostAddress}/{handler}";
var encoding = new UTF8Encoding();
var bytes = encoding.GetBytes(data);
var request = WebRequest.Create(baseUrl);
if (options.AuthenticationType == AuthenticationType.Basic)
{
var encoded = Convert.ToBase64String(Encoding.GetEncoding("ISO-8859-1").GetBytes(options.UserName + ":" + options.Password));
request.Headers[HttpRequestHeader.Authorization] = "Basic " + encoded;
}
request.Method = requestMethod;
request.ContentType = "application/json";
#if NET451
request.ContentLength = bytes.Length;
#endif
#if NETCORE
var taskStream = request.GetRequestStreamAsync();
taskStream.Wait();
var stream = taskStream.Result;
stream.Write(bytes, 0, bytes.Length);
#else
var stream = request.GetRequestStream();
stream.Write(bytes, 0, bytes.Length);
stream.Close();
#endif
return request;
}
The method calling this method is the following for GET:
public string Get(SecurityOptions options, string handler, string data)
{
var request = this.Prepare(options, "GET-X", handler, data);
#if NETCORE
var task = this.ExecuteAsync(request, data);
task.Wait();
return task.Result;
#else
return this.Execute(request, data);
#endif
}
This Get method caused an error by using a request method GET-X which Solr itself (6.4.1) did not understand. I've changed this to a normal request method: GET therefore solving the error on solr's side.
However currently i'm getting a System.Net.ProtocolViolationException with the message: Cannot send a content-body with this verb-type. This is happening when waiting for the taskStream to finish and write its result to the request-body.
My question:
How would one send a GET-request with a body (in json format (as string)) within dotnet core?
Since RFC2616 says it's not forbidden i'd like to use this 'feature' as answered in the following question
See RFC2616 - Hypertext Transfer Protocol -- HTTP/1.1, section 4.3 "Message Body":
A message-body MUST NOT be included in a request if the specification of the > > request method (section 5.1.1) does not allow sending an entity-body in requests.
In section 9.3 "GET" including an entity-body is not forbidden.
So, yes, you are allowed to send an entity-body with a HTTP GET request.

Microsoft Translator Bad request (400) issue

I've seen threads on this issue but my problem is particularly confusing. I have a free 2 million character subscription, a valid client id and secret. When I run my code I get to call the API a few times successfully (the most I've seen is 75 consecutive successful calls). Then every other call returns a Bad request response: The remote server returned an error: (400) Bad Request.
I create the token once with my credentials and never create it again. I loop through a file, parse it, and submit every parsed string for translation by calling the API. It seems that I reach some sort of limit that I'm now aware of.
When looking at my account, it doesn't seem to be discounting the characters that I've translated already which would make me highly suspicious that I have the wrong credentials when creating the token. I quadruple-checked that and everything seems to be ok.
Any guidance on what I may be missing here would be much appreciated.
Here's the code that creates the token. I do think though that there may be an unknown limitation that I'm not aware of with the free subscription.
static void gettoken()
{
//Get access token
string clientID = "my client id";
string clientSecret = "my secret";
String strTranslatorAccessURI = "https://datamarket.accesscontrol.windows.net/v2/OAuth2-13";
String strRequestDetails = string.Format("grant_type=client_credentials&client_id={0}&client_secret={1}&scope=http://api.microsofttranslator.com", clientID, clientSecret);
System.Net.WebRequest webRequest = System.Net.WebRequest.Create(strTranslatorAccessURI);
webRequest.ContentType = "application/x-www-form-urlencoded";
webRequest.Method = "POST";
byte[] bytes = System.Text.Encoding.ASCII.GetBytes(strRequestDetails);
webRequest.ContentLength = bytes.Length;
using (System.IO.Stream outputStream = webRequest.GetRequestStream())
{
outputStream.Write(bytes, 0, bytes.Length);
}
System.Net.WebResponse webResponse = webRequest.GetResponse();
System.Runtime.Serialization.Json.DataContractJsonSerializer serializer = new System.Runtime.Serialization.Json.DataContractJsonSerializer(typeof(AdmAccessToken));
AdmAccessToken token = (AdmAccessToken)serializer.ReadObject(webResponse.GetResponseStream());
MyGlobals.headerValue = "Bearer " + token.access_token;
}
And here's the code that calls the API itself. I call the API method from a loop.
static void RunBing(string sterm)
{
//Submit the translation request
string txtToTranslate = sterm;
string uri = "http://api.microsofttranslator.com/v2/Http.svc/Translate?text=" + txtToTranslate + "&from=en&to=es";
System.Net.WebRequest translationWebRequest = System.Net.WebRequest.Create(uri);
translationWebRequest.Headers.Add("Authorization", MyGlobals.headerValue);
System.Net.WebResponse response = null;
try {
response = translationWebRequest.GetResponse();
}
catch (Exception e)
{
Console.WriteLine("Term failed: " + sterm);
Console.WriteLine(e);
return;
}
System.IO.Stream stream = response.GetResponseStream();
System.Text.Encoding encode = System.Text.Encoding.GetEncoding("utf-8");
System.IO.StreamReader translatedStream = new System.IO.StreamReader(stream, encode);
System.Xml.XmlDocument xTranslation = new System.Xml.XmlDocument();
xTranslation.LoadXml(translatedStream.ReadToEnd());
MyGlobals.xlation = xTranslation.InnerText;
}
After several successful calls to the API, I start to get the following message:
System.Net.WebException: The remote server returned an error: (400) Bad Request.
at System.Net.HttpWebRequest.GetResponse()
at Translate.TranslateText.Program.RunBing(String sterm)

JIRA Rest API. Retrieve errormessages returned by API when it fails, using c# or vb.net

I'm developing a small app that pulls issues from JIRA from a given list of issue ids, however some of them don't exist and the API call returns a 400 Bad Request message.
This is the relevant block of code I have so far (C#):
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(thejiraurl);
request.Method = "GET";
request.ContentType = "Content-Type: application/json";
request.Accept = "application/json";
string mergedCredentials = "thecredentials :)";
byte[] byteCredentials = UTF8Encoding.UTF8.GetBytes(mergedCredentials);
string encodedCredentials = Convert.ToBase64String(byteCredentials);
request.Headers.Add("Authorization", "Basic " + encodedCredentials);
try
{
WebResponse response = request.GetResponse(); //this line breaks because some records don't exist anymore, that's ok, but at least I need to know which ones! those are found in the response that I can't see here but I can with Fiddler! #.#
Stream data = response.GetResponseStream();
}
catch(WebException ex)
{
Console.WriteLine(ex.Message);
if(ex.Status == WebExceptionStatus.ProtocolError)
{
Console.WriteLine("Status Code : {0}", ((HttpWebResponse)ex.Response).StatusCode); //This is 'BadRequest'
Console.WriteLine("Status Description : {0}", ((HttpWebResponse)ex.Response).StatusDescription); //This is 'Bad Request'
using (Stream responseStream = ex.Response.GetResponseStream())
using (StreamReader responseReader = new StreamReader(responseStream))
{
string responseMessage = responseReader.ReadToEnd(); //This is a long message but do not has the errormessages seen with Fiddler (and even in a internet browser)
Console.WriteLine(responseMessage);
}
}
}
However when I use Fiddler I can see the actual errormessages returned, that looks like:
{"errorMessages":["A value with ID '1' does not exist for the field 'key'."],"errors":{}}
How can I get this messages using C# or vb?
This is very similar to question, but that one is with Java: https://answers.atlassian.com/questions/147793/retrieving-errormessages-when-a-call-to-the-rest-api-fails-using-httpurlconnection
I appreciate any help.

How to redirect a WCF to an external URL (Google AdWords Sign In) and handle the response?

I am building a WCF that encapsulates Google OAuth 2.0.
The plan: Client calls WCF endpoint which then redirects to the Google Sign In page for user authentication. On successful authentication, Google kicks back to the redirect URI and returns the Access Token in the response.
[AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Required)]
public class AdWordsOAuthService : IOAuthService
{
public string AuthenticateAndGetRefreshToken()
{
string refreshToken = string.Empty;
try
{
AuthenticateUser();
}
catch (Exception ex)
{
throw;
}
return refreshToken;
}
private void AuthenticateUser()
{
// build the SOAP header here...
string authUrl = "https://accounts.google.com/o/oauth2/auth"; //redirect to this url
string postData = "response_type=code"
+ "&client_id=" + HttpUtility.UrlEncode("9999999999999.apps.googleusercontent.com")
//+ "&client_secret=" + HttpUtility.UrlEncode("dsflkdfsljkdfskjldskjlfds")
+ "&redirect_uri=" + HttpUtility.UrlEncode("http://localhost:50306/NextOAuthService/AdWordsOAuthService/AuthenticateAndGetRefreshToken")
+ "&scope=" + HttpUtility.UrlEncode("https://adwords.google.com/api/adwords")
+ "&access_type=offline";
byte[] byteArray = Encoding.UTF8.GetBytes(postData);
//handle webrequest stuff...
var request = (HttpWebRequest)WebRequest.Create(authUrl);// + postData);
if (request != null)
{
request.Method = "POST";
request.Timeout = 20000;
request.ContentType = "application/x-www-form-urlencoded";
request.ContentLength = byteArray.Length; // byteArray.Length;
Stream dataStream = request.GetRequestStream();
dataStream.Write(byteArray, 0, byteArray.Length);
dataStream.Close();
//attempt to redirect to the Adwords OAuth URL: https://adwords.google.com/api/adwords&?response.....blah blah
HttpWebResponse response = (HttpWebResponse)request.GetResponse();
WebOperationContext.Current.OutgoingResponse.StatusCode = HttpStatusCode.RedirectKeepVerb;
WebOperationContext.Current.OutgoingResponse.Location = response.ResponseUri.AbsoluteUri;
return;
}
}
}
What's Actually Happening: When the code attempts the redirect, I get following exception:
The content type text/html; charset=UTF-8 of the response message does not match the content type of the binding (application/soap+xml;> charset=utf-8)
When I examine the response (using fiddler), the response contains the actual HTML code for the Google OAuth Sign In page. So, instead of redirecting the WCF to the url, I am instead receiving an html response containing the page source.
How do I get around this and force the redirect?
I think you are miss understanding the calls a bit. The First URL that you are building there is the one that you should be displaying to the user asking if they want to let you access there data.
You need to wait for them to except. You need to deal with the Authentication Code. Google 3 Legged OAuth2 Flow
You should consider using Googles dot net client lib. It will handle all this for you.

The remote server returned an error: (403) Forbidden. during post request...?

I try to make small application for myself and I found this application
How to upload video on Dailymotion with c# ?? Is somebody has a complete code?
When I tried every thing but publishing is not working. I used fiddler but I cant find the error.
Here is the code
var request = WebRequest.Create("https://api.dailymotion.com/me/videos?url=" + Uri.EscapeUriString(uploadResponse.url));
request.Method = "POST";
request.ContentType = "application/x-www-form-urlencoded";
request.Headers.Add("Authorization", "OAuth " + accessToken);
var requestBytes = Encoding.UTF8.GetBytes("title=test 123&channel=Funny&tags=Humor&description=Testing testing&published=true");
var requestBytes = Encoding.UTF8.GetBytes(requestString);
var requestStream = request.GetRequestStream();
requestStream.Write(requestBytes, 0, requestBytes.Length);
var response = request.GetResponse();
var responseStream = response.GetResponseStream();
string responseString;
using (var reader = new StreamReader(responseStream))
{
responseString = reader.ReadToEnd();
}
When it reaches request.GetResponse() it gives the error. So what is the problem here..?
I believe you need to get rid of the "me" in the url as you're using OAuth instead of basic authentication, like this:
"https://api.dailymotion.com/videos?url="
Instead of:
"https://api.dailymotion.com/me/videos?url="
At least in a quick scan that looks like it's it, I wrote an auto-publisher for a client a year ago and it didn't use the me in the url. My credentials are invalid now, so can't test it unfortunately. It seems to be a bug in the answer you linked.
If you can read other languages, I found it helpful just going through their SDKs and converting the code:
http://www.dailymotion.com/doc/api/sdk-php.html
https://github.com/dailymotion/dailymotion-sdk-php/blob/master/Dailymotion.php

Categories

Resources