Home - About me - Browse by categories

[ASPNET Web API] Forcer le content type pour une action donnée

Avec ASP.NET Web API, la content négociation se fait à l’aide du header Accept de la requête HTTP. Lorsque le type demandé n’est pas pris en charge, la requête est alors traitée avec le formateur par défaut, en l’occurrence le formateur JSON.

Cependant, dans certains cas il est nécessaire de forcer  le format de retour de la requête. Par exemple pour retourner un flux RSS.

Considérons le code suivant :

public class RssController : ApiController
{
private readonly IBlogService _blogService;
public RssController()
{
var dbContext = new MetroBlogDbContext();
_blogService = new BlogService(dbContext);
}

public IEnumerable<Post> Get()
{
return _blogService.GetLatestPosts(true, 0, 20).ToList();
}
}

Il s’agit d’un simple contrôleur Web API qui retourne une liste d’objet Post (la définition n’a pas d’importance ici). Pour être capable de retourner un format de flux RSS, j’ai écrit un custom formatter pour RSS/Atom (cf. http://www.strathweb.com/2012/04/rss-atom-mediatypeformatter-for-asp-net-webapi/).

Une fois le formateur développé, il suffit de l’enregistrer au démarrage de l’application :

GlobalConfiguration.Configuration.Formatters.Add(new SyndicationFeedFormatter());

Cette solution permet de faire en sorte que lorsque le header Accept de la requête HTTP est à <em>application/rss+xml</em> ou <em>application/atom+xml</em>, le formateur SyndicationFeedFormatter soit utilisé et donc que le format en sortie soit un flux RSS. Ce n’est cependant pas suffisant pour que l’action Get renvoie toujours un flux RSS!

Pour le forcer, il est nécessaire de modifier le code de l’action Get et de créer nous même l’HttpResponseMessage qui sera renvoyé :

public HttpResponseMessage Get()
{
try
{
var posts = _blogService.GetLatestPosts(true, 0, 20).ToList();
var responseMessage = new HttpResponseMessage(HttpStatusCode.OK);
responseMessage.Content = new ObjectContent(typeof(IEnumerable<Post>), posts, new SyndicationFeedFormatter());
responseMessage.Content.Headers.ContentType = new System.Net.Http.Headers.MediaTypeHeaderValue("application/rss+xml");
return responseMessage;
}
catch(Exception ex)
{
throw new HttpResponseException(HttpStatusCode.InternalServerError);
}
}

A partir de là, quelque soit le header Accept qui est envoyé, le format retourné sera <em>application/rss+xml</em>.

Il est également possible de filtrer certains type en se basant sur le header Accept de la requête afin de forcer le format que dans certains cas :

public HttpResponseMessage Get()
{
try
{
var posts = _blogService.GetLatestPosts(true, 0, 20).ToList();
var responseMessage = new HttpResponseMessage(HttpStatusCode.OK);

if (Request.Headers.Accept.Any(a => a.MediaType == "application/json"))
{
responseMessage.Content = new ObjectContent(typeof(IEnumerable<Post>), posts, new JsonMediaTypeFormatter());
responseMessage.Content.Headers.ContentType = new System.Net.Http.Headers.MediaTypeHeaderValue("application/json");
}
else
{
responseMessage.Content = new ObjectContent(typeof(IEnumerable<Post>), posts, new SyndicationFeedFormatter());
responseMessage.Content.Headers.ContentType = new System.Net.Http.Headers.MediaTypeHeaderValue("application/rss+xml");
}

return responseMessage;
}
catch(Exception ex)
{
throw new HttpResponseException(HttpStatusCode.InternalServerError);
}
}

Dans le cas présent, si le header Accept de la requête contient le media type <em>application/json</em>, on renvoie un retour en JSON, sinon on renvoie le flux RSS formaté.

A bientôt !


Any question about this post? Feel free to drop a comment below or contact me on Twitter @jcorioland