Why it works using Ajax POST but not using HttpWebRequest? - c#

Here's a strange thing: I'm trying to send data to a Coldfusion web service via HttpWebRequest (also tried with HttpClient), and I always get a "login page" as response.
BUT, if I do the same thing as Ajax Post, it works.
BUT², if I put the content-type as "application/json" in the Ajax call, it returns the login page as well.
The web service manager says that the service doesn't need login, since we're using VPN to call it. But if I try to access the webservice URI via browser, it opens the login page.
The code in C#:
[EDIT] Created the object using JsonConvert
var request = HttpWebRequest.Create("http://url.cfc");
var obj= new
{
method = "MethodName",
data1 = "123456",
data2 = "aaa"
};
string postData = JsonConvert.SerializeObject(obj);
request.Method = "POST";
//request.ContentType = "application/json"; (not using!!!)
using (var writer = new StreamWriter(request .GetRequestStream()))
{
writer.Write(postData );
writer.Flush();
writer.Close();
}
var response = (HttpWebResponse)request.GetResponse();
var responseString = new StreamReader(response.GetResponseStream()).ReadToEnd();
And the code in JS:
$.ajax({
type: "post",
url: "http://url.cfc",
data: ({
method: "MethodName",
data1: 123456,
data2: "aaa" }),
dataType: "json",
success: function (result) {
console.log(result); },
error: function (result) {
console.log(result); },
});
});
Is there some substantial difference between Ajax call and HttpWebRequest call that can "block" the request using C#? Or maybe I'm failing in put some important data in HttpWebRequest's Header? Moreover: some issue in Coldfusion's web service authorization configuration?

You may need to move the methodname to the url instead of passing as a post param.
In Javascript in your AJAX call:
url: "http://url.cfc?method=MethodName"
and in C#:
var request = HttpWebRequest.Create("http://url.cfc?method=MethodName");

Related

simulate ajax call using C#

I am making an ajax call to a local resource like this
$.ajax({
url: 'http://localhost:10001',
dataType: "text",
data: { a: 'aVal',b: 'bVal',message: 'message' },
success: function (data) {
$("#test").append(data);
},
error: function (jqXHR,textStatus,errorThrown) {
alert('error '+textStatus+" "+errorThrown);
}
});
Now i just want to simulate the call from C#.
I am able to make a raw call using this code
WebRequest request = WebRequest.Create("http://localhost:10001");
request.ContentType = "text";
HttpWebResponse response = (HttpWebResponse)request.GetResponse();
i dont know how to send the data along.If there is a better way, kindly suggest
Also, I want this to have the exact structure and appearance because i am handling the request at the node js server like this
var url=require('url');
var url_parts=url.parse(request.url,true);
var data=url_parts.query;
Thanks
As it is a get request you can pass parameters in query string of url:
string aVal="aVal";
string bVal="bVal";
string message="message";
string Url ="http://localhost:10001?a="+aVal+"&b="+bVal+"&message="+message;
WebRequest request = WebRequest.Create(url);
For details on How to make get and post Request in C# see this article

Programmatically making a GET request

Say I had the following Jquery request
$.ajax({
type: "GET",
url: "http://localhost:8501/exampleservice.svc/rest/Start",
contentType: "application/json; charset=utf-8",
processData: false,
data: { confirmationNum : '90210' },
dataType: "json",
success: function (data, status, xhr)
{
},
error: function (xhr, status, error)
{
},
complete: function (xhr, status)
{
}
});
What is the proper way to this correctly in C#?
I have tried the following with an error occurring at the data stream:
"An unhandled exception of type 'System.Net.ProtocolViolationException' "
string biometricURL = "http://localhost:8501/exampleservice.svc/rest/Start";
byte[] jsonData = new ASCIIEncoding().GetBytes("{ confirmationNum : '90210' }");
WebRequest request;
request = WebRequest.Create(biometricURL);
request.ContentType = "application/json; charset=utf-8";
request.ContentLength = jsonData.Length;
request.Credentials = CredentialCache.DefaultCredentials;
Stream dataStream = request.GetRequestStream();
dataStream.Write(jsonData, 0, jsonData.Length);
dataStream.Close();
HttpWebResponse response = (HttpWebResponse)getBiometricCapture.GetResponse();
The GET Request does not have a body / content. As a result, using the:
Stream dataStream = request.GetRequestStream();
dataStream.Write(jsonData, 0, jsonData.Length);
dataStream.Close();
may cause the "System.Net.ProtocolViolationException".
If you want to pass custom data through the GET Request, append custom parameters via the QueryString or Headers.
Otherwise, use the POST Request instead.
The matter here is that you have a body in your GET request. Here are two solutions to solve your issue:
Change your request type to POST instead of GET (type: "POST")
Remove your contentType: "application/json; charset=utf-8" parameter. ContentType is useless if you're doing a GET request. GET requests should not have content-type because they do not have request entity.
As other users have already answered, you don't pass JSON objects in the content body for a GET request. However, using a post method like they suggest is not RESTful, which is what it appears you are trying to build based on the semantics of your example URL.
In RESTful services, simple accessors are implemented with the parameters passed as URL path fragments (the exception generally being complicated queries, in which case you use query variables in the URL or a POST). This is not the case for you, as you are accessing by a simple ID. So, for example, if you are trying to get a BiometricCapture resource with id 12345, you would access the URL:
http://localhost:8501/exampleservice.svc/rest/biocaptures/12345
Included the data as part of the URL like this.
HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create("http://localhost:8501/exampleservice.svc/rest/Start?confirmationNum='90210'");
request.Method = "GET";
request.ContentType = "application/json; charset=utf-8";
HttpWebResponse response = (HttpWebResponse)request.GetResponse();

