1

Hi I have simplified my code as much as possible below. What I am trying to achieve is call a restful wcf service.However when I add the set request header method I get exception, in both Firefox and chrome, but it works in IE it successfully hits the service method.

<script src="http://code.jquery.com/jquery-1.9.1.min.js"></script>

    <script type="text/javascript" src="http://crypto-js.googlecode.com/svn/tags/3.1.2/build/rollups/hmac-md5.js"></script>
    <script type="text/javascript" src="http://crypto-js.googlecode.com/svn/tags/3.1.2/build/components/enc-base64-min.js"></script>
<script type="text/javascript">

    function WriteResponse(string) {        
        $("#divResult").val(string);
    }

    function setHeader(xhr) {
        var secretkey = "1234dgt";
        var hashedUrl = CryptoJS.HmacMD5($('#txtUrl').val(), secretkey);
        var hashedUrlBase64 = hashedUrl.toString(CryptoJS.enc.Base64);
        xhr.setRequestHeader('Authorization', hashedUrlBase64, "1234dgt");
    }

    $(document).ready(function () {
        $("#btnCall").click(function () {

            jQuery.support.cors = true;
            $.ajax({               
                url: $('#txtUrl').val(),
                type: 'GET',
                async: false,
                dataType: 'json',
                success: function (data) {
                    WriteResponse(data);
                },
                error: function (x, y, z) {
                    alert(x + '\n' + y + '\n' + z);
                },
                beforeSend: setHeader
            });
        });
    });

</script>

Any help would be much appreciated.
Thanks

// Here is the c# code used to call the same service:
public static string GetUserBookmarks(string uri)
    {
        HttpWebRequest request = WebRequest.Create(uri) as HttpWebRequest;
        string encodedUri = EncodeText(_key, uri, UTF8Encoding.UTF8);
        request.Headers[HttpRequestHeader.Authorization] = encodedUri;
        HttpWebResponse response = request.GetResponse() as HttpWebResponse;
        Stream bookmarksStream = response.GetResponseStream();
        StreamReader reader = new StreamReader(bookmarksStream);
        string str = reader.ReadToEnd();
        reader.Close();
        bookmarksStream.Close();
        return str;
    }

    public static string EncodeText(string key, string text, Encoding encoding)
    {
        HMACMD5 hmacMD5 = new HMACMD5(encoding.GetBytes(key));
        byte[] textBytes = encoding.GetBytes(text);
        byte[] encodedTextBytes =
            hmacMD5.ComputeHash(textBytes);
        string encodedText =
            Convert.ToBase64String(encodedTextBytes);
        return encodedText;
    }



// Here is the wcf service method and its interface\contract

[ServiceContract]
public interface IRestSerivce
{
    [WebGet(UriTemplate = "users/{username}")]
    [OperationContract]
    List<string> GetUserBookmarks(string username);

}



public List<string> GetUserBookmarks(string username)
    {
        WebOperationContext context = WebOperationContext.Current;
        OutgoingWebResponseContext outgoingResponseContext =
            context.OutgoingResponse;

        bool isUserAuthenticated = IsUserAuthenticated(username);
        if (isUserAuthenticated == false)
        {
            outgoingResponseContext.StatusCode = HttpStatusCode.Unauthorized;
            return null;
        }

        outgoingResponseContext.StatusCode = HttpStatusCode.OK;

        List<string> bookmarks = new List<string>();
        bookmarks.Add("User has been authenticated Successfully");

        return bookmarks;
    }

Here is the error I am receiving, this is the alert in the ajax error function producing this, however there are no errors in the firbug console window.

[object Object] error [Exception... "Failure" nsresult: "0x80004005 (NS_ERROR_FAILURE)" location: "JS frame :: http://code.jquery.com/jquery-1.9.1.min.js :: .send :: line 5" data: no]

Mark
  • 11
  • 3

2 Answers2

0

Can you please have a look at this stackoverflow question, I think it demonstrates what you are trying to achieve.

I think you're passing one parameter too many to setRequestHeader.

