How to call an external URL from a ASP.NET MVC solution - c#

First post inhere ever. So better make it a good one.
I have a ASP.NET MVC 2 web application in which I have an actionResult I need to do a call for me.
The thing is I need this A.R to handle some data operations and after that I need it to call an external URL which is actually a Company Module that handles sending messages to our company handset phones.
It just needs to call the URL that looks like this:
string url = "http://x.x.x.x/cgi-bin/npcgi?no=" + phoneNumber + "&msg=" + message;
I don't need any return message or anything. Just want to call that external URL which is of course outside the scope of my own web application. (I do not want to Redirect). That URL must be called behind the GUI without the user ever realising. And the page that they are viewing must not be affected.
I tried with:
Server.Execute(url);
However did not work. I've heard that some ppl go about this by having a hidden iFrame on the page. The setting the src to the url one may need and then somehow execute that, to get the call instantiated. It doesn't seem so elegant to me, but if that is the only solution, does anyone have an example as to how that is done. Or if you have a more sleek suggestion I am all ears.

I finally got it working with this piece of code:
string messageToCallInPatient = "The doctor is ready to see you in 5 minutes. Please wait outside room " + roomName;
string url = "http://x.x.x.x/cgi-bin/npcgi?no=" + phoneNumber + "&msg=" +
messageToCallInPatient;
HttpWebRequest webReq = (HttpWebRequest)WebRequest.Create(string.Format(url));
webReq.Method = "GET";
HttpWebResponse webResponse = (HttpWebResponse)webReq.GetResponse();
//I don't use the response for anything right now. But I might log the response answer later on.
Stream answer = webResponse.GetResponseStream();
StreamReader _recivedAnswer = new StreamReader(answer);

