I am trying to make a http post request to obtain an api token. If successful, it is supposed to return string values of access token, token type (bearer) and expires_in.
The code I have is a generic one which I was expecting to see working. But for some reasons, it throws an exception of 400 "The remote server returned an error. Bad Request". I have been trying everything to fix this whereas the result doesn't change.
When I debug the code and see the result in the Output window, there is an exception about Data stream saying "this stream doesn't support seek operations"
Stream dataStream = request.GetRequestStream();
dataStream.Write(byteArray, 0, byteArray.Length);
dataStream.Close();
My doubt is it happens due to the postData, the way it is encoded. My client secret is something like:
g/gOvqf5R+FTZZXbwsCbp0WsQjF9B0bl87IBQ8VAJ2Q=
Does it encode the characters in the secret itself so that it constructs a bad request?
I have also tried this on POSTMAN and it produced a result, so there is nothing with the api. It comes down again to the request content. It's a console app. I am pasting my code below and I am thankful for your help in advance.
public static APIModel GenerateApiKey()
{
var appSettings = ConfigurationManager.AppSettings;
try
{
var urlToCall = string.Format("https://app.example.com/token");
var uri = new Uri(urlToCall);
var request = (HttpWebRequest)WebRequest.Create(uri);
request.Method = "POST";
string postData = "grant_type=client_credentials&client_id=" + appSettings["my_client_id"] + "&client_secret=" + appSettings["my_client_secret"];
byte[] byteArray = Encoding.UTF8.GetBytes(postData);
request.ContentType = "application/x-www-form-urlencoded";
request.ContentLength = byteArray.Length;
Stream dataStream = request.GetRequestStream();
dataStream.Write(byteArray, 0, byteArray.Length);
dataStream.Close();
var response = (HttpWebResponse)request.GetResponse();
APIModel bearerToken;
using (StreamReader sr = new StreamReader(response.GetResponseStream()))
{
string jsonFromServer = sr.ReadToEnd();
bearerToken = JsonConvert.DeserializeObject<APIModel>(jsonFromServer);
}
response.Close();
return bearerToken;
}
catch (Exception e)
{
throw new Exception("Error getting a response from API " + e.Message);
}
}
The remote server is giving you a 400 error due to you sending it incorrect data of some sort. You may be able to get the response and figure out the exact error - the remote server would quite possibly give you some more information. However, I can see one issue with your post data - the client secret needs to be URL encoded. Look at the content of it and you will see that it ends with an = sign. that will be interpreted as a special character. I also like to be a bit more explicit about creating strings, so this would work for you:
var postItems = new List<KeyValuePair<string, string>>
{
new KeyValuePair<string, string>("grant_type", "client_credentials"),
new KeyValuePair<string, string>("client_id", "client_credentials"),
new KeyValuePair<string, string>("client_secret", "client_credentials"),
};
string postData = string.Join("&",
postItems.Select (kvp =>
string.Format("{0}={1}", kvp.Key, HttpUtility.UrlEncode(kvp.Value))));
Client id and secret had to be url encoded separately while forming form data. Updated postData:
string postData = "grant_type=client_credentials&client_id=" + HttpUtility.UrlEncode(appSettings["my_client_id"]) + "&client_secret=" + HttpUtility.UrlEncode(appSettings["my_client_secret"]);
Related
I'm trying to get a simple response from a local .net site of my own. (Really I'm just trying to see what the content-body looks like from the server side.) Here is the controller method that's sending the response:
public HttpResponseMessage Post([FromBody]string value)
{
data.Add(value);
var msg = Request.CreateResponse(HttpStatusCode.Created);
msg.Headers.Location = new Uri(Request.RequestUri + "/" + (data.Count-1).ToString());
msg.Content = new StringContent(value);
return msg;
}
And here is the code that's making the request:
HttpWebRequest request;
request = (HttpWebRequest)WebRequest.Create ("http://localhost:50203/api/Values");
request.Method = "POST";
try
{
WebResponse response = (HttpWebResponse)request.GetResponse();
Stream dataStream = response.GetResponseStream();
byte[] requestBody = ASCIIEncoding.ASCII.GetBytes(HttpUtility.UrlEncode("grant_type=client_credentials"));
request.ContentLength = requestBody.Length;
dataStream.Write(requestBody, 0, requestBody.Length);
StreamReader reader = new StreamReader(dataStream);
myString = reader.ReadToEnd();
}
I'm getting the response message: HTTP Error 411. The request must be chunked or have a content length. But as you can see I DO assign the content length in the line: request.ContentLength = requestBody.Length;.
Why am I getting this error?
Thanks to help from itsme86 I was able to see what was happening. It had to do with misunderstanding the HttpWebRequest method. I was trying to set the content length and write to the request after I'd already posted it using the GetResponse method. I should have posted the length first. This wasn't a particularly good question, and no one else should answer.
I'm not sure why this PayPal Pay operation is giving me this error even though I seem to have covered all the required fields:
Error Code: 81002 Severity: Error Message: Unspecified Method (Method Specified is not Supported)"
string postData = JsonConvert.SerializeObject(request);
value of postData:
"actionType=PAY
¤cyCode=USD
&cancelUrl=https%3a%2f%2fexample.com%2fcancel
&returnUrl=https%3a%2f%2fexample.com%2freturn
&requestenvelope.errorLanguage=en_US
&receiverList.receiver(0).email=recipientemail%40gmail.com
&receiverList.receiver(0).amount=0.05
&VERSION=94.0
&USER=bizemail-facilitator_api1.gmail.com
&PWD=xxxxx
&SIGNATURE=xxxxxxxxx"
Here's how I do the post:
SendRequest("https://api-3t.sandbox.paypal.com/nvp", postData);
public string SendRequest(string url, string postData)
{
var uri = new Uri(url);
var request = WebRequest.Create(uri);
var encoding = new UTF8Encoding();
var requestData = encoding.GetBytes(postData);
request.ContentType = "application/x-www-form-urlencoded";
request.Method = "POST";
request.Timeout = (300*1000); //TODO: Move timeout to config
request.ContentLength = requestData.Length;
using (var stream = request.GetRequestStream()) {
stream.Write(requestData, 0, requestData.Length);
}
var response = request.GetResponse();
string result;
using (var reader = new StreamReader(response.GetResponseStream(), Encoding.ASCII)) {
result = reader.ReadToEnd();
}
return result;
}
The method PAY doesn't exist on the NVP api. Full list of methods supported by that API is found here.
The PAY method, however, is defined in the Adaptive Payments API. Depending on your needs, you have two options:
Change the endpoint to https://svcs.paypal.com/AdaptivePayments/PAY and modify your values
Use another method, like DoDirectPayment, but I'm not sure it does what you want to.
I assume the value of postData is before you serialize it to a JSON string, instead of after as you say, since it is clearly not a JSON string.
If so, then it is already x-www-form-urlencoded, and you do not need to serialize it to a JSON string at all.
Or if you do after all, then change just this: request.ContentType = "application/json";
I am trying write simple request to REST service.Follow to documentation from REST Service provider:
I should use in header Content-Type: application/json.
Response return in json format
For authorization proccess I have to send two headers one with APIKey and second with APISign
Controller PING in REST service to test code.
I use .net 2.0
string sha1String = APIKey + "/rest/ping" + APISecret;
string XRestApiSign = SHA1HashStringForUTF8String(sha1String);
string data = "";
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(restServer);
request.Method = "POST";
request.ContentType = "application/json";
request.Headers.Add("X-Rest-ApiSign", XRestApiSign);
request.Headers.Add("X-Rest-ApiKey", APIKey);
request.ContentLength = data.Length;
StreamWriter requestWriter;
Stream webStream = request.GetRequestStream();
using (requestWriter = new StreamWriter(webStream, System.Text.Encoding.ASCII)) ;
{
requestWriter.Write(data);
}
request.BeginGetResponse((x) =>
{
using (HttpWebResponse response = (HttpWebResponse)request.EndGetResponse(x))
{
List<string> list = Newtonsoft.Json.JsonConvert.DeserializeObject<List<string>>(response.GetResponseStream().ToString());
}
}, null);
I should get response string PONG but I get below message
Unexpected character encountered while parsing value: S. Path '', line 0, position 0
Is code OK ? Why I get this message?
This is mostly the case because the script that generates the JSON on the server side adds the byte order mark to the response.
In your case, however, you're trying to convert the stream to JSON, not the content of the stream. You need to read all text from the stream and deserialize the object from that. You need to call one of the methods on the stream that reads the content.
I modified my code with yours suggestion and it works. Now I have problem with send data :)
Subscription user1 = new Subscription
{
Email = "kubaIt#test.com.pl",
List = "xfct2bjcdv",
};
List<Subscription> user = new List<Subscription>();
user.Add(user1);
string json = JsonConvert.SerializeObject(user);
string data = json;
I added above. Other code is the same. I got error :The request was aborted: The request was canceled."
json = [{\"email\":\"kubaIt#test.com.pl\",\"list\":\"xfct2bjcdv\"}] //value from debuger
//Create a request using a URL that can receive a post.
WebRequest request = WebRequest.Create("https://go.urbanairship.com/api/push/");
request.Credentials = new NetworkCredential("pvYMExk3QIO7p2YUs6BBkg", "rO3DsucETRadbbfxHkd6qw");
// Set the Method property of the request to POST.
request.Method = "POST";
// Create POST data and convert it to a byte array.
//WRITE JSON DATA TO VARIABLE D
string postData = "{\"aps\": {\"badge\": 1, \"alert\": \"Hello from Urban Airship!\"}, \"device_tokens\": [\"6334c016fc643baa340eca25bc661d15055a07b475e9a6108f3f644b15dd05ac\"]}";
byte[] byteArray = Encoding.UTF8.GetBytes(postData);
// Set the ContentType property of the WebRequest.
request.ContentType = "application/json";
// Set the ContentLength property of the WebRequest.
request.ContentLength = byteArray.Length;
// Get the request stream.
using (Stream dataStream = request.GetRequestStream())
{
// Write the data to the request stream.
dataStream.Write(byteArray, 0, byteArray.Length);
}
// Get the response.
WebResponse response = request.GetResponse();
//Error "The remote server returned an error: (400) Bad Request"
// Display the status.
Console.WriteLine(((HttpWebResponse)response).StatusDescription);
// Get the stream containing content returned by the server.
using (Stream dataStream = response.GetResponseStream())
{
// Open the stream using a StreamReader for easy access.
using (var reader = new StreamReader(dataStream))
{
// Read the content.
string responseFromServer = reader.ReadToEnd();
// Display the content.
Console.WriteLine(responseFromServer);
response.Close();
}
}
I have experienced a similar problem to what he is getting.
When the exception is thrown calling GetResponse(), it is a WebException. Cast it as such, then check out the response stream. Yes, the content length is -1, but ignore that.
catch (Exception ex)
{
//byte[] buffer = new byte[999999];
WebException wex = (WebException)ex;
var s = wex.Response.GetResponseStream();
string ss = "";
int lastNum = 0;
do
{
lastNum = s.ReadByte();
ss += (char)lastNum;
} while (lastNum != -1);
s.Close();
s = null;
ErrorHasOccurred(new Exception("An error has occurred sending the notification to Urban Airship. Please see the InnerException for details. Please note that, for sending messages, the master password is required (instead of the regular password). ERROR: " + ss, ex));
}
Then just breakpoint right where I have ErrorHasOccurred and read the contents of the ss variable. It will tell you the actual error that Urban Airship returns.
What is your question? The server is saying your request is bad. Use Fiddler if you're not sure what you are actually sending to the server, then fix your request. Otherwise fix your server code.
Either way, this is "not a real question" fodder without some clarification.
It is a valid question...
First. Not use hard code for build the json string, use JavaScriptSerializer
var json = new JavaScriptSerializer().Serialize(yourObject);
Second. For single parameter, use
...
BodyStyle = WebMessageBodyStyle.Bare,
...
insted of
BodyStyle = WebMessageBodyStyle.WrappedRequest,
(I spend a few hours with a similar problem)
This may be a pathetically simple problem, but I cannot seem to format the post webrequest/response to get data from the Wikipedia API. I have posted my code below if anyone can help me see my problem.
string pgTitle = txtPageTitle.Text;
Uri address = new Uri("http://en.wikipedia.org/w/api.php");
HttpWebRequest request = WebRequest.Create(address) as HttpWebRequest;
request.Method = "POST";
request.ContentType = "application/x-www-form-urlencoded";
string action = "query";
string query = pgTitle;
StringBuilder data = new StringBuilder();
data.Append("action=" + HttpUtility.UrlEncode(action));
data.Append("&query=" + HttpUtility.UrlEncode(query));
byte[] byteData = UTF8Encoding.UTF8.GetBytes(data.ToString());
request.ContentLength = byteData.Length;
using (Stream postStream = request.GetRequestStream())
{
postStream.Write(byteData, 0, byteData.Length);
}
using (HttpWebResponse response = request.GetResponse() as HttpWebResponse)
{
// Get the response stream.
StreamReader reader = new StreamReader(response.GetResponseStream());
divWikiData.InnerText = reader.ReadToEnd();
}
You might want to try a GET request first because it's a little simpler (you will only need to POST for wikipedia login). For example, try to simulate this request:
http://en.wikipedia.org/w/api.php?action=query&prop=images&titles=Main%20Page
Here's the code:
HttpWebRequest myRequest =
(HttpWebRequest)WebRequest.Create("http://en.wikipedia.org/w/api.php?action=query&prop=images&titles=Main%20Page");
using (HttpWebResponse response = (HttpWebResponse)myRequest.GetResponse())
{
string ResponseText;
using (StreamReader reader = new StreamReader(response.GetResponseStream()))
{
ResponseText = reader.ReadToEnd();
}
}
Edit: The other problem he was experiencing on the POST request was, The exception is : The remote server returned an error: (417) Expectation failed. It can be solved by setting:
System.Net.ServicePointManager.Expect100Continue = false;
(This is from: HTTP POST Returns Error: 417 "Expectation Failed.")
I'm currently in the final stages of implementing an C# MediaWiki API which allows the easy scripting of most MediaWiki viewing and editing actions.
The main API is here: http://o2platform.googlecode.com/svn/trunk/O2%20-%20All%20Active%20Projects/O2_XRules_Database/_Rules/APIs/OwaspAPI.cs and here is an example of the API in use:
var wiki = new O2MediaWikiAPI("http://www.o2platform.com/api.php");
wiki.login(userName, password);
var page = "Test"; // "Main_Page";
wiki.editPage(page,"Test content2");
var rawWikiText = wiki.raw(page);
var htmlText = wiki.html(page);
return rawWikiText.line().line() + htmlText;
You seem to be pushing the input data on HTTP POST, but it seems you should use HTTP GET.
From the MediaWiki API docs:
The API takes its input through
parameters in the query string. Every
module (and every action=query
submodule) has its own set of
parameters, which is listed in the
documentation and in action=help, and
can be retrieved through
action=paraminfo.
http://www.mediawiki.org/wiki/API:Data_formats