ServiceStack REST API and CORS
Asked Answered
C

2

47

Does anyone know if the ServiceStack framework can be used to create CORS REST services?

I've been banging my head against the WCF REST stuff for days now - utterly useless.

Constrain answered 21/11, 2011 at 12:39 Comment(3)
i have tried using the wcf rest starter kit and dhvik.blogspot.com/2011/06/… (both the attribute and the very first un-ideal code example given) and i keep getting: Origin xxxxx.com is not allowed by Access-Control-Allow-Origin.Constrain
#7235099Gerkman
i think the chrome network console is erroneously reporting a cancelled request - fiddler doesn't show the same result - it says it completed ok...Constrain
A
88

Using the CorsFeature plugin

Enabling Global CORS support

We now have a CorsFeature which wraps CORS headers into the Plugin below to make it much easier to add CORS support to your ServiceStack services.

Commonly this is now all that's needed:

Plugins.Add(new CorsFeature());

Which uses the default values:

CorsFeature(allowedOrigins:"*", 
    allowedMethods:"GET, POST, PUT, DELETE, OPTIONS", 
    allowedHeaders:"Content-Type", 
    allowCredentials:false);

You can leave out any of the values matching the default. E.g. if you just wanted to restrict the allowed methods to just GET and POST requests, you can just do:

Plugins.Add(CorsFeature(allowedMethods:"GET, POST"));

Globally enable CORS for all OPTION requests

Once the CorsFeature (or manual Global Headers) is registered, you can optionally choose to enable CORS for all OPTION requests by adding a PreRequest filter to emit all registered Global Headers (i.e. the Headers in CorsFeature) and short-circuit all OPTIONS requests with:

this.PreRequestFilters.Add((httpReq, httpRes) => {
    //Handles Request and closes Responses after emitting global HTTP Headers
    if (httpReq.Method == "OPTIONS") 
        httpRes.EndRequest(); //add a 'using ServiceStack;'
});

Enabling CORS per-service support

Instead of using the plugin above, ServiceStack also allows you to enable CORS on a per-service basis by using [EnableCors] Response Filter attribute which has the same defaults as above. E.g. You can enable just GET, POST as above with:

[EnableCors(allowedMethods:"GET,POST")]
public class MyService : Service { ... }

Manually enabling CORS

The beauty of ServiceStack is that it's built on a highly flexible and simple core. We don't try to build strong-typed APIs over everything, as it's impossible to predict what new HTTP Headers / StatusCodes will exist in the future. So whilst we provide convenient behavior to accomplish common tasks, we also provide a flexible API that lets you configure any desired HTTP Output.

Setting Global HTTP Headers

This is how to globally enable Cross Origin Sharing in you AppHost config:

public override void Configure(Container container)
{
    //Permit modern browsers (e.g. Firefox) to allow sending of any REST HTTP Method
    base.SetConfig(new EndpointHostConfig
    {
        GlobalResponseHeaders = {
            { "Access-Control-Allow-Origin", "*" },
            { "Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS" },
            { "Access-Control-Allow-Headers", "Content-Type" },
        },
    });
}

Returning Custom HTTP Headers in a service

These headers will get sent on every request, alternatively you can also enable it for specific web services, i.e. take the Hello World Web Service for example:

public class Hello {
    public string Name { get; set; }
}

public class HelloResponse {
    public string Result { get; set; }
}

public class HelloService : IService 
{
    public object Any(Hello request)
    {
        var dto = new HelloResponse { Result = "Hello, " + request.Name };
        return new HttpResult(dto) {
            Headers = {
              { "Access-Control-Allow-Origin", "*" },
              { "Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS" } 
              { "Access-Control-Allow-Headers", "Content-Type" }, }
        };
    }
}

The above is all the C# code you need to develop a web service which is then automatically wired up for you on all HTTP Verbs (GET, POST, etc) and built-in endpoints, i.e. JSON, XML, JSV, HTML, CSV, SOAP 1.1/1.2 - for free, without any config or friction required. Checkout the live example of the above web service.

In addition to the above endpoints each service is available to be called by JSONP (another popular way to enable cross-domain service calls in Ajax apps) where each service can be called via JSONP by simply adding the ?callback=cb parameter to the querystring, e.g:

http://www.servicestack.net/ServiceStack.Hello/servicestack/hello/world?callback=cb

This is another example of the flexibility and productivity wins of using ServiceStack where you're literally given friction-free flexibility and expressive freedom in your web service to literally return just about anything and it gets serialized as expected.

It's not only easier to use than WCF (with more features out-of-the-box) but it's also much faster where all its components are highly optimized for maximum performance.

Akbar answered 21/11, 2011 at 12:39 Comment(7)
Could you explain the pipeline for an OPTIONS request? Any guesses why the headers might not be returned, and why a 404 is returned whenever I implement a request filter?Roadhouse
Can you ask a new question, explain your issue and provide the impl of the Request Filter and the before/after effect it has. Provide as much relevant code as needed to repro, thx.Akbar
Perhaps I'm doing something wrong but [EnableCors(allowedMethods:"GET,POST")] on the service type doesn't seem to work. If I move it and put it on the Get() and Options() methods then it does work.Seaman
@Akbar I've added the PreRequestFilters to my AppHost.cs as you've shown, but my POST requests are still not getting the headers they need. They're set up like this: gist.github.com/JaKXz/8fd6ec1dda2f1b6aef0a --I've got a GET request in the same file set up the same way which works fine. Please let me know if I can provide more info.External
Is there an easy way to allow for any header for allowedHeaders without listing each one individually?Karim
@Karim The CorsFeature registers them all by default as shown in the defaults above.Akbar
@Akbar I have to explicitly list out each header otherwise I get an error.Karim
A
7

Just FYI, as I had a hard time figuring out where the CORS plugin lived. Maybe I'm just thick.

It's in ServiceStack.ServiceInterface.Cors.

Autotype answered 12/12, 2012 at 0:0 Comment(1)
That's why i love resharper :)Marcin

© 2022 - 2024 — McMap. All rights reserved.