Get data on error with HttpWebRequest - c#

While interacting with an API there is a situation where they will return a 401 response that also contains data. I would like to return this data regardless of the error code of the response.
I have created a function to submit a either a GET or POST using HttpWebRequest that returns a string containing the response data. The only problem is that if the response is a 401, an error is thrown and the data is not read.
Here is an example of what is returned:
HTTP/1.1 401 Unauthorized
Access-Control-Allow-Credentials: false
Content-Type: application/json; charset=UTF-8
Date: Tue, 19 May 2015 17:56:10 GMT
Vary: Accept-Encoding
Vary: Accept-Encoding
Content-Length: 254
Connection: keep-alive
{"status":"error","message":"access_token (...) was deleted (at Tue May 19 17:52:49 UTC 2015). Use your refresh token (if you have one) to generate a new access_token.","requestId":"..."}
Here is what I have for my function so far:
private string SendHttpRequest(string url, out int statusCode, string method = "GET", object postData = null, string contentType = "application/json")
{
bool isPost = method.Equals("POST", StringComparison.CurrentCultureIgnoreCase);
byte[] content = new ASCIIEncoding().GetBytes(isPost ? JsonConvert.SerializeObject(postData) : "");
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
request.AllowAutoRedirect = true;
request.Method = method;
request.ContentType = contentType;
request.ContentLength = postData == null ? 0 : content.Length;
if (isPost && postData != null)
{
Stream reqStream = request.GetRequestStream();
reqStream.Write(content, 0, content.Length);
}
HttpWebResponse response = (HttpWebResponse)request.GetResponse(); // Throws error here
string result;
using (StreamReader sr = new StreamReader(response.GetResponseStream()))
{
result = sr.ReadToEnd();
}
statusCode = (int)response.StatusCode;
response.Close();
return result;
}
How can I still get the data for a 401 response? There is no requirement to use HttpWebRequest, that is just what I have been using so far.

The call to GetResponse is throwing a WebException. You can catch that exception and extract the response via the exception's Response property:
private string SendHttpRequest(string url, out int statusCode, string method = "GET", object postData = null, string contentType = "application/json")
{
bool isPost = method.Equals("POST", StringComparison.CurrentCultureIgnoreCase);
byte[] content = new ASCIIEncoding().GetBytes(isPost ? JsonConvert.SerializeObject(postData) : "");
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
request.AllowAutoRedirect = true;
request.Method = method;
request.ContentType = contentType;
request.ContentLength = postData == null ? 0 : content.Length;
if (isPost && postData != null)
{
Stream reqStream = request.GetRequestStream();
reqStream.Write(content, 0, content.Length);
}
HttpWebResponse response = null;
//Get the response via request.GetResponse, but if that fails,
//retrieve the response from the exception
try
{
response = (HttpWebResponse)request.GetResponse();
}
catch (WebException ex)
{
response = (HttpWebResponse)ex.Response;
}
string result;
using (StreamReader sr = new StreamReader(response.GetResponseStream()))
{
result = sr.ReadToEnd();
}
statusCode = (int)response.StatusCode;
response.Close();
return result;
}

Related

Document Moved 201 Remove from WebResponse

I use .NET 4.61. Can I get the response from https://1106-7916.el-alt.com/wp-json/wc/v2/products/407 instead of https://1106-7916.el-alt.com/wp-json/wc/v2/products, which causes a redirect? Can I add code to BuildRequest, shown below, to get that response automatically?
I am using the WooCommerce REST API to create products. Here is my request:
POST-https://1106-7916.el-alt.com/wp-json/wc/v2/products?consumer_key=X
{"attributes":[{"name":"Color","visible":true,"variation":true,"options":["Red","Blue","Green","Orange"]},{"name":"Size","visible":true,"variation":true,"options":["S","M","L"]}],"title":"FooFoo","sku":"TestCreateProductWoo1026","description":"Test","categories":[],"tags":[],"type":"variable"}
Here is the response:
HTTP/1.1 201 Created
Cache-Control: no-cache, must-revalidate, max-age=0
Allow: GET, POST
Location: https://1106-7916.el-alt.com/wp-json/wc/v2/products/407
<head><title>Document Moved</title></head>
<body><h1>Object Moved</h1>This document may be found here</body>{"id":407,"name":"Product","slug":"product"}
Here is my code:
private string BuildRequest(string path, IDictionary<string, string> query, HttpMethodTypes httpMethod, object body)
{
string pathAndQuery = BuildParameters(path, query);
string resultData = string.Empty;
HttpWebRequest myHttpWebRequest = (HttpWebRequest)WebRequest.Create(pathAndQuery);
myHttpWebRequest.Accept = "application/json";
myHttpWebRequest.ContentType = "application/json";
myHttpWebRequest.UserAgent = "JMA Web Technologies";
myHttpWebRequest.AllowAutoRedirect = true;
SetHeaders(myHttpWebRequest);
if (httpMethod != HttpMethodTypes.GET)
myHttpWebRequest.Method = httpMethod.ToString();
SetResponseBody(body, myHttpWebRequest);
WebResponse httpResponse = myHttpWebRequest.GetResponse();
Stream responseStream = httpResponse.GetResponseStream();
StreamReader reader = new StreamReader(responseStream);
resultData = reader.ReadToEnd();
responseStream.Close();
httpResponse.Close();
return resultData;
}
Any help is greatly appreciated.

