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
Details
y 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.