Examinando los métodos Details y Delete de una aplicación ASP.NET Core MVC

Abramos el controlador Movies y examinemos el método Detail:

// GET: Movies/Details/5
public async Task<IActionResult> Details(int? id)
{
    if (id == null)
    {
        return NotFound();
    }

    var movie = await _context.Movie
        .FirstOrDefaultAsync(m => m.ID == id);
    if (movie == null)
    {
        return NotFound();
    }

    return View(movie);
}

El motor de scaffolding de MVC que creó este método de acción agrega un comentario mostrando la petición HTTP que invoca al método. En este caso es una petición GET con tres segmentos de URL, el controlador Movies , el método Detailsy un valor id. Recordemos que esos segmentos están definidos en el archivo Startup.cs.

app.UseMvc(routes =>
{
    routes.MapRoute(
        name: "default",
        template: "{controller=Home}/{action=Index}/{id?}");
});

EF hace que sea facil buscar datos utiliznado el método SingleOrDefaultAsync. Una característica de seguridad importante que tiene el método es que verifica que el código de búsuqeda haya encontrado una película antes de hacer algo con ella. Por ejemplo, un hacker podría introducir errores en el sitio cambiando la URL creada por los links de http://localhost:xxxx/Movies/Details/1 a algo como http://localhost:xxxx/Movies/Details/12345 ( o algún otro valor que no representa ninguna película). Si no verificamos que la película sea null, la aplicación podría dar un error.

Examinemos los métodos Delete y DeleteConfirmed.

// GET: Movies/Delete/5
public async Task<IActionResult> Delete(int? id)
{
    if (id == null)
    {
        return NotFound();
    }

    var movie = await _context.Movie
        .FirstOrDefaultAsync(m => m.ID == id);
    if (movie == null)
    {
        return NotFound();
    }

    return View(movie);
}

// POST: Movies/Delete/5
[HttpPost, ActionName("Delete")]
[ValidateAntiForgeryToken]
public async Task<IActionResult> DeleteConfirmed(int id)
{
    var movie = await _context.Movie.FindAsync(id);
    _context.Movie.Remove(movie);
    await _context.SaveChangesAsync();
    return RedirectToAction(nameof(Index));
}

Notemos que el método GET HTTP Delete no borra la película especificada sino que retorna una vista de la película que se puede enviar como un HTTP Post para que se elimine. Haciendo una operación de borrado como respuesta a una solicitud GET (o cualquier operación de creación, edición o que produzca algun cambio en los datos) abre un agujero de seguridad.

El método [HttpPost] que borra datos se llama DleteConfirmed para darle al método HTTP POST una firma única. Las dos firmas del método se muestran a continuación:

// GET: Movies/Delete/5
public async Task<IActionResult> Delete(int? id)
{
// POST: Movies/Delete/5
[HttpPost, ActionName("Delete")]
[ValidateAntiForgeryToken]
public async Task<IActionResult> DeleteConfirmed(int id)
{

La common language runtime (CLR) requiere que los métodos sobrecargados tengan una firma de paramétros diferente (el mismo nombre del método pero una diferente lista de parámetros).

Sin embargo, aquí tenemos dos métodos Delete (uno para el GET y otro para el POST) y ambos tienen la misma firma de parámetros (los dos aceptan un solo entero como parámetro).

Hay dos formas de solucionar este problema, una es darle a los métodos nombres diferentes. Eso es lo que el mecanismo de scaffolding hizo en el example que nos precede. Sin embargo, esto nos da un pequeño problema, ASP.NET mapea los segmentos de una URL al nombre de los métodos de acción, si cambiamos el nombre del método, el enrutado no lo va a poder encontrar. La solución la vemos en el ejemplo, que es agregar el atributo ActionName("Delete") al método DeleteConfirmed. Este atributo hace el mapeo del sistema de enrutado para que la URL /DELETE/ de una solicitud POST encuentre el método DeleteConfirmed.

Otra solución común para métodos que tienen el mismo nombre y firmas es cambiar artificialmente la firma de un método POST para incluir un parámetro extra (que no se use). Eso es lo que hicimos cuando agregamos el parámetro notUsed. Si quisieramos podríamos hacer lo mismo en el método [HttpPost] Delete:

// POST: Movies/Delete/6
[ValidateAntiForgeryToken]
public async Task<IActionResult> Delete(int id, bool notUsed)

En la ultima parte del tutorial vamos a ver como podemos poner nuestra app web internet, publicandola a Azure.