C# - Receiving strange character from HttpWebResponse

I have this code to send a HTTP Request:
public string MakeRequest(string requestUrl, object data)
{
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(requestUrl);
request.ContentType = "application/json";
request.KeepAlive = false;
request.Headers.Add("Authorization", "BEARER " + apiToken);
System.Net.ServicePointManager.Expect100Continue = false;
if (data != null)
{
request.Method = "POST";
using (var streamWriter = new StreamWriter(request.GetRequestStream()))
{
string json = new JavaScriptSerializer().Serialize(data);
streamWriter.Write(json);
streamWriter.Flush();
streamWriter.Close();
}
}
else
request.Method = "GET";
using (HttpWebResponse response = request.GetResponse() as HttpWebResponse)
{
if (response.StatusCode != HttpStatusCode.OK && response.StatusCode != HttpStatusCode.Created)
throw new Exception(String.Format("Server error (HTTP {0}: {1}).", response.StatusCode, response.StatusDescription));
string Charset = response.CharacterSet;
Encoding encoding = Encoding.GetEncoding(Charset);
StreamReader reader = new StreamReader(response.GetResponseStream(), encoding);
return reader.ReadToEnd();
}
}
It works well for most calls but one POST where I receive this as response:
"�\b\0\0\0\0\0\0�V�M,.I-�/JI-R��V3<S����L�L,�L��jk[���&\0\0\0"
And when I see the call captured by Fiddler it says the routine received:
{
"MasterOrder": {
"OrderId": "65250824"
}
}
So, what is happening exactly? How is that Fiddler sees one response and the applications sees another response?
Solved the issue by adding these lines to the request:
request.Headers.Add(HttpRequestHeader.AcceptEncoding, "gzip,deflate");
request.AutomaticDecompression = DecompressionMethods.GZip | DecompressionMethods.Deflate;

Passing headers to webRequest as parameter

If we have generic httpWebRequest method, and if we pass headers through parameter, how can we pass them as string?
Example of method and headers as parameter. How do we pass headers to the method?
public static HttpWebResponse PostRequest(string url, string usrname, string pwd, string method, string contentType,
string[] headers, string body)
{
// Variables.
HttpWebRequest Request;
HttpWebResponse Response;
//
string strSrcURI = url.Trim();
string strBody = body.Trim();
try
{
// Create the HttpWebRequest object.
Request = (HttpWebRequest)HttpWebRequest.Create(strSrcURI);
if (string.IsNullOrEmpty(usrname) == false && string.IsNullOrEmpty(pwd) == false)
{
// Add the network credentials to the request.
Request.Credentials = new NetworkCredential(usrname.Trim(), pwd);
}
// Specify the method.
Request.Method = method.Trim();
// request headers
foreach (string s in headers)
{
Request.Headers.Add(s);
}
// Set the content type header.
Request.ContentType = contentType.Trim();
// set the body of the request...
Request.ContentLength = body.Length;
using (Stream reqStream = Request.GetRequestStream())
{
// Write the string to the destination as a text file.
reqStream.Write(Encoding.UTF8.GetBytes(body), 0, body.Length);
reqStream.Close();
}
// Send the method request and get the response from the server.
Response = (HttpWebResponse)Request.GetResponse();
// return the response to be handled by calling method...
return Response;
}
catch (Exception e)
{
throw new Exception("Web API error: " + e.Message, e);
}
}
You can use stream to write content to webrequest:
string data = "username=<value>&password=<value>"; //replace <value>
byte[] dataStream = Encoding.UTF8.GetBytes(data);
private string urlPath = "http://xxx.xxx.xxx/manager/";
string request = urlPath + "index.php/org/get_org_form";
WebRequest webRequest = WebRequest.Create(request);
webRequest.Method = "POST";
webRequest.ContentType = "application/x-www-form-urlencoded";
webRequest.ContentLength = dataStream.Length;
Stream newStream=webRequest.GetRequestStream();
// Send the data.
newStream.Write(dataStream,0,dataStream.Length);
newStream.Close();
WebResponse webResponse = webRequest.GetResponse();

