Returnera rätt, returnera enhetligt (ASP.NET WebApi serie 4/4)

I den här den sista delen i mini-serien om ASP.NET WebApi tittar vi in i själva metoderna i api:ets controllers och hur värden returneras från dessa metoder.

Beroende på version av .NET-ramverket så finns det olika sätt att returnera från actions:

  • CLR-typer/PoCos
  • IHttpActionResult (fulla .NET-ramverket) eller IActionResult (.NET Core)
  • HttpResponseMessage (fulla .NET-ramverket)

Vilket sätt man väljer kan ju såklart bero på domänen i vilken api:et ska verka, men i huvudsak kan man uppnå samma resultat med alla olika varianter. Det viktiga är att man är konsekvent inom ett och samma api/projekt, främst för att underlätta felsökning och öka kodkvaliteten.

Exempel på varje variant följer.

CLR-typer/PoCos

Det här sättet att returnera är det man blir serverad om man väljer att låta Visual Studio skapa en exempel-controller via File - New Project/Solution och någon ASP.Net MVC/WebApi-mall.

Ett exempel på detta kan se ut enligt

public class ValuesController : ApiController  
{
    // GET api/values
    public IEnumerable<string> Get()
    {
        return new string[] { "value1", "value2" };
    }

    // GET api/values/5
    public string Get(int id)
    {
        return "value";
    }

    // POST api/values
    public void Post([FromBody]string value)
    {
    }

    // PUT api/values/5
    public void Put(int id, [FromBody]string value)
    {
    }

    // DELETE api/values/5
    public void Delete(int id)
    {
    }
}

Status-koderna (HttpStatus) härleds implicit, där retur av något typat värde ger 2xy (oftast 200), medan return void ger 204 NoContent. Koden ovan är direkt kopierade fråmn Visual Studio-mallen.

Det här sättet ger alltså inte utvecklare direkt kontroll över statuskoderna.

Samma sak gäller för ASP.NET Core-mallen i Visual Studio. Den genererade koden ser ungefär likadan ut.

IHttpActionResult/IActionResult

Om man skulle konvertera ovanstående exempel till att returnera IHttpActionResult för det fulla .NET-ramverket och IActionResult för .NET Core skulle det se ut enligt nedan, fulla .NET-ramverket först:

public class ValuesController : ApiController  
{
    // GET api/values
    public IHttpActionResult Get()
    {
        return Ok(new string[] { "value1", "value2" });
    }

    // GET api/values/5
    public IHttpActionResult Get(int id)
    {
        return Ok("value");
    }

    // POST api/values
    public IHttpActionResult Post([FromBody]string value)
    {
        return StatusCode(HttpStatusCode.NoContent);
    }

    // PUT api/values/5
    public IHttpActionResult Put(int id, [FromBody]string value)
    {
        return StatusCode(HttpStatusCode.NoContent);
    }

    // DELETE api/values/5
    public IHttpActionResult Delete(int id)
    {
        return StatusCode(HttpStatusCode.NoContent);
    }
}

Notera return StatusCode(...) då NoContent inte finns som hjälp-funktion i fulla .NET-ramverket, att jämföra med .NET Core nedan.

Motsvarande klass för .NET Core:

[Route("api/[controller]")]
public class ValuesController : Controller  
{
    // GET api/values
    [HttpGet]
    public IActionResult Get()
    {
        return Ok(new string[] { "value1", "value2" });
    }

    // GET api/values/5
    [HttpGet("{id}")]
    public IActionResult Get(int id)
    {
        return Ok("value");
    }

    // POST api/values
    [HttpPost]
    public IActionResult Post([FromBody]string value)
    {
        return NoContent();
    }

    // PUT api/values/5
    [HttpPut("{id}")]
    public IActionResult Put(int id, [FromBody]string value)
    {
        return NoContent();
    }

    // DELETE api/values/5
    [HttpDelete("{id}")]
    public IActionResult Delete(int id)
    {
        return NoContent();
    }
}

Värt att notera här är att man har ensat basklassen för MVC- och WebApi-controllers, båda ärver från samma basklass. Basklassen ligger dessutom i Mvc-namespace, till skillnad från ApiController som ligger i System.Web.Http.

Min personliga uppfattning är att det här sättet att returnera är att föredra då det ger total kontroll över http-statusen som api-konsumenten ställs inför.

HttpResponseMessage

Att returnera HttpResponseMessage är numera förlegat och används nästan aldrig längre. Det finns inte heller tillgängligt på något enkelt sätt i .NET Core.

Summering/rekommendation

Om man bygger något nytt, från grunden, så har man såklart fria tyglar och kan välja vilket sätt man vill. Det viktiga, för att få en enkel och tydlig kodbas att förvalta framgent, är att man håller sig till ett och samma sätt genom hela kodbasen. Det är inget problem att under utvecklingsarbetet byta, då ingreppet är tämligen litet. Personligen gillar jag IHttpActionResult/IActionResult-varianten bäst eftersom den ger kontroll över den faktiska status-koden ut från dina actions i ditt api.

Tillbaka till introduktionen.