how do i turn this $.ajax request into a WebClient execution

I have a page called: tar-url.com
I want to ping target page with a PUT request viai C#.
I want to return a Success or Error to client.
This exists and works with all clients NOT IE.
var xml = "[XMLDOC]";
$.ajax({
type: "PUT",
contentType: "multipart-form",
url: "tar-url.com",
headers: {Authorization: "Basic herpderp="},
data: xml
success: function(){console.log("success");},
error: function(){console.log("error");}
});
This is the request i normally do. It works in my old format, but there is 1 hitch, it doesnt work in IE9, SO i came up with this brilliant idea; Have my server do it, not the browser.
I create a Generic Handler: gHand.ashx which allows me to carry out my calls.
I do this for some other calls, but it is simple GET requests, that return some JSON. Here is where i need help.
I create my method as given in C#:
public void ProcessRequest(HttpContext context)
{
WebClient wsb = new WebClient();
//pass *tar-url.com here*.
string url = context.Request.QueryString["url"];
//pass contentType here.
string ct = context.Request.QueryString["contextType"];
string type = context.Request.QueryString["type"];
string headers = context.Request.QueryString["headers"];
//not sure how to access the xml?
// something like this?
string xml = context.Request.QueryString["save"];
//HERE I NEED TO ASSIGN REST OF STUFF TO *wsg*
string response = wsb.DownloadString(url);
context.Response.Write(response);
}
How i Call it in javascript:
$.ajax({
url:"gHand.ashx",
type: "get",
data: JSON.stringify({
save: xml,
type: "PUT",
url: "tar-url.com",
contentType: "multipart/form",
headers:{ Authorization: "Basic HerpDerp="}
}),
success: function(){...},
error: function(){...}
});
My calls are all seeming to be correct in the sense that i can build a WebClient and execute similar scripts, but it seems that this particular set up boggles my mind.
Edit: Has anyone any idea?
When you send your data to the server, you will want to decode it.
example:
You are sending a map of:
{
save:xml,
url: url,
type:type,
contenType: ct,
headers:{...}
}
So you can look at that and say, similar to how it says:
string url = context.Request.QueryString["url"];
and proceed as normal. Your REQUEST TYPE is the last thing you should check because it determines HOW your WebClient object will react.
Since data is going to be saved, instead of you doing
wsb.DownloadString(url);
which is more or less a get request, you would want to do something like:
wsb.uploadString(URL, METHOD, DATA);
Since you are pushing an XML DOC, or:
wsb.uploadData(URL, METHOD, DATA);
if you are uploading images.
Source: http://msdn.microsoft.com/en-us/library/system.net.webclient.aspx
It doesnt matter which order you assign variables, but when you call uploadData, it is executing the webclient request. There is NOT an wsb.execute() command.

GET 405 method not allowed

This is my jquery code to call web api
var request = {
RequestId: "123",
DeviceId: "ACU-B2-01-R1",
AccessType: "Unlock",
LoginId: "tester",
Password: "tester"
};
$.ajax({
url: 'http://localhost:55208/api/accesspanel',
type: 'POST',
data: JSON.stringify(request),
dataType: 'jsonp',
contentType: "application/json;charset=utf-8",
success: function (data) {
alert("success");
alert(JSON.stringify(data));
},
error: function (x, y, z) {
alert(x + '\n' + y + '\n' + z);
}
});
When I run this code, nothing happens. Neither the success nor error block gets fired. After checking in the debug console of chrome, this is the error record:
GET http://localhost:55208/api/accesspanel?callback=jQuery18203847100134007633_…22,%22LoginId%22:%22tester%22,%22Password%22:%22tester%22}&_=1364916423737 405 (Method Not Allowed)
send jquery.min.js:2
p.extend.ajax jquery.min.js:2
(anonymous function)
I am, however, able to call my web api method successfully using C# code, which looks like this:
using (var client = new HttpClient())
{
client.BaseAddress = new Uri("http://localhost:55208/");
var request = new DeviceAccessRequest
{
RequestId = Guid.NewGuid().ToString(),
DeviceId = "ACU/B2/01/R1",
AccessType ="Unlock",
LoginId = "tester",
Password = "tester" ,
};
var response = client.PostAsJsonAsync("api/accesspanel", request).Result;
if (response.IsSuccessStatusCode)
{
var deviceAccessResponse = response.Content.ReadAsAsync<DeviceAccessResponse>().Result;
}
}
And this is my web api method:
[HttpPost]
public HttpResponseMessage PostDeviceControl(DeviceAccessRequest deviceAccessRequest)
{
var deviceAccessResponse = new DeviceAccessResponse(deviceAccessRequest.RequestId)
{
Status = "OK"
};
var response = Request.CreateResponse<DeviceAccessResponse>(HttpStatusCode.OK, deviceAccessResponse);
return response;
}
The reason you are seeing a GET request in your console is because you specified dataType: 'jsonp' which works only with GET requests (the reason for that is because jQuery translates this to a <script> tag pointing to the url you specified). If you want to be doing cross domain AJAX with other verbs than GET you cannot use JSONP. If you need to use other verbs (such as POST in your case) you have 2 options:
CORS. Take a look at the following video which illustrates how you could enable CORS on your Web API. Obviously for this to work your client side browser need tio support it
Server side bridge on your domain. The idea here is to have some server side script on the domain hosting your javascript code that will send the HTTP request to the API and return the response to the client. Then you will send a regular AJAX POST request to your own domain

