Created
March 1, 2012 18:46
-
-
Save codeprogression/1952063 to your computer and use it in GitHub Desktop.
A NancyFx IResponseFormatter extension to do content-negotiation
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
using System; | |
using System.Linq; | |
using Nancy.ViewEngines; | |
namespace Nancy | |
{ | |
public static class CustomFormatterExtensions | |
{ | |
public static Response AsNegotiated<TModel>(this IResponseFormatter formatter, TModel model, HttpStatusCode statusCode = HttpStatusCode.OK, Tuple<Func<Response>, string> defaultResponse = null) | |
{ | |
if (defaultResponse == null) | |
defaultResponse = new Tuple<Func<Response>, string>(() => new Response | |
{ | |
ContentType = null, | |
StatusCode = HttpStatusCode.UnsupportedMediaType | |
}, null); | |
var defaultResponseDelegate = defaultResponse.Item1; | |
var defaultContentType = defaultResponse.Item2; | |
if (formatter.Context.Request == null || formatter.Context.Request.Headers == null || formatter.Context.Request.Headers.Accept == null) | |
return defaultResponseDelegate.Invoke(); | |
var accept = formatter.Context.Request.Headers.Accept; | |
var weightedContentTypes = accept.Select(x => x.Item1).DefaultIfEmpty(); | |
foreach (var contentType in weightedContentTypes) | |
{ | |
if (defaultContentType == contentType || contentType == "*/*") return defaultResponseDelegate.Invoke(); | |
var serializer = formatter.Serializers.FirstOrDefault(x => x.CanSerialize(contentType)); | |
if (serializer != null && !(contentType.EndsWith("xml") && model.IsAnonymousType())) | |
{ | |
return new Response | |
{ | |
Contents = stream => serializer.Serialize(contentType, model, stream), | |
ContentType = contentType, | |
StatusCode = statusCode | |
}; | |
} | |
} | |
return defaultResponseDelegate.Invoke(); | |
} | |
} | |
} | |
/* Usage: | |
public AsNegotiatedTestModule() : base("/negotiated") | |
{ | |
Get["/view"] = p => | |
{ | |
var model = new Person("John", "Doe"); | |
return Response.AsNegotiated(model, defaultResponse: new Tuple<Func<Response>, string>(()=>View[model],"text/html")); | |
}; | |
} | |
Request to '/negotiated/view' with this header returns the View (html): | |
Accept: text/html,application/json;q=0.9,application/xml;q=0.8 | |
Request to '/negotiated/view' with this header returns JSON: | |
Accept: text/html;q=0.7,application/json;q=0.9,application/xml;q=0.8 | |
*/ |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment