原文 Examining the Details and Delete methods
作者 Rick Anderson
翻譯 謝煬(Kiler)
校對 許登洋(Seay)、姚阿勇(Mr.Yao)
打開 Movie 控制器並查看 Details
方法:
// GET: Movies/Details/5
public async Task<IActionResult> Details(int? id)
{
if (id == null)
{
return NotFound();
}
var movie = await _context.Movie.SingleOrDefaultAsync(m => m.ID == id);
if (movie == null)
{
return NotFound();
}
return View(movie);
}
創建這個 action 方法的 MVC 基架引擎添加了一條注釋給出了會調用這個方法的 HTTP 請求。在這個例子中是一個有三個URL段的GET請求, Movies
控制器, Details
方法和 id
參數值。回顧一下 Startup 里定義的這些段。
app.UseMvc(routes =>
{
routes.MapRoute(
name: "default",
template: "{controller=Home}/{action=Index}/{id?}");//手工高亮
});
代碼先行(Code First)模式使用 SingleOrDefaultAsync 方法更易於數據搜索。這個方法包含的一個重要安全功能,就是在代碼嘗試用電影記錄做任何操作之前確保查找方法已經找到了一條電影記錄。例如,黑客可以把產生的鏈接 URL 從 *http://localhost:xxxx/Movies/Details/1 * 改成類似於 *http://localhost:xxxx/Movies/Details/12345 * (或者其他非實際電影記錄的值),從而給網站帶來錯誤。如果您不檢查影片是否為空,應用程序將會拋出異常。
查看 Delete 方法和 DeleteConfirmed 方法
// GET: Movies/Delete/5
public async Task<IActionResult> Delete(int? id)
{
if (id == null)
{
return NotFound();
}
var movie = await _context.Movie.SingleOrDefaultAsync(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.SingleOrDefaultAsync(m => m.ID == id);
_context.Movie.Remove(movie);
await _context.SaveChangesAsync();
return RedirectToAction("Index");
}
需要注意的是 HTTP GET Delete
方法不刪除指定的影片,它返回一個你可以提交 (HttpPost) 刪除操作的 Movie 的視圖。如果在對 GET 請求的響應中執行刪除操作(或者編輯,創建,或任何其他更改數據的操作)將會引入一個安全漏洞。
真正刪除數據的 [HttpPost]
方法被命名為 DeleteConfirmed
,給這個 HTTP POST 方法一個唯一的簽名或名稱。這兩個方法的簽名如下:
// GET: Movies/Delete/5
public async Task<IActionResult> Delete(int? id)
// POST: Movies/Delete/5
public async Task<IActionResult> DeleteConfirmed(int id)
公共語言運行時(CLR)要求重載方法有一個唯一的參數簽名(相同的方法名,但不同的參數列表)。然而,在這里你需要兩個 Delete
方法 – 一個 GET 請求一個 POST 請求 – 並且它們都具有相同的參數簽名。(它們都需要接受一個整數作為參數)。
有兩種方案可以解決該問題,其中一種方法是,賦予方法不同的名稱。這就是基架機制在前面的例子所做的事情。但是,這個方法引入了一個小問題: ASP.NET 利用名字將 URL 段映射到 action 方法,如果你重命名一個方法,路由通常將無法找到該方法。解決的辦法就是你在例子中看到的,就是為 DeleteConfirmed
方法添加 ActionName("Delete")
特性。該特性為路由系統執行映射,所以一個 POST 請求的包含 /Delete/ 的 URL 會找到 DeleteConfirmed
的方法。
對於具有相同名稱和參數簽名的方法,另一種常見的的解決辦法是通過人為的改變 POST 方法的簽名,即包含一個附加的(未使用)參數。這就是我們在前面文章中已經添加的 unused
的參數。在這里你可以對 [HttpPost] Delete
方法采用同樣的解決辦法:
// POST: Movies/Delete/5
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Delete(int id, bool notUsed)
{
var movie = await _context.Movie.SingleOrDefaultAsync(m => m.ID == id);
_context.Movie.Remove(movie);
await _context.SaveChangesAsync();
return RedirectToAction("Index");
}