Running Multiple WebRequests at the same time with $.ajax

I have 2 MVC apps that need to connect to a 3rd application. The code that is causing problems is identical in both MVC apps.
public bool UpdateServerData()
{
//string BASE_URL = "http://";
string BASE_URL = "http://localhost:55094";
string url = BASE_URL + "/Home/PullLiveData";
WebRequest wr = WebRequest.Create(url);
wr.Credentials = CredentialCache.DefaultNetworkCredentials; // uses current windows user
var response = (HttpWebResponse)wr.GetResponse();
return true;
}
public ActionResult GetServerUpdateProgress()
{
//string BASE_URL = "http://";
string BASE_URL = "http://localhost:55094";
string url = BASE_URL + "/Home/UpdateProgress";
WebRequest wr = WebRequest.Create(url);
wr.Credentials = CredentialCache.DefaultNetworkCredentials; // uses current windows user
var myobj = new UpdateAJAXProgress();
var response = (HttpWebResponse)wr.GetResponse();
var reader = new StreamReader(response.GetResponseStream());
JavaScriptSerializer js = new JavaScriptSerializer();
var objText = reader.ReadToEnd();
myobj = (UpdateAJAXProgress)js.Deserialize(objText, typeof(UpdateAJAXProgress));
return Json(myobj);
}
UpdateServerData tells localhost:55094 to refresh the data in the db.
GetServerUpdateProgress returns a progress count / total so that I can display a progress bar for the db refresh.
The $.ajax that runs UpdateServerData is set to work async: true
Then using setTimeouts, I run GetServerUpdateProgress every few seconds which returns how far along UpdateServerData is from completing.
Working App Functionality:
Not Working:
So what appears to be happening in the non-working version is that it is not running GetServerUpdateProgress even though ajax is calling up the function, it doesn't actually begin to process anything inside it until UpdateServerData is complete. You can see the ajax is sync is set correctly because the loading animation is displayed for both in the non working screen shot. I put a breakpoint at the start of GetServerUpdateProgress and it doesn't even trigger until after UpdateServerData is finished processing.
My main concern is that some setting, perhaps in the webconfig or global.asax, is different and that is what is causing both these apps to run a little differently. Any ideas?
Here's some of the associated javascript:
function UpdateData()
{
$("#ChartUpdateProgressWhole").show();
$.ajax({
type: "POST",
async: true,
url: '#(Url.Action("UpdateServerData", "Charts"))',
contentType: "application/json; charset=utf-8",
success: function (data) {
Alert2({
iconfilename: "tick.png",
text: "Database Updated!",
autohide: true,
});
},
error: function (XMLHttpRequest, textStatus, errorThrown) {
},
complete:function (jqXHR, textStatus) {
$("#ChartUpdateProgressWhole").hide();
timerStop = true;
LoadChart();
},
});
if (!timerStop) {
CheckProgress();
}
}
function CheckProgress()
{
if(timerStop) {
CheckProgressAjax();
return;
}
window.setTimeout(CheckProgress, 2000);
CheckProgressAjax();
}
function CheckProgressAjax()
{
$.ajax({
type: "POST",
async: false,
url: '#(Url.Action("GetServerUpdateProgress", "Charts"))',
contentType: "application/json; charset=utf-8",
success: function (data) {
var width = (data.Completed * 100)/data.Total;
$("#ChartUpdateProgressPercent").css("width", width);
},
error: function (XMLHttpRequest, textStatus, errorThrown) {
alert(XMLHttpRequest.status);
alert(XMLHttpRequest.responseText);
}
});
}
Taking a bit of a stab in the dark here, but ASP.NET will actually queue async requests and process them in order if session state is enabled (to avoid having to deal with synchronisation issues no doubt).
My suggestion would be to disable session state all together if feasible, if this is not possible you can disable it per controller using the following attribute:
[SessionState(SessionStateBehavior.Disabled)]
public class SomeController

Categories