3

total n00b when it comes to restful stuff, ajax, and so forth so please be gentle.

I have an issue whereby I have taken the example ServiceStack "Todo" service, and am trying to develop a mobile client using this service as a data source. I'm trying to learn how it all works so I can build a specific service which I feel SS is more suited to as opposed to WCF/WebAPI.

Anyway let's say that the Service is running on http://localhost:1234/api/todos I have enabled CORS support based on cobbling together information found in various other posts. So my Configure function looks like this:

Plugins.Add(new CorsFeature());

            this.RequestFilters.Add((httpReq, httpRes, requestDto) =>
            {
                httpRes.AddHeader("Access-Control-Allow-Origin", "*");
                //Handles Request and closes Responses after emitting global HTTP Headers
                if (httpReq.HttpMethod == "OPTIONS")
                {
                    httpRes.AddHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS");
                    httpRes.AddHeader("Access-Control-Allow-Headers", "X-Requested-With, Content-Type");
                    httpRes.StatusCode = 204;
                    httpRes.End();
                }
            });

and I have a service method like this on the TodoService:

[EnableCors]
        public object Post(Todo todo)
        {

            var t = Repository.Store(todo);
            return t;
        }

Using a browser (FF/IE) If I call this ajax function:

var todo = { content: "this is a test" };
            $.ajax(
            {
                type: "POST",
                contentType: "application/json",
                data: JSON.stringify(todo),
                timeout:20000,
                url: "http://localhost:1234/api/todos",
                success: function (e) {
                    alert("added");
                    app.navigate("Todo");
                },
                error: function (x, a, t) {
                    alert("Error");
                    console.log(x);
                    console.log(a);
                    console.log(t);
                }
            }
            );

from http://localhost:1234, then it all works fine. The todo gets added and in the success function, "e" contains the returned todo object the service created. However, if I call this from anywhere else (http://localhost:9999 i.e the asp.net dev server that the mobile client app is running under) then, although the Service method executes, and the todo does get added on the server side, the response back to jquery is empty, and it hits the error function right away.

I'm convinced I am doing something dumb but I can't for the life of me see it. Anyone have any clue? Thanks in advance...

Update: Well it seems to work OK now, the problem appeared to be

 httpRes.AddHeader("Access-Control-Allow-Origin", "*");

outside of the "OPTIONS" block. So the code that works in apphost is

Plugins.Add(new CorsFeature());
            this.RequestFilters.Add((httpReq, httpRes, requestDto) =>
            {

                //Handles Request and closes Responses after emitting global HTTP Headers
                if (httpReq.HttpMethod == "OPTIONS")
                {
                    httpRes.AddHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS");
                    httpRes.AddHeader("Access-Control-Allow-Origin", "*");
                    httpRes.AddHeader("Access-Control-Allow-Headers", "X-Requested-With, Content-Type");
                    httpRes.StatusCode = 204;
                    httpRes.End();
                }
            });
3
  • It might be worth adding the update as an answer to the question instead if it solved your problem. That would make it obvious to anyone else with a similar issue Commented Feb 24, 2013 at 10:31
  • @levelnis, I will as soon as I know for sure that the problem is resolved :) Commented Feb 24, 2013 at 11:26
  • Fair enough. You could still add it as an answer though, no? Just don't accept it until you've confirmed resolution. Your call... Commented Feb 24, 2013 at 11:34

1 Answer 1

4

so it turns out there was a problem in my original code; the amdended code is:

Plugins.Add(new CorsFeature());
            this.RequestFilters.Add((httpReq, httpRes, requestDto) =>
            {

                //Handles Request and closes Responses after emitting global HTTP Headers
                if (httpReq.HttpMethod == "OPTIONS")
                {
                    httpRes.AddHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS");
                    //this line used to be outside the if block so was added to every header twice.                      
                    httpRes.AddHeader("Access-Control-Allow-Origin", "*");
                    httpRes.AddHeader("Access-Control-Allow-Headers", "X-Requested-With, Content-Type");
                    httpRes.StatusCode = 204;
                    httpRes.End();
                }
            });

So the CorsFeature() plugin would appear to be correctly handling all CORs stuff for POST, GET and the pre-flight OPTIONS request is being handled by the RequestFilter (confusion - why doesn't the plugin just handle the OPTIONS request?) ; in the old code, the allow-origin header was being added twice for every request (by the plugin and by the filter) and this seems to have been confusing either jquery or the browser.

Not that I fully understand any of this , I have some reading to do :) and it's all been rendered moot anyway since the mobile framework I am using (DXTreme) can't seem to handle anything other than JSONP (no good for me since I need POST/PUT) for a cross-domain Rest Data source, so I am already going to have to go the proxy route, or dump the framework, or find some other way around my issues.

Sign up to request clarification or add additional context in comments.

2 Comments

Note: You should change httpRes.End() to httpRes.EndServiceStackRequest() to properly end the request.
@mythz - thanks but when I did that, it stopped working again...I only see the preflight OPTIONS request being sent and my ajax error handler immediately fires as there is no response content. The response headers now show the allow origin as "*, *" and all of the allow-methods are duplicated. The only way I have been able to get this working is in the code above. Now even more confused than ever!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.