1

ServiceStack (9.54), POST request with JQuery AJAX.
cross domain request, prompts an Error "Request not found".

the service is self-hosted as windows service. FireWall is off.

I have done, what I read, in ServiceStack for cross domain calls (CORS), but without result.

In the web page, the code (which works successfully on localhost) is the following.

   jQuery.support.cors = true;
         CallTest()
         {
              $.ajax({
               type: 'POST',
               url: 'http://dev.testhost.com:18162/TestAPI',
               data: JSON.stringify(myRequest),
               contentType: 'application/json',
               dataType: 'json',
               success: function (response, status) {alert(status); },
               error :  error: function (xhr, err) { alert(err);  }
            }
        }
   //in server the code is 
   //1. at appHost
     SetConfig(new ServiceStack.WebHost.Endpoints.EndpointHostConfig
       {

           GlobalResponseHeaders =
           {      //Signal advanced web browsers what HTTP Methods you accept
              { "Access-Control-Allow-Origin", "*" },
              { "Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS" },
              { "Access-Control-Allow-Headers", "Content-Type" },

           }
  }
    //2. request
     [Route("/TestAPI", "POST")]
     [Route("/TestAPI", "GET")]
   public class myRequest
   {

    public string name { get; set; }
    public address[] addresses  { get; set; }
  }
   public class myResponse
  {
    public bool success { get; set; }
    public string message { get; set; }
   }
  // 3. Service
  [AddHeader(ContentType = ContentType.Json)]
    public myResponse  Post(myRequest request)
    {
       return new myResponse();
    }

I debugged with different settings in AppHost code, based on @mythz previous answers, ServiceStack CORS Feature

but it did not work for me.

Update 1: It works for Chrome, not for IE, FIREFOX, OPERA

    CHROME Request   
    POST /TestAPI/CreateReservation HTTP/1.1 
    Connection: keep-alive
    Content-Length: 622
    Accept: application/json, text/javascript, */*; q=0.01
    Chrome/27.0.1453.116 Safari/537.36
    Content-Type: application/json

    CHROME RESPONSE   
     HTTP/1.1 200 OK
     Transfer-Encoding: chunked
     Content-Type: application/json; charset=utf-8
     Server: Microsoft-HTTPAPI/2.0
     X-Powered-By: ServiceStack/3.954 Win32NT/.NET
     Access-Control-Allow-Origin: *
     Access-Control-Allow-Methods: GET, POST, PUT, DELETE, OPTIONS
     Access-Control-Allow-Headers: Content-Type

    IE10 Request
    OPTIONS /TestAPI/CreateReservation HTTP/1.1
    Accept: */*
    Origin:  localhost:28014
    Access-Control-Request-Method: POST
    Access-Control-Request-Headers: content-type, accept
    Accept-Encoding: gzip, deflate
    User-Agent: Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.1; WOW64; Trident/6.0)
    Host:  
    Content-Length: 0
    DNT: 1
    Connection: Keep-Alive
    Pragma: no-cache

    IE10 Response 
    HTTP/1.1 404 Not Found
    Content-Length: 3
    Content-Type: text/plain
    Server: Microsoft-HTTPAPI/2.0
    X-Powered-By: ServiceStack/3.954 Win32NT/.NET
    Access-Control-Allow-Origin: *
    Access-Control-Allow-Methods: GET, POST, PUT, DELETE, OPTIONS
    Access-Control-Allow-Headers: Content-Type

Update 2: Problem solved, it works, perfect for all browsers tested (Chrome,IE10, Firefox,Opera 12).

Thank you @mythz, @Jon

and @sroes from the stackoverflow question ServiceStack returns 405 on OPTIONS request

step 1. using code from @sroes answer, I replaced in AppHost.Configure the GlobalResponseHeaders,

      Plugins.Add(new CorsFeature());
      RequestFilters.Add((httpReq, httpRes, requestDto) =>
      {
         httpRes.AddHeader("Access-Control-Allow-Origin", "*");

        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.End();
        }
      }); 

