Created
July 5, 2012 20:42
-
-
Save ianbattersby/3056291 to your computer and use it in GitHub Desktop.
ServiceStackReSTExample: Trying to figure out 300 Multiple Choices return
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
namespace ServiceStackReSTExample | |
{ | |
using System; | |
using System.Collections.Generic; | |
using System.ComponentModel; | |
using System.Linq; | |
using System.Net; | |
using System.Runtime.Serialization; | |
using System.Threading; | |
using ServiceStack.Common.Web; | |
using ServiceStack.Logging; | |
using ServiceStack.Logging.Support.Logging; | |
using ServiceStack.ServiceHost; | |
using ServiceStack.ServiceInterface; | |
using ServiceStack.ServiceInterface.ServiceModel; | |
using ServiceStack.WebHost.Endpoints; | |
// Warning: Contrived example ahead | |
public class Movie | |
{ | |
public string Title { get; set; } | |
public List<string> Actors { get; set; } | |
} | |
public class MovieResponse | |
{ | |
public string Id { get; set; } | |
public ResponseStatus ResponseStatus { get; set; } | |
public List<Movie> Movies { get; set; } | |
} | |
[Description("Movie web service")] | |
[RestService("/movies", "GET,OPTIONS")] | |
[DataContract] | |
public class MovieLookup | |
{ | |
} | |
public class MovieLookupService : RestServiceBase<MovieLookup> | |
{ | |
public override object OnGet(MovieLookup request) | |
{ | |
// So what I really want to do here is return a 300 Multiple Chocies with links to the other two model-based services. | |
// It seems sensible to use HttpResult opposed to hijacking IHasOptions directly, however I get caught in a loop. Possible | |
// HEAD issue? Most likely. | |
return new HttpResult(new object(), base.RequestContext.ContentType, HttpStatusCode.MultipleChoices); | |
// Obviously I would be returned an empty object here in practice, but some links to the services. | |
// As we don't have a preferred link we won't be using the LOCATION header (as per RFC2616). | |
} | |
} | |
[Description("Movie by title web service")] | |
[RestService("/movies/title/{title}", "GET,OPTIONS")] | |
[DataContract] | |
public class MovieLookupTitle | |
{ | |
[DataMember] | |
public string Title { get; set; } | |
} | |
public class MovieLookupTitleService : RestServiceBase<MovieLookupTitle> | |
{ | |
public override object OnGet(MovieLookupTitle request) | |
{ | |
return new MovieResponse() | |
{ | |
// Lookup in DB for this title.. | |
Id = Guid.NewGuid().ToString(), | |
Movies = new List<Movie> { new Movie() { Title = "Nelly packs her trunk", Actors = new List<string> { "Demis Bellot", "Ian Battersby" } } }, | |
}; | |
} | |
} | |
[Description("Movie by actor web service")] | |
[RestService("/movies/actor/{actor}", "GET,OPTIONS")] | |
[DataContract] | |
public class MovieLookupActor | |
{ | |
[DataMember] | |
public string Actor { get; set; } | |
} | |
public class MovieLookupActorService : RestServiceBase<MovieLookupActor> | |
{ | |
public override object OnGet(MovieLookupActor request) | |
{ | |
return new MovieResponse() | |
{ | |
// Lookup in DB for this actor | |
Id = Guid.NewGuid().ToString(), | |
Movies = new List<Movie> { | |
new Movie() { Title = "Nelly packs her trunk", Actors = new List<string> { "Demis Bellot", "Ian Battersby" }}, | |
new Movie() { Title = "Planes, Trains, and Strawberries", Actors = new List<string> { "Ian Battersby", "Rob Ashton" }} | |
}, | |
}; | |
} | |
} | |
public class AppListenerHost | |
: AppHostHttpListenerBase | |
{ | |
private static ILog log; | |
public AppListenerHost(string appName) | |
: base(appName, typeof(Movie).Assembly) | |
{ | |
LogManager.LogFactory = new DebugLogFactory(); | |
log = LogManager.GetLogger(typeof(AppListenerHost)); | |
} | |
public override void Configure(Funq.Container container) | |
{ | |
SetConfig(new EndpointHostConfig | |
{ | |
GlobalResponseHeaders = | |
{ | |
{ "Access-Control-Allow-Origin", "*" }, | |
{ "Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS" }, | |
}, | |
WsdlServiceNamespace = "http://www.servicestack.net/types", | |
}); | |
} | |
} | |
class Program | |
{ | |
public const string AppName = @"Ian's Movie App"; | |
public const string ListeningOn = @"http://localhost:83/"; | |
static void Main(string[] args) | |
{ | |
using (var appHost = new AppListenerHost(AppName)) | |
{ | |
appHost.Init(); | |
appHost.Start(ListeningOn); | |
Console.WriteLine("Started listening on: " + ListeningOn); | |
Console.WriteLine("AppHost Created at {0}, listening on {1}", DateTime.Now, ListeningOn); | |
Thread.Sleep(System.Threading.Timeout.Infinite); | |
} | |
System.Console.WriteLine("ReadLine()"); | |
System.Console.ReadLine(); | |
} | |
} | |
} |
Realise the above example is XML based, HEADER-version most likely something like;
Link: </movie/title>; rel="http://localhost:83/rels/movie/title"
Link: </movie/actor>; rel="http://localhost:83/rels/movie/actor"
In which case you can just return a custom contentType, headers and body, e.g:
new HttpResult {
ContentType = "application/xml",
Headers = {
{"Link","</movie/title>; rel=\"http://localhost:83/rels/movie/title\""},
{"Link","</movie/actor>; rel=\"http://localhost:83/rels/movie/actor\""},
},
ResponseText = "<link rel=...", //If you also want to return it in the body.
};
Thanks Demis, been tied up but will follow this up tomorrow.
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
OK, think I did get the 300 thing wrong - but would be good to know how to do.
http://martinfowler.com/articles/richardsonMaturityModel.html#level3