Can I a wrap a GET request inside another GET request? - c#

I may well be approaching this incorrectly, but what I'm trying to do is consume a GET request so I can manipulate the response into a format that I want. I need to be able to launch this from a browser, so I thought about building another RESTful service for this purpose.
i.e. Service ABC returns a string using a GET request. I want to take that string, do some manipulation and return it. I still need to be able to launch from a browser, so what I'm planning is to create a RESTful service XYZ, where the GET request in XYZ launches a call to the GET request of ABC, takes that response, converts it into my collection, and returns that collection. I'll then display in MVC.
Firstly: is this a dumb choice? I don't know a lot about different types of services.
Secondly: I have been able to get the ABC service data using a Console client, but not using a web-based client or service. Is this to be expected?
Code:
string webPath = #"http://ABCService.co.uk/";
string methodCall = #"methodABC/uid";
RestClient restClient = new RestClient(webPath);
RestRequest request = new RestRequest(methodCall, Method.GET);
var restResponse = restClient.Execute(request);
var content = restResponse.Content;
This works fine in the console (and I've actually been able to get the data just using a WebClient too), but neither method works from inside an MVC controller or service. I just get this as an ErrorException in restResponse:
Exception: "{"Unable to connect to the remote server" InnerException
= {"A connection attempt failed because the connected party did not properly respond after a period of time, or established connection
failed because connected host has failed to respond 80.64.52.36:80"}
Service ABC is up and running, can be accessed from a browser and console app. Note that I have no ability to alter any settings within Service ABC.
Many thanks

I resolved this by setting the proxy to null, rather than using a default proxy.
public string ReadWebReport(string path)
{
string str = String.Empty;
HttpWebRequest Request = WebRequest.Create(path) as HttpWebRequest;
Request.Method = "GET"; //Or PUT, DELETE, POST
Request.ContentType = "application/x-www-form-urlencoded";
Request.Proxy = null; //<-- inserted line
using (HttpWebResponse Response = Request.GetResponse() as HttpWebResponse)
{
if (Response.StatusCode != HttpStatusCode.OK)
throw new Exception("The request did not complete successfully and returned status code " + Response.StatusCode);
using (StreamReader Reader = new StreamReader(Response.GetResponseStream()))
{
str = Reader.ReadToEnd();
}
}
return str;
}

Related

Https calls are not connecting to server

I am working on Windows Service in visual studio 2017. In the rest api's call, getting exceptions while debugging code. Sometimes first 2 3 calls working after that getting exceptions.
System.Net.WebException: 'The remote server returned an error: (503)
Server Unavailable.'
The remote server returned an error: (429)
Unable to connect to the remote server
When calling same api's from Postman, getting response successfully.
This is my code
private void timer1_Tick(object sender, ElapsedEventArgs e)
{
WriteToFile("timer1_Tick method called..");
try
{
string jsonString = "";
string jsonstring2 = "";
string prodfetchurl = HOST;
var req = WebRequest.Create(prodfetchurl) as HttpWebRequest;
req.Method = "GET";
InitializeRequest(req);
req.Accept = MIME_TYPE;
//System.Threading.Thread.Sleep(5000);
var response = (HttpWebResponse)req.GetResponse();
WriteToFile("First service called...");
if (response.StatusCode == HttpStatusCode.OK)
{
Stream responseStream = response.GetResponseStream();
StreamReader responseReader = new StreamReader(responseStream);
jsonString = responseReader.ReadToEnd();
}
var deserialsseobj = JsonConvert.DeserializeObject<ProductList>(jsonString).Products.Where(i => i.Failed > 0).ToList();
foreach (var a in deserialsseobj)
{
var pid = a.ID;
string url = FailedDevicesUrl + pid.Value + "/failed";
var req2 = WebRequest.Create(url) as HttpWebRequest;
req2.Method = "GET";
InitializeRequest(req2);
req2.Timeout = 300000;
req2.Accept = MIME_TYPE;
var response1 = (HttpWebResponse)req2.GetResponse();
Stream responsestream2 = response1.GetResponseStream();
WriteToFile("Second service called...");
if (response1.StatusCode == HttpStatusCode.OK)
{
StreamReader responsereader1 = new StreamReader(responsestream2);
jsonstring2 = responsereader1.ReadToEnd();
}
var output = JsonConvert.DeserializeObject<List<FailedDeviceList>>(jsonstring2); // Will get List of the Failed devices
List<int> deviceids = new List<int>();
Reprocessdata reproc = new Reprocessdata();
Reprocessdata.DeviceId rprod = new Reprocessdata.DeviceId();
reproc.ForceFlag = true;
reproc.ProductID = pid.Value;
foreach (var dd in output)
{
rprod.ID = dd.DeviceId;
reproc.DeviceIds.Add(rprod);
}
// Reprocess the Product in Devices
var req3 = WebRequest.Create(ReprocessUrl) as HttpWebRequest;
req3.Method = "POST";
InitializeRequest(req3);
req3.Accept = MIME_TYPE;
req3.Timeout = 300000;
req3.ContentType = "application/json";
using (StreamWriter writer = new StreamWriter(req3.GetRequestStream()))
{
string json = new JavaScriptSerializer().Serialize(reproc);
writer.Write(json);
writer.Close();
}
System.Threading.Thread.Sleep(5000);
var response5 = (HttpWebResponse)req3.GetResponse();
WriteToFile("Third service called...");
if (response5.StatusCode == HttpStatusCode.OK)
{
string result;
using (StreamReader rdr = new StreamReader(response5.GetResponseStream()))
{
result = rdr.ReadToEnd();
}
}
}
response.Close();
}
catch (Exception ex)
{
WriteToFile("Simple Service Error on: {0} " + ex.Message + ex.StackTrace);
}
}
Methods used in above code
protected override void OnStart(string[] args)
{
base.OnStart(args);
timer1 = new System.Timers.Timer();
timer1.Interval = 60000; //every 1 min
timer1.Elapsed += new System.Timers.ElapsedEventHandler(timer1_Tick);
timer1.Enabled = true;
WriteToFile("Service has started..");
}
public void InitializeRequest(HttpWebRequest request)
{
request.Headers.Add("aw-tenant-code", API_TENANT_CODE);
request.Credentials = new NetworkCredential(USER_NAME, PASSWORD);
request.KeepAlive = false;
request.AddRange(1024);
}
When I contacted service provide they said everything fine from there side. Is this my code is buggy or windows service not reliable? How can I fix this issue?
Note: All APIS are working fine from Angular application using Visual Studio Code. It means my code is not working.
Edit1: Three below services I am using from this document of VMware.
private const string HOST = "https:host/api/mdm/products/search?";
private const string FailedDevicesUrl = "https:host/api/mdm/products/";
private const string ReprocessUrl = "https:host/api/mdm/products/reprocessProduct";
Response http code 429 indicates that you sending too many requests on target web service.
This means service you trying to send requests has a policies that blocks some requests by request-per-time limit.
Also I admit that external service can be manually configured to throw 403 code in specific cases that you can't know about. If that, this information can be explained in external service documentation... or not :)
What you can do with this?
Fit in limitations
You can make detailed research what limits target webservice has and set up your code to fit in this limitations. For example if service has limitation for receiving only one request per 10 minutes - you must set up your timer to send one request each 10 or more minutes. If documentation not provide such information - you can test it manually by finding some patterns with external service responses.
Use proxy
Every limitation policy based on information about requests senders. Usually this information consists of IP address of sender only. This means if you send 2 requests from two different IP addresses - limitation policy will perceive that like 2 different computers sending these requests. So you can find/buy/rent some proxy IP addresses and send requests through there on target web server.
How to connect through proxy in C# using WebRequest you can see in this answer.
Negotiate with external service provider
If you have possibility to communicate with external service developers or help center, you can ask their to reduce limitations for your IP address (if it static) or provide some mechanisms to avoid limitation policy for you. If for some reason they cannot provide this opportunity, at least you can ask detailed information about limitations.
Repetition mechanism
Some times 503 error code that is outer exception you received may be caused by service unavailable. It means that server can be under maintenance or temporary overloaded. So you can write repetition mechanism to make continious sending requests to server until it'll be accessible.
Polly library may help you with repetition mechanism creation
The inner error of that 503 is:
The remote server returned an error: (429)
HTTP 429 indicates too many requests. Maybe your upstream server can’t process all requests sent.
This can happen when you reached rate limiting / throttling value if you’re calling a third party API.
UPDATE
As per page 28 in the API docs, you could configure throttling when creating a new API. Check if the throttling is too small or maybe turn off the throttling and see if that could fix the error?

Request parameter in Windows Mobile for REST API's

I have one Windows Handheld device application on .Net framework 3.5 which has the requirement of accessing a REST API. The REST API gives me JSON output which I am going to process later. I have the following code for that:-
HttpWebRequest webRequest;
string result = String.Empty;
try
{
webRequest = (HttpWebRequest)WebRequest.Create(url);
webRequest.Method = "POST";
webRequest.KeepAlive = false;
webRequest.ContentType = "application/x-www-form-urlencoded";
using (WebResponse response = webRequest.GetResponse())
{
using (StreamReader streamReader = new StreamReader(response.GetResponseStream()))
{
result = streamReader.ReadToEnd();
}
}
}
catch (Exception ex)
{
result = ex.Message;
}
The url variable is holding the url for the API with some query parameters in it.
For Example "http://www.something.com/Login?id=test&pwd=test".
Now my problem is I dont want to use the query string parameters rather I want to use Request parameters because the above approach does not work every time perfectly. Some times I get an "Unauthorized" error. And also I have one tokenId which I need to send everytime I am calling the API and the token Id is in base64 format.
Can anyone please help me how can I use the Request Parameter feature to send the parameter values?
use the Headers property of your request object.
webRequest.Headers.Add("id", "test");
webRequest.Headers.Add("pwd", "test");
webRequest.Headers.Add("token", myToken);

How can I successfully post JSON via C# to a Python Flask route that authenticates via the JSON content?

I've written a rudimentary API in a Flask project to allow POSTing data via JSON strings. The JSON requires two properties: username and apikey, which are validated through the following decorator:
def apikey_required(f):
#wraps(f)
def decorated_function(*args, **kwargs):
if not request.json:
abort(404)
json_data = request.json
if not 'username' in json_data or not 'apikey' in json_data:
abort(404)
user = User.query.filter(User.username == json_data['username']).first()
if not user or user.status != "superuser":
abort(404)
if not user.apikey or user.apikey != json_data['apikey']:
return jsonify({'status': 'error', 'message': 'unrecognized API key'})
return f(*args, **kwargs)
return decorated_function
I've written routes utilizing this decorator and they work beautifully in Python applications: Here's the basic structure of an API route:
#mod.route('/invadd', methods=['GET', 'POST'])
#apikey_required
def invadd():
json = request.json
#lots of application-specific logic that passes unit tests
My Flask unit tests work fine:
good_post_response = self.app.post(
'api/invadd', data=json.dumps(test_json),
content_type='application/json') # assertions which verify the reponse pass
Python applications I've written work fine:
response = urllib2.urlopen(req, json.dumps(post_json)) #req is an api route URL
response_json = json.loads(response.read())
But in my C# app, I get a SocketException: No connection could be made because the target machine actively refused it. when I try to post JSON to these same routes. Here's a relevant code snippet:
HttpWebRequest request = (HttpWebRequest)WebRequest.Create();
request.ContentType = "application/json";
request.Method = "POST";
request.ContentLength = postJSON.Length;
using (StreamWriter sw = new StreamWriter(request.GetRequestStream())) <--- FAILURE POINT
{
sw.Write(postJSON.ToString());
sw.Flush();
sw.Close();
}
HttpWebResponse response = (HttpWebResponse)request.GetResponse();
using (StreamReader sr = new StreamReader(response.GetResponseStream()))
{
string result = sr.ReadToEnd();
AddFeedback(result);
}
I've also tried using the WebClient class:
WebClient wc = new WebClient();
AddFeedback(String.Format("Processing order {0}", order.OrderID));
string postJSON = BuildJSON(order);
string url = String.Format("{0}api/invadd", gslBase); //I verified that the URL is correctly constructed
string response = wc.UploadString(url, "POST", postJSON);
AddFeedback(response);
It's clear to me that the failure happens when the app tries to initiate the connection to the route, as it never gets to the point where it's actually trying to post the JSON data. But I'm not sure how to get around this. Do I need to change my Flask route?
That kind of exception indicates that there was a error at the socket level - that's before you reach JSON, or even HTTP.
Make sure you're connecting to the right machine and the right port.
It's not clear where you're inputting that data on your C# code - you probably should be using WebRequest.Create("yoururl") .
You can also try to connect using a browser, and see if it works.
If all those details are right, you can use wireshark to check what, exactly, is causing the connection to fail

Can't access Web of Trust (WoT) API w/ JSON.Net

I'm new to JSON & am using VS 2013/C#. Here's the code for the request & response. Pretty straightforward, no?
Request request = new Request();
//request.hosts = ListOfURLs();
request.hosts = "www.cnn.com/www.cisco.com/www.microsoft.com/";
request.callback = "process";
request.key = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";
string output = JsonConvert.SerializeObject(request);
//string test = "hosts=www.cnn.com/www.cisco.com/www.microsoft.com/&callback=process&key=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";
try
{
var httpWebRequest = (HttpWebRequest) WebRequest.Create("http://api.mywot.com/0.4/public_link_json2?);
httpWebRequest.ContentType = "application/json";
httpWebRequest.Method = "POST";
using (var streamWriter = new StreamWriter(httpWebRequest.GetRequestStream()))
{
string json = output;
streamWriter.Write(json);
}
var httpResponse = (HttpWebResponse) httpWebRequest.GetResponse();
using (var streamReader = new StreamReader(httpResponse.GetResponseStream()))
{
var responseText = streamReader.ReadToEnd();
}
}
catch (WebException e)
{
MessageBox.Show(e.ToString());
}
//response = true.
//no response = false
return true;
}
When I run this, I get a 405 error indicating method not allowed.
It seems to me that there are at least two possible problems here: (1) The WoT API (www.mywot.com/wiki/API) requires a GET request w/ a body, & httpWebRequest doesn't allow a GET in the httpWebRequest.Method; or (2) the serialized string isn't serialized properly.
NOTE: In the following I've had to remove the leading "http://" since I don't have enough rep to post more than 2 links.
It should look like:
api.mywot.com/0.4/public_link_json2?hosts=www.cnn.com/www.cisco.com/www.microsoft.com/&callback=process&key=xxxxxxxxxxxxxx
but instead looks like:
api.mywot.com/0.4/public_link_json2?{"hosts":"www.cnn.com/www.cisco.com/www.microsoft.com/","callback":"process","key":"xxxxxxxxxxxxxxxxxxx"}.
If I browse to:api.mywot.com/0.4/public_link_json2?hosts=www.cnn.com/www.cisco.com/www.microsoft.com/&callback=process&key=xxxxxxxxxxxxxx; I get the expected response.
If I browse to: api.mywot.com/0.4/public_link_json2?{"hosts":"www.cnn.com/www.cisco.com/www.microsoft.com/","callback":"process","key":"xxxxxxxxxxxxxxxxxxx"}; I get a 403 denied error.
If I hardcode the request & send as a GET like below:
var httpWebRequest = (HttpWebRequest) WebRequest.Create("api.mywot.com/0.4/public_link_json2? + "test"); it also works as expected.
I'd appreciate any help w/ this & hope I've made the problem clear. Thx.
Looks to me like the problem is that you are sending JSON in the URL. According to the API doc that you referenced, the API is expecting regular URL encoded parameters (not JSON), and it will return JSON to you in the body of the response:
Requests
The API consists of a number of interfaces, all of which are called using normal HTTP GET requests to api.mywot.com and return a response in XML or JSON format if successful. HTTP status codes are used for returning error information and parameters are passed using standard URL conventions. The request format is as follows:
http://api.mywot.com/version/interface?param1=value1&param2=value2
You should not be serializing your request; you should be deserializing the response. All of your tests above bear this out.

Windows Phone REST Call issue

I got a Windows Phone project which are getting an list of a object that i call friend from an webservice using REST. The whole connection part works good the first time, the second time it fails. I get the same value from the method even tho i change the value in the database. Here is an example.
Users goes to an page
The right value is fetched from the database using an WCF service
I change the value in the database manually
User goes into the page again and the method for fetching the data is started again but it still gets the same result as the first time it fetched data from the webservice.
Any ideas?
Code:
HttpWebRequest request;
protected override void OnNavigatedTo(System.Windows.Navigation.NavigationEventArgs e)
{
UpdateData();
}
public void UpdateData()
{
((App)App.Current).ShowProgressBar();
string uri = App.SERVICE_URI + "/GetFriends?userid=" + App.CurrentUserId;
request = (HttpWebRequest)HttpWebRequest.Create(new Uri(uri));
request.BeginGetResponse(new AsyncCallback(GetFriendsReadCallback), request);
}
private void GetFriendsReadCallback(IAsyncResult asynchronousResult)
{
List<Friend> friends;
HttpWebRequest request = (HttpWebRequest)asynchronousResult.AsyncState;
HttpWebResponse response = (HttpWebResponse)request.EndGetResponse(asynchronousResult);
using (StreamReader streamReader1 = new StreamReader(response.GetResponseStream()))
{
string resultString = streamReader1.ReadToEnd();
var ser = new DataContractJsonSerializer(typeof(List<Friend>));
var stream = new MemoryStream(Encoding.Unicode.GetBytes(resultString));
DataContractJsonSerializer jsonSerializer = new DataContractJsonSerializer(typeof(List<Friend>));
friends = (List<Friend>)jsonSerializer.ReadObject(stream);
}
You are running into a caching issue, most likely. Either change your REST service to disable caching:
Response.Cache.SetCacheability(HttpCacheability.NoCache);
If you don't have access to the service code, you can append a changing dummy parameter to the end of your request URL (e.g. a GUID or DateTime.Now.Ticks).
Check out my answer here: WebClient in a WP7.1 app called only once
I'd run this in the emulator with fiddler2 operating - check what id being sent over http to find out if the call is being made second time, and if the correct answer is being sent back. Once you know whether the problem is client or server side then start debugging using breakpoints - where is the wrong value first picked up.

Categories

Resources