Community
  • 1
  • 1
Nikolaos Georgiou
  • 2,434
  • 1
  • 22
  • 28
  • Hi, unfortunately removing either the second or third param to the setRequestHeader method produces the same error. – Mark Mar 11 '13 at 12:35
  • Can you call the service successfully by some other way, e.g. via a small C# console application? So you can eliminate any other problems like wrong salt or similar trivial issues. – Nikolaos Georgiou Mar 11 '13 at 13:23
  • Hi Nikolaos, yes I can call the service fine via a c# console app. I could send you sample code. I have wcf restful service being called by c# console app and also via web app. If i remove the set header method it works fine. I cannot find any help on the web for this matter. – Mark Mar 11 '13 at 14:19
  • and you're generating the Authorization header the same way in the C# app? MD5 hash of the target URL with a secret key and then base64 the entire thing? one more thing you can try is instead of using the beforeSend function, use the headers attribute. Check out the second answer [in this question](http://stackoverflow.com/questions/3258645/pass-request-headers-in-a-jquery-ajax-get-call) – Nikolaos Georgiou Mar 11 '13 at 14:36
  • Hi do you have an email I can send this to? – Mark Mar 11 '13 at 16:29
  • Hi Mark, just post it here, so that more people can have a look. – Nikolaos Georgiou Mar 11 '13 at 19:48
  • I have added additional code to help resolve this if anyone can help. – Mark Mar 12 '13 at 09:19
  • Also just to reiterate, if I remove the setHeader in the ajax call it works and I hit the breakpoint on the server method, also it works in IE but not Chrome or Firefox. – Mark Mar 12 '13 at 09:24
  • So the ajax call works without authorization? That might mean that you aren't enforcing the authorization on the service side (which is of course a different problem). Do you get any javascript errors with the setHeader? Have you checked the javascript console in your browser? Also, please try with the headers approach instead of the setHeader to see if it makes a difference. My best guess so far is that there's some Javascript error you need to debug (as I said earlier, setRequestHeader doesn't take 3 parameters but 2). – Nikolaos Georgiou Mar 12 '13 at 10:02
  • I cannot add an image unfortunately as I need a reputation of 10 +. – Mark Mar 12 '13 at 11:38
  • I have added the error above with description. If I remove one of the params I get the same error. I see what you are saying about the server side, but it is strange that it works in IE. – Mark Mar 12 '13 at 11:39
  • Have you searched for this error online? If I do a google search I end up [here](http://stackoverflow.com/questions/5133864/ajax-cross-domain-problem). Is this your case? Are you doing a cross-domain call with async=false? Regarding the server-side authorization, try to remove the header from the C# client demo app to see if you still can access the server. If you can, it means the authorization isn't enforced. – Nikolaos Georgiou Mar 12 '13 at 11:46
0

I finally found the issue with my code, it was due to Authorization headers not being allowed server side. So to solve the issue I needed to add some code to the global.asac.cs class of my wcf project. The below code also enables cross domain calls.

    protected void Application_BeginRequest(object sender, EventArgs e)
    {

        HttpContext.Current.Response.Cache.SetCacheability(HttpCacheability.NoCache);
        HttpContext.Current.Response.Cache.SetNoStore();

        EnableCrossDmainAjaxCall();
    }

    private void EnableCrossDmainAjaxCall()
    {
        HttpContext.Current.Response.AddHeader("Access-Control-Allow-Origin",
                      "*");

        if (HttpContext.Current.Request.HttpMethod == "OPTIONS")
        {
            HttpContext.Current.Response.AddHeader("Access-Control-Allow-Methods",
                          "GET, POST");
            HttpContext.Current.Response.AddHeader("Access-Control-Allow-Headers",
                          "Content-Type, Accept, Authorization");
            HttpContext.Current.Response.AddHeader("Access-Control-Max-Age",
                          "1728000");
            HttpContext.Current.Response.End();
        }
    }

Thank you to Nikolaos for your help.

Mark
  • 11
  • 3