Since you don't expect a return value from the url, simplest way is
After the AR Execution, use Webclient to trigger the URL
Either by HTTP GET or POST (Synchronous or Asynchronous)
Sample code
WebClient wc = new WebClient();
wc.UploadProgressChanged += (sender, evtarg) =>
{
Console.WriteLine(evtarg.ProgressPercentage);
};
wc.UploadDataCompleted += (sender, evtarg) =>
{
String nResult;
if (evtarg.Result != null)
{
nResult = Encoding.ASCII.GetString(evtarg.Result);
Console.WriteLine("STATUS : " + nResult);
}
else
Console.WriteLine("Unexpected Error");
};
String sp= "npcgi??no=" + phoneNumber + "&msg=" + message;
System.Uri uri = new Uri("http://x.x.x.x/cgi-bin/");
wc.UploadDataAsync(uri, System.Text.Encoding.ASCII.GetBytes(sb);
The sample uses HTTP POST and Asynchronous call( So it will return immediately after triggering the URL - Non blocking)

You can use simply " return Redirect(url);"

Related

Outlook Rest API returning no results

I'm trying to display a list of events from an Outlook calendar using the example request microsoft have here
However, I've no proper experience with using any sort of REST APIs before. Using the URL they provide I should be getting something back but I'm not. Here is the code in my controller:
string uri = "https://outlook.office365.com/api/v1.0/me/events";
var webRequest = (HttpWebRequest)WebRequest.Create(uri);
webRequest.Method = "GET";
string result = "";
try
{
WebClient webClient = new WebClient();
webClient.Encoding = Encoding.UTF8;
result = webClient.DownloadString(uri);
try
{
string returnedString = result;
TempData.Add("myval", result);
ViewBag.result = "returned string " + result;
}
catch (Exception er2)
{
ViewBag.error = er2.Message;
}
ViewBag.secondresult = "first result " + result;
}
catch (Exception er)
{
}
ViewBag.firstResult = "Outside try catch " + result;
ViewBag.url = uri;
return View();
Then in my view I'm calling the ViewBags like this:
<p> here </p>
#ViewBag.url
#ViewBag.firstResult
#ViewBag.result
#ViewBag.error
#ViewBag.secondresult
<p> end </p>
But besides my here and end I get nothing. This is a project that was set up without any input from myself so I'm having to do everything across a network which is why I'm using so many try catches.
Can someone with more experience with using REST APIs tell me if I'm messing something up somewhere?
I don't see any authentication in your code, so it's likely returning a 401. You need to use OAuth2 to get an access token and use that to authenticate your calls. Since you're doing this in C#, you might want to look at the API wrappers on NuGet that implement a lot of this for you. There are some sample starter apps on http://dev.office.com/code-samples that might be helpful too (search for ASP.NET MVC).

Web api HttpContext.Current.Request.UserAgent is always null

I'm trying to get some of api users request information like the device that they use and the operating system so I tried it like this :
private string GetDeviceInfo()
{
var userAgent = HttpContext.Current.Request.UserAgent;
var uaParser = Parser.GetDefault();
var c = uaParser.Parse(userAgent);
return c.Device + "|" + c.OS + "|" + c.UserAgent;
}
but the HttpContext.Current.Request.UserAgent is always null !. I searched about it and tried this link , could you please tell me what is wrong?
Request.UserAgent is just value of "user agent" header in HTTP request. Browser will automatically send it with all requests (including AJAX), no-browser clients generally will not include such header.
If your "client" is not browser it needs to add the header with appropriate values itself.
Sample if using HttpWebRequest
var request = (HttpWebRequest)WebRequest.Create("http://www.contoso.com");
request.UserAgent="My custom user agent string";
var response = (HttpWebResponse)myHttpWebRequest.GetResponse();

Why my Http client making 2 requests when I specify credentials?

I created RESTful webservice (WCF) where I check credentials on each request. One of my clients is Android app and everything seems to be great on server side. I get request and if it's got proper header - I process it, etc..
Now I created client app that uses this service. This is how I do GET:
// Create the web request
var request = WebRequest.Create(Context.ServiceURL + uri) as HttpWebRequest;
if (request != null)
{
request.ContentType = "application/json";
// Add authentication to request
request.Credentials = new NetworkCredential(Context.UserName, Context.Password);
// Get response
using (var response = request.GetResponse() as HttpWebResponse)
{
// Get the response stream
if (response != null)
{
var reader = new StreamReader(response.GetResponseStream());
// Console application output
var s = reader.ReadToEnd();
var serializer = new JavaScriptSerializer();
var returnValue = (T)serializer.Deserialize(s, typeof(T));
return returnValue;
}
}
}
So, this code get's my resource and deserializes it. As you see - I'm passing credentials in my call.
Then when debugging on server-side I noticed that I get 2 requests every time - one without authentication header and then server sends back response and second request comes bach with credentials. I think it's bad for my server - I'd rather don't make any roundtrips. How should I change client so it doesn't happen? See screenshot of Fiddler
EDIT:
This is JAVA code I use from Android - it doesn't do double-call:
MyHttpResponse response = new MyHttpResponse();
HttpClient client = mMyApplication.getHttpClient();
try
{
HttpGet request = new HttpGet(serviceURL + url);
request.setHeader(new BasicHeader(HTTP.CONTENT_TYPE, "application/json"));
request.addHeader("Authorization", "Basic " + Preferences.getAuthorizationTicket(mContext));
ResponseHandler<String> handler = new BasicResponseHandler();
response.Body = client.execute(request, handler);
response.Code = HttpURLConnection.HTTP_OK;
response.Message = "OK";
}
catch (HttpResponseException e)
{
response.Code = e.getStatusCode();
response.Message = e.getMessage();
LogData.InsertError(mContext, e);
}
The initial request doesn't ever specify the basic header for authentication. Additionally, since a realm is specified, you have to get that from the server. So you have to ask once: "hey, I need this stuff" and the server goes "who are you? the realm of answering is 'secure area'." (because realm means something here) Just because you added it here:
request.Credentials = new NetworkCredential(Context.UserName, Context.Password);
doesn't mean that it's going to be for sure attached everytime to the request.
Then you respond with the username/password (in this case you're doing BASIC so it's base64 encoded as name:password) and the server decodes it and says "ok, you're all clear, here's your data".
This is going to happen on a regular basis, and there's not a lot you can do about it. I would suggest that you also turn on HTTPS since the authentication is happening in plain text over the internet. (actually what you show seems to be over the intranet, but if you do go over the internet make it https).
Here's a link to Wikipedia that might help you further: http://en.wikipedia.org/wiki/Basic_access_authentication
Ok, I got it. I manually set HttpHeader instead of using request.Credentials
request.Headers.Add(HttpRequestHeader.Authorization, "Basic " + Convert.ToBase64String(Encoding.UTF8.GetBytes(Context.UserName + ":" + Context.Password)));
Now I see only single requests as expected..
As an option you can use PreAuthenticate property of HttpClientHandler. This would require a couple of lines more
var client = new HttpClient(new HttpClientHandler
{
Credentials = yourCredentials,
PreAuthenticate = true
});
With using this approach, only the first request is sent without credentials, but all the rest requests are OK.

Delete (MediaWiki) Page with C# (HTTP POST)

I try to delete a page like this:
WebClient wClient = new WebClient();
wClient.UploadStringCompleted += new UploadStringCompletedEventHandler(client_UploadStringCompleted);
string str_post = "action=delete" + "&title=Vorlage:" + str_zuloeschendeVorlage + "&token=" + str_token + "%2B%5C";
wClient.UploadStringAsync(new Uri(#"http://localhost/mediawiki/api.php"), "POST", str_post);
The Token is not the problem (i got a correct one). And i'm logged in as admin. The callback client_UploadStringCompleted is called correct (with a correct connection). No error code returns (from api). The result is just the code from the api.php (with no error code). But the site is still there. I think the uri or the str_post is wrong.
Please help!
i found the problem...
the headers-information was missing:
WebClient wClient = new WebClient();
wClient.Headers["Content-Type"] = "application/x-www-form-urlencoded";
wClient.UploadStringCompleted += new UploadStringCompletedEventHandler(client_UploadStringCompleted);
the rest of the code is correct
Why do you append "%2B%25C" to your querystring? It translates to " \" (space - antislash) which is strange since it will be part of the received token.
Try to issue the POST request without these noise characters.

Call webservice on outside server from javascript using asp.net and C#

I'm trying to test web service calls using an ASP.NET page that creates a form with username and password fields and a "Submit" button. (Both jQuery and the .js file I'm using are included in script tags in the head element.)
The "Submit" button calls a function created in the C# code behind file that makes a call to a separate JavaScript file.
protected void mSubmit_Click(object sender, EventArgs eventArgs)
{
String authenticate = String.Format("Authentication(\"{0}\",\"{1}\");", this.mUsername.Text,this.mPassword.Text);
Page.ClientScript.RegisterStartupScript(this.GetType(), "ClientScript", authenticate, true);
}
The JavaScript function, Authenticate, makes web service call, using jQuery and Ajax, to a different server, sending JSON parameters and expecting back JSON in response.
function Authentication(uname, pwd) {
//gets search parameters and puts them in json format
var params = '{"Header":{"AuthToken":null,"ProductID":"NOR","SessToken":null,"Version":1},"ReturnAuthentication":true,"Password":"' + pwd + '","Username":"' + uname + '",ā€¯ReturnCredentialsā€¯:false }';
var xmlhttp = $.ajax({
async: false,
type: "POST",
url: 'https://myHost.com/V1/Identity/Authenticate',
data: params,
contentType: 'application/json'
});
alert(xmlhttp.statusText);
alert(xmlhttp.responseText);
return;
}
However, because the web service I'm calling is on a different server than the ASP.NET, C# and JavaScript files, I'm not getting a statusText or responseText alert.
Somehow, nothing is being sent to the web service and I'm not getting anything back, not even an error. I tried putting a function in the beforeSend attribute, but that didn't fire. Is there a special way I need to handle calling an off-server web service?
UPDATE!
At the advice of jjnguy, Janie and Nathan, I'm now trying a server side call to the web service using HttpWebRequest. Using some of jjnguy's code as well as code from this question, I've come up with this.
public static void Authenticate(string pwd, string uname)
{
string ret = null;
HttpWebRequest request = (HttpWebRequest)WebRequest.Create("https://myhost.com/V1/Identity/Authenticate");
request.ContentType = "application/json";
request.Method = "POST";
string data = "{\"Header\":{\"AuthToken\":null,\"ProductID\":\"NOR\",\"SessToken\":null,\"Version\":1},\"ReturnAuthentication\":true,\"Password\":\"" + pwd + "\",\"Username\":\"" + uname + "\",\"ReturnCredentials\":false }'";
byte[] byteData = UTF8Encoding.UTF8.GetBytes(data);
request.ContentLength = byteData.Length;
using (Stream postStream = request.GetRequestStream())
{
postStream.Write(byteData, 0, byteData.Length);
}
HttpWebResponse response = (HttpWebResponse)request.GetResponse();
using (response)
{
// Get the response stream
StreamReader reader = new StreamReader(response.GetResponseStream());
// Console application output
ret = reader.ReadToEnd();
}
Console.WriteLine(ret);
}
However, I'm getting a (400) Bad Request error from the remote server when I try to get the response from my HttpWebRequest. The value of the Response property of the exception says {System.Net.HttpWebResponse} and the value of the Status property is ProtocolError. I'm pretty sure this is because the URL is using HTTP SSL protocol. What can I do to get around that, other than having the ASP.NET page URL start with HTTPS (not an option)?
Turns out the code that I posted in my update was correct, I just had a typo and one setting incorrect in the data string.
string data = "{\"Header\":{\"AuthToken\":null,\"ProductID\":\"NOR\",\"SessToken\":null,\"Version\":1},\"ReturnAuthentication\":true,\"Password\":\"" + pwd + "\",\"Username\":\"" + uname + "\",\"ReturnCredentials\":true}";
For simplicity's sake, why don't you write the call to the webservice in C# on the Server Side?
You have the same abilities to send requests and get responses in C# as you do with Javascript.
Here is a crack at your function in C#:
public static string Authenticate(string pwd, string uname)
{
HttpWebRequest requestFile = (HttpWebRequest)WebRequest.Create("https://myHost.com/V1/Identity/Authenticate");
requestFile.ContentType = "application/json";
requestFile.Method = "POST";
StreamWriter postBody = new StreamWriter(requestFile.GetRequestStream())
using (postBody) {
postBody.Write("{\"Header\":{\"AuthToken\":null,\"ProductID\":\"NOR\",\"SessToken\":null,\"Version\":1},\"ReturnAuthentication\":true,\"Password\":\"" + pwd + "\",\"Username\":\"" + uname + "\",\"ReturnCredentials\":false }'");
}
HttpWebResponse serverResponse = (HttpWebResponse)requestFile.GetResponse();
if (HttpStatusCode.OK != serverResponse.StatusCode)
throw new Exception("Url request failed. Connection to the server inturrupted");
StreamReader responseStream = new StreamReader(serverResponse.GetResponseStream());
string ret = null;
using (responseStream) {
ret = responseStream.ReadLine();
}
return ret;
}
Disclaimer This has not been tested.
Instead of using the client script to make the request from the server; use server side code to make the request
EDIT to expand answer:
From your web project in visual studio, click add web reference, and point to the service you were originally accessing via your client script: (I believe it was 'https://myHost.com/V1/Identity/Authenticate)
You can now talk to the service using c# code instead of js (and pass in the users provided credentials.)
Also, since the request against the service is coming from a server, rather than a browser; you bypass the cross-domain restrictions that apply.
FURTHER EDIT to show additional technique:
If you don't like the idea of using Visual Studio to generate a service proxy for you, then you can handcraft the request yourself using WebClient or HttpRequest
WebClient:
http://msdn.microsoft.com/en-us/library/system.net.webclient(VS.80).aspx
HttpWebRequest:
http://msdn.microsoft.com/en-us/library/system.net.httpwebrequest(VS.80).aspx
Seems like you're running into the same origin policy
http://en.wikipedia.org/wiki/Same_origin_policy
I believe there are ways to circumvent it, but I think the other posters are right. On the server, write methods that use a HttpWebRequest to call the web service, and then use JavaScriptSerializer to parse out the JSON. I spent most of the afternoon researching this cause I'll have to write something similar myself.
>>>> Nathan
P.S. I like #Janie's plan better... Can you do that with a web service that returns JSON as well as one that would pass back XML?

Categories