Skip to content

Instantly share code, notes, and snippets.

@codeprogression
Created March 1, 2012 18:46
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save codeprogression/1952063 to your computer and use it in GitHub Desktop.
Save codeprogression/1952063 to your computer and use it in GitHub Desktop.
A NancyFx IResponseFormatter extension to do content-negotiation
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