views:

1671

answers:

4

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)?

+2  A: 

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.

jjnguy
I hope you're going to put some using blocks in there. I'm down to two votes - don't make me _use_ one on you...
John Saunders
ok, ill take care of my streams
jjnguy
p.s. I'm not very good at C#.
jjnguy
p.p.s Please don't ever copy paste the code I post on this site into production code of your own. God will kill kittens!
jjnguy
A: 

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

Janie
I don't have access to that service in my web project. It's in a different part of the code base than where my files are.
norabora
I understand that; VS will generate a proxy object that will interact with that service on your behalf. You'll have access to all the methods on it...
Janie
Have a look at jjnguy's solution for specifics...
Janie
@Janie, thanks.
jjnguy
A: 

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?

Nathan
What about @jjnguy's plan?
jjnguy
You didn't add the JavaScriptSerializer. /jkI'm still curious if you can build proxy classes for JSON services... Can't seem to get it working on my machine here...
Nathan
+2  A: 

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}";
norabora