Request to Yandex Speech

I try to set request to recognize wav file->to text with Yandex Speech API via desktop app.
Example of request from documentation:
POST /asr_xml?uuid=01ae13cb744628b58fb536d496daa1e6&key=developers-simple- key&topic=maps HTTP/1.1
Content-Type: audio/x-speex
User-Agent: Dalvik/1.2.0 (Linux; U; Android 2.2.2; LG-P990 Build/FRG83G)
Host: asr.yandex.net
Transfer-Encoding: chunked
7d0
...
chunked body
So, i register at developer forum, get api key and write simple code:
public string RecognizeSpeech(byte[] bytes, String uuid, String apiKey, string topic = "queries", string lang = "ru-RU")
{
try
{
var uri = string.Format("https://asr.yandex.net/asr_xml?" +
"uuid={0}" +
"&key={1}" +
"&topic={2}" +
"&lang={3}", uuid, apiKey, topic, lang);
var request = (HttpWebRequest)WebRequest.Create(uri);
request.Method = "POST";
request.ContentType = "audio/x-wav";//"audio/x-pcm;bit=16;rate=16000";
request.ContentLength = bytes.Length;
using (var stream = request.GetRequestStream())
{
stream.Write(bytes, 0, bytes.Length);// exception here
}
var response = request.GetResponse();
var reader = new StreamReader(response.GetResponseStream(), Encoding.UTF8);
return reader.ReadToEnd();
}
catch (Exception ex)
{
...
}
return "";
}
I try to use audio/x-wav or audio/x-pcm;bit=16;rate=16000, but I get error:
Unable to write data to the transport connection: remote host forcibly ripped existing connection.
(use google translate)
byte[] bytes- is:
var audioBytes = File.ReadAllBytes(#"file.wav");
P.S. documentation on Russian language
This gist set POST request to Yandex Speech Cloud.
You need to make valid audio file (i use Freemake) - pcm,16 bit, 16000 hz, mono channel.
Here the solution:
public string PostMethod(byte[] bytes)
{
string postUrl = "https://asr.yandex.net/asr_xml?" +
"uuid=01ae13cb744628b58fb536d496daa1e6&" +
"key="+your_api_key_here+"&" +
"topic=queries";
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(postUrl);
request.Method = "POST";
request.Host = "asr.yandex.net";
request.SendChunked = true;
request.UserAgent = "Oleg";
request.ContentType = "audio/x-pcm;bit=16;rate=16000";
request.ContentLength = bytes.Length;
using (var newStream = request.GetRequestStream())
{
newStream.Write(bytes, 0, bytes.Length);
}
HttpWebResponse response = (HttpWebResponse)request.GetResponse();
string responseToString = "";
if (response != null)
{
var strreader = new StreamReader(response.GetResponseStream(), Encoding.UTF8);
responseToString = strreader.ReadToEnd();
}
int index = responseToString.IndexOf("<variant confidence=\"1\">");
responseToString = responseToString.Substring(index + 24, responseToString.Length - index - 24);
int index2 = responseToString.IndexOf("</variant>");
responseToString = responseToString.Substring(0, index2);
return responseToString;
}

Add param POST request using HttpWebRequest async windows phone 8 - JSON [duplicate]

I need to call a method from a webservice, so I've written this code:
private string urlPath = "http://xxx.xxx.xxx/manager/";
string request = urlPath + "index.php/org/get_org_form";
WebRequest webRequest = WebRequest.Create(request);
webRequest.Method = "POST";
webRequest.ContentType = "application/x-www-form-urlencoded";
webRequest.
webRequest.ContentLength = 0;
WebResponse webResponse = webRequest.GetResponse();
But this method requires some parameters, as following:
Post data:
_username:'API USER', // api authentication username
_password:'API PASSWORD', // api authentication password
How can I add these parameters into this Webrequest?
Use stream to write content to webrequest
string data = "username=<value>&password=<value>"; //replace <value>
byte[] dataStream = Encoding.UTF8.GetBytes(data);
private string urlPath = "http://xxx.xxx.xxx/manager/";
string request = urlPath + "index.php/org/get_org_form";
WebRequest webRequest = WebRequest.Create(request);
webRequest.Method = "POST";
webRequest.ContentType = "application/x-www-form-urlencoded";
webRequest.ContentLength = dataStream.Length;
Stream newStream=webRequest.GetRequestStream();
// Send the data.
newStream.Write(dataStream,0,dataStream.Length);
newStream.Close();
WebResponse webResponse = webRequest.GetResponse();
If these are the parameters of url-string then you need to add them through '?' and '&' chars, for example http://example.com/index.aspx?username=Api_user&password=Api_password.
If these are the parameters of POST request, then you need to create POST data and write it to request stream. Here is sample method:
private static string doRequestWithBytesPostData(string requestUri, string method, byte[] postData,
CookieContainer cookieContainer,
string userAgent, string acceptHeaderString,
string referer,
string contentType, out string responseUri)
{
var result = "";
if (!string.IsNullOrEmpty(requestUri))
{
var request = WebRequest.Create(requestUri) as HttpWebRequest;
if (request != null)
{
request.KeepAlive = true;
var cachePolicy = new RequestCachePolicy(RequestCacheLevel.BypassCache);
request.CachePolicy = cachePolicy;
request.Expect = null;
if (!string.IsNullOrEmpty(method))
request.Method = method;
if (!string.IsNullOrEmpty(acceptHeaderString))
request.Accept = acceptHeaderString;
if (!string.IsNullOrEmpty(referer))
request.Referer = referer;
if (!string.IsNullOrEmpty(contentType))
request.ContentType = contentType;
if (!string.IsNullOrEmpty(userAgent))
request.UserAgent = userAgent;
if (cookieContainer != null)
request.CookieContainer = cookieContainer;
request.Timeout = Constants.RequestTimeOut;
if (request.Method == "POST")
{
if (postData != null)
{
request.ContentLength = postData.Length;
using (var dataStream = request.GetRequestStream())
{
dataStream.Write(postData, 0, postData.Length);
}
}
}
using (var httpWebResponse = request.GetResponse() as HttpWebResponse)
{
if (httpWebResponse != null)
{
responseUri = httpWebResponse.ResponseUri.AbsoluteUri;
cookieContainer.Add(httpWebResponse.Cookies);
using (var streamReader = new StreamReader(httpWebResponse.GetResponseStream()))
{
result = streamReader.ReadToEnd();
}
return result;
}
}
}
}
responseUri = null;
return null;
}
For doing FORM posts, the best way is to use WebClient.UploadValues() with a POST method.
Hope this works
webRequest.Credentials= new NetworkCredential("API_User","API_Password");
I have a feeling that the username and password that you are sending should be part of the Authorization Header. So the code below shows you how to create the Base64 string of the username and password. I also included an example of sending the POST data. In my case it was a phone_number parameter.
string credentials = Convert.ToBase64String(Encoding.ASCII.GetBytes(_username + ":" + _password));
HttpWebRequest webRequest = (HttpWebRequest)WebRequest.Create(Request);
webRequest.Headers.Add("Authorization", string.Format("Basic {0}", credentials));
webRequest.ContentType = "application/x-www-form-urlencoded";
webRequest.Method = WebRequestMethods.Http.Post;
webRequest.AllowAutoRedirect = true;
webRequest.Proxy = null;
string data = "phone_number=19735559042";
byte[] dataStream = Encoding.UTF8.GetBytes(data);
request.ContentLength = dataStream.Length;
Stream newStream = webRequest.GetRequestStream();
newStream.Write(dataStream, 0, dataStream.Length);
newStream.Close();
HttpWebResponse response = (HttpWebResponse)webRequest.GetResponse();
Stream stream = response.GetResponseStream();
StreamReader streamreader = new StreamReader(stream);
string s = streamreader.ReadToEnd();
The code below differs from all other code because at the end it prints the response string in the console that the request returns. I learned in previous posts that the user doesn't get the response Stream and displays it.
//Visual Basic Implementation Request and Response String
Dim params = "key1=value1&key2=value2"
Dim byteArray = UTF8.GetBytes(params)
Dim url = "https://okay.com"
Dim client = WebRequest.Create(url)
client.Method = "POST"
client.ContentType = "application/x-www-form-urlencoded"
client.ContentLength = byteArray.Length
Dim stream = client.GetRequestStream()
//sending the data
stream.Write(byteArray, 0, byteArray.Length)
stream.Close()
//getting the full response in a stream
Dim response = client.GetResponse().GetResponseStream()
//reading the response
Dim result = New StreamReader(response)
//Writes response string to Console
Console.WriteLine(result.ReadToEnd())
Console.ReadKey()

Categories

Resources