This post was originally published on Coding Glamour.

In Ruby on Rails is het mogelijk om met respond_to een actie beschikbaar te maken in andere formaten dan HTML met één regel. Pretty neat, omdat je je code zo zonder moeite via verschillende interfaces kan gebruiken.

respond_to do |format|
  format.html
  format.xml  { render :xml => @huis }
  format.json { render :json => @huis }
end

In ASP.NET MVC 2 is er niet standaard zo'n oplossing, maar doordat MVC zo pluggable is is deze wel eenvoudig toe te voegen. Models en Views
Hierbij introduceer ik jullie tot de nieuwe site 'fudna'. Ze tonen huizen en hebben hiervoor de volgende MVC structuur.
http://www.100procentjan.nl/tweakers/fudnamvc.png
De actie 'Index' op de 'HuisController' ziet er zo uit:

public ActionResult Index(int id)
{
    var model = FudnaDao.GetHuis(id);
    return View(model);
}

Wat resulteert in de weergave van dit vernieuwende concept:
http://www.100procentjan.nl/tweakers/fudnaview.png

En nu andere formaten
Allereerst breiden we de standaard routing uit in Global.asax. Naast de 'standaard' regel voegen we een rule toe die extensies accepteert.

public static void RegisterRoutes(RouteCollection routes)
{
    routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
    // dit is nieuw
    routes.MapRoute(
        "DefaultWithExtension",
        "{controller}/{action}/{id}.{format}",
        new { controller = "Home", action = "Index" } // Parameter defaults
    );
    // dit niet meer
    routes.MapRoute(
        "Default",
        "{controller}/{action}/{id}",
        new { controller = "Home", action = "Index", id = UrlParameter.Optional } // Parameter defaults
    );
}

Om aan te geven welke formaten we ondersteunen maken we gebruik van ActionFilterAttributes. Mooi hieraan is dat we het resultaat van elke actie kunnen overschrijven in deze filters. Het RespondTo filter zou er ongeveer zo uit zien:

public class RespondTo : ActionFilterAttribute 
{
    private Format[] _formats;
    public RespondTo(params Format[] formats)
    {
        _formats = formats;
    }
    public override void OnActionExecuted(ActionExecutedContext filterContext)
    {
        // zoek het model op
        var model = ((ViewResult) filterContext.Result).ViewData.Model;
        // hebben we een format parameter?
        object format;
        filterContext.RouteData.Values.TryGetValue("format",  out format);
        // zoja, dan kijk naar de waarde
        switch(format as string)
        {
            // als json niet ondersteunt; dan return
            case "json":
                if (!_formats.Any(f => f == Format.Json)) return;
                // transformeer het model naar Json
                // en overschrijf het oude Result
                filterContext.Result = new JsonResult { Data = model, JsonRequestBehavior = JsonRequestBehavior.AllowGet };
                break;
            case "xml":
                if (!_formats.Any(f => f == Format.Xml)) return;
                // same same voor XML. Maar dat is lastiger in een one-liner
                using(MemoryStream ms = new MemoryStream()) // simpele serialization
                    using(TextWriter tw = new StreamWriter(ms))
                    {
                        new XmlSerializer(model.GetType()).Serialize(tw, model);
                        ms.Seek(0, SeekOrigin.Begin);
                        // hier zetten we de nieuwe content naar de XML
                        filterContext.Result = new ContentResult { ContentType = "text/xml", Content = new StreamReader(ms).ReadToEnd() };
                    }
                break;
        }
    }
}
public enum Format
{
    Xml,
    Json
}


Actie aanpassen
Aan de bestaande actie hoeven we nu niets meer aan te passen. We zetten er enkel een nieuw attribuut op:

[RespondTo(Format.Xml, Format.Json)]
public ActionResult Index(int id)
{
    var model = FudnaDao.GetHuis(id);
    return View(model);
}


Resultaat
En dat was het al. Wanneer we nu '.xml' of '.json' toevoegen aan de URL krijgen we de data in dat formaat binnen!
http://www.100procentjan.nl/tweakers/fudnaxml.png

http://www.100procentjan.nl/tweakers/fudnajson.png