step 2: based on @mythz proposal for a route and a method that accepts Options requests. I added in Routes, without actually to create any function for Options.

   Routes
      .Add<ReservationRequest>("/TestAPI/CreateReservation", "POST, GET, OPTIONS");

Problem solved, it works for me, ServiceStack rocks !!

thanks a lot.

Update 3 : It works also with the proposed code from @mythz.

At the beginning, the code could not compile, because it could not find the EndServiceStackRequest().

(an extension method in the namespace ServiceStack.WebHost.Endpoints.Extensions).

A reference to System.Web also required. Also the httpReq.Method is httpReq.HttpMethod.

The most important is the declaration in Routes for OPTIONS.

Fortunately, it is not necessary to add an empty method 'Options(RequestDto)`.

       using System.Web;
       using ServiceStack.WebHost.Endpoints.Extensions;
       public override void Configure(Container container)
       {             
         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.EndServiceStackRequest();
         });

         Routes
           .Add<ReservationRequest>("/TestAPI/CreateReservation", "POST, OPTIONS");
       }

Also, this question OPTIONS Verb for Routes with custom CORS headers is about the same issue.

Community
  • 1
  • 1
stefan2410
  • 1,931
  • 2
  • 16
  • 21

1 Answers1

1

See this earlier answer on applying CORS on OPTION HTTP Requests.

You can apply the CORS headers to all OPTION requests with a global filter like:

Plugins.Add(new CorsFeature()); //Registers global CORS Headers

this.RequestFilters.Add((httpReq, httpRes, requestDto) => {
   //Handles Request and closes Responses after emitting global HTTP Headers
    if (httpReq.Method == "OPTIONS") 
        httpRes.EndServiceStackRequest();
});
Community
  • 1
  • 1
mythz
  • 141,670
  • 29
  • 246
  • 390
  • thanks Demis, but I have read the question and I had tried already the code. The specific snippet, the RequestFilters is not correct and it cannot find the properties. I did corrected the code as RequestFilters.Add((httpReq, httpRes, requestDto) => { if (httpReq.HttpMethod == "OPTIONS") httpRes.End(); }); Without results. – stefan2410 Jul 05 '13 at 16:12
  • @stefan2410 have a look at all the HTTP Traffic in the web inspector and see which ones are failing. – mythz Jul 05 '13 at 16:26
  • I have tested in all browsers, (IE,Firefox,Opera) they have the same behavior, (not found 404), except Chrome who send 2 requests, => first (not found 404), second SUCCESFULL. HTTP/1.1 404 Not Found Content-Length: 3 Content-Type: text/plain Server: Microsoft-HTTPAPI/2.0 X-Powered-By: ServiceStack/3.944 Win32NT/.NET Access-Control-Allow-Origin: * Access-Control-Allow-Methods: GET, POST, PUT, DELETE, OPTIONS Access-Control-Allow-Headers: Content-Type =====> SECOND OF CHROME =>HTTP/1.1 200 OK Transfer-Encoding: chunked Content-Type: application/json; charset=utf-8 – stefan2410 Jul 05 '13 at 18:19
  • They likely return 404 NotFound because your request DTO is limited to only **GET** or **POST**, try removing the method filter from the route, e.g `[Route("/TestAPI")]` so it works for all HTTP Methods. But this is something the Global RequestFilter would've also allowed. – mythz Jul 05 '13 at 18:23
  • @stefan2410 don't post content in comments, just add them to the end of your question. – mythz Jul 05 '13 at 18:24
  • NO with [Route("/TestAPI")], Chrome, IE return no results but with HTTP/1.1 200 OK, ===> Firefox, Opera return HTTP/1.1 403 Forbidden. Hope I don't make mistake – stefan2410 Jul 05 '13 at 18:59