"
 
 
 
ASP.NET (snapshot 2017) Microsoft documentation and samples

Examining the Details and Delete methods

By Rick Anderson

Open the Movie controller and examine the Details method:

[!code-csharpMain]

   1:  //#define snippet_1stSearch
   2:  //#define snippet_SearchID
   3:  #define snippet_SearchGenre
   4:   
   5:   
   6:  using Microsoft.AspNetCore.Mvc;
   7:  using Microsoft.AspNetCore.Mvc.Rendering;
   8:  using Microsoft.EntityFrameworkCore;
   9:  using MvcMovie.Models;
  10:  using System;
  11:  using System.Linq;
  12:  using System.Threading.Tasks;
  13:   
  14:  namespace MvcMovie.Controllers
  15:  {
  16:      public class MoviesController : Controller
  17:      {
  18:          private readonly MvcMovieContext _context;
  19:   
  20:          public MoviesController(MvcMovieContext context)
  21:          {
  22:              _context = context;
  23:          }
  24:   
  25:          #region snippet_details
  26:          // GET: Movies/Details/5
  27:          public async Task<IActionResult> Details(int? id)
  28:          {
  29:              if (id == null)
  30:              {
  31:                  return NotFound();
  32:              }
  33:   
  34:              var movie = await _context.Movie
  35:                  .SingleOrDefaultAsync(m => m.ID == id);
  36:              if (movie == null)
  37:              {
  38:                  return NotFound();
  39:              }
  40:   
  41:              return View(movie);
  42:          }
  43:          #endregion
  44:          #region snippetCreate
  45:          // GET: Movies/Create
  46:          public IActionResult Create()
  47:          {
  48:              return View();
  49:          }
  50:   
  51:          // POST: Movies/Create
  52:          [HttpPost]
  53:          [ValidateAntiForgeryToken]
  54:          public async Task<IActionResult> Create(
  55:              [Bind("ID,Title,ReleaseDate,Genre,Price, Rating")] Movie movie)
  56:          {
  57:              if (ModelState.IsValid)
  58:              {
  59:                  _context.Add(movie);
  60:                  await _context.SaveChangesAsync();
  61:                  return RedirectToAction("Index");
  62:              }
  63:              return View(movie);
  64:          }
  65:          #endregion
  66:   
  67:          // GET: Movies/Edit/5
  68:          public async Task<IActionResult> Edit(int? id)
  69:          {
  70:              if (id == null)
  71:              {
  72:                  return NotFound();
  73:              }
  74:   
  75:              var movie = await _context.Movie.SingleOrDefaultAsync(m => m.ID == id);
  76:              if (movie == null)
  77:              {
  78:                  return NotFound();
  79:              }
  80:              return View(movie);
  81:          }
  82:   
  83:          // POST: Movies/Edit/5
  84:          // To protect from overposting attacks, please enable the specific properties you want to bind to, for 
  85:          // more details see http://go.microsoft.com/fwlink/?LinkId=317598.
  86:          [HttpPost]
  87:          [ValidateAntiForgeryToken]
  88:          public async Task<IActionResult> Edit(int id, [Bind("ID,Title,ReleaseDate,Genre,Price,Rating")] Movie movie)
  89:          {
  90:              if (id != movie.ID)
  91:              {
  92:                  return NotFound();
  93:              }
  94:   
  95:              if (ModelState.IsValid)
  96:              {
  97:                  try
  98:                  {
  99:                      _context.Update(movie);
 100:                      await _context.SaveChangesAsync();
 101:                  }
 102:                  catch (DbUpdateConcurrencyException)
 103:                  {
 104:                      if (!MovieExists(movie.ID))
 105:                      {
 106:                          return NotFound();
 107:                      }
 108:                      else
 109:                      {
 110:                          throw;
 111:                      }
 112:                  }
 113:                  return RedirectToAction("Index");
 114:              }
 115:              return View(movie);
 116:          }
 117:   
 118:          #region snippet_delete
 119:          #region snippet_delete2
 120:          // GET: Movies/Delete/5
 121:          public async Task<IActionResult> Delete(int? id)
 122:          {
 123:              #endregion
 124:              if (id == null)
 125:              {
 126:                  return NotFound();
 127:              }
 128:   
 129:              var movie = await _context.Movie
 130:                  .SingleOrDefaultAsync(m => m.ID == id);
 131:              if (movie == null)
 132:              {
 133:                  return NotFound();
 134:              }
 135:   
 136:              return View(movie);
 137:          }
 138:   
 139:          #region snippet_delete3
 140:          // POST: Movies/Delete/5
 141:          [HttpPost, ActionName("Delete")]
 142:          [ValidateAntiForgeryToken]
 143:          public async Task<IActionResult> DeleteConfirmed(int id)
 144:          {
 145:              #endregion
 146:              var movie = await _context.Movie.SingleOrDefaultAsync(m => m.ID == id);
 147:              _context.Movie.Remove(movie);
 148:              await _context.SaveChangesAsync();
 149:              return RedirectToAction("Index");
 150:          }
 151:          #endregion
 152:   
 153:          private bool MovieExists(int id)
 154:          {
 155:              return _context.Movie.Any(e => e.ID == id);
 156:          }
 157:  #if snippet_1stSearch
 158:          // First Search
 159:          #region snippet_1stSearch
 160:          public async Task<IActionResult> Index(string searchString)
 161:          {
 162:              var movies = from m in _context.Movie
 163:                           select m;
 164:   
 165:              if (!String.IsNullOrEmpty(searchString))
 166:              {
 167:                  movies = movies.Where(s => s.Title.Contains(searchString));
 168:              }
 169:   
 170:              return View(await movies.ToListAsync());
 171:          }
 172:          #endregion
 173:          // End first Search
 174:  #endif
 175:   
 176:  #if snippet_SearchID
 177:          // Search ID 
 178:          #region snippet_SearchID
 179:          public async Task<IActionResult> Index(string id)
 180:          {
 181:              var movies = from m in _context.Movie
 182:                           select m;
 183:   
 184:          #region snippet_SearchNull
 185:              if (!String.IsNullOrEmpty(id))
 186:              {
 187:                  movies = movies.Where(s => s.Title.Contains(id));
 188:              }
 189:          #endregion
 190:   
 191:              return View(await movies.ToListAsync());
 192:          }
 193:          #endregion
 194:          // End search ID
 195:  #endif
 196:   
 197:  #if SearchPost
 198:          // Search Post
 199:          #region snippet_SearchPost
 200:          [HttpPost]
 201:          public string Index(string searchString, bool notUsed)
 202:          {
 203:              return "From [HttpPost]Index: filter on " + searchString;
 204:          }
 205:          #endregion
 206:          // End SP
 207:  #endif
 208:   
 209:  #if snippet_SearchGenre
 210:          // Search by genre.
 211:          #region snippet_SearchGenre
 212:          // Requires using Microsoft.AspNetCore.Mvc.Rendering;
 213:          public async Task<IActionResult> Index(string movieGenre, string searchString)
 214:          {
 215:              #region snippet_LINQ
 216:              // Use LINQ to get list of genres.
 217:              IQueryable<string> genreQuery = from m in _context.Movie
 218:                                              orderby m.Genre
 219:                                              select m.Genre;
 220:              #endregion
 221:   
 222:              var movies = from m in _context.Movie
 223:                           select m;
 224:   
 225:              #region snippet_SearchNull2
 226:              if (!String.IsNullOrEmpty(searchString))
 227:              {
 228:                  movies = movies.Where(s => s.Title.Contains(searchString));
 229:              }
 230:              #endregion
 231:   
 232:              if (!String.IsNullOrEmpty(movieGenre))
 233:              {
 234:                  movies = movies.Where(x => x.Genre == movieGenre);
 235:              }
 236:   
 237:              var movieGenreVM = new MovieGenreViewModel();
 238:              movieGenreVM.genres = new SelectList(await genreQuery.Distinct().ToListAsync());
 239:              movieGenreVM.movies = await movies.ToListAsync();
 240:   
 241:              return View(movieGenreVM);
 242:          }
 243:          #endregion
 244:  #endif
 245:      }
 246:  }

The MVC scaffolding engine that created this action method adds a comment showing an HTTP request that invokes the method. In this case it???s a GET request with three URL segments, the Movies controller, the Details method and an id value. Recall these segments are defined in Startup.cs.

[!code-csharpMain]

   1:  #if V1x
   2:  using System;
   3:  using System.Collections.Generic;
   4:  using System.Linq;
   5:  using System.Threading.Tasks;
   6:  using Microsoft.AspNetCore.Builder;
   7:  using Microsoft.AspNetCore.Hosting;
   8:  using Microsoft.Extensions.Configuration;
   9:  using Microsoft.Extensions.DependencyInjection;
  10:  using Microsoft.Extensions.Logging;
  11:  using Microsoft.EntityFrameworkCore;
  12:  using MvcMovie.Models;
  13:   
  14:  namespace MvcMovie
  15:  {
  16:      public class Startup
  17:      {
  18:          public Startup(IHostingEnvironment env)
  19:          {
  20:              var builder = new ConfigurationBuilder()
  21:                  .SetBasePath(env.ContentRootPath)
  22:                  .AddJsonFile("appsettings.json", optional: false, reloadOnChange: true)
  23:                  .AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true)
  24:                  .AddEnvironmentVariables();
  25:              Configuration = builder.Build();
  26:          }
  27:   
  28:          public IConfigurationRoot Configuration { get; }
  29:   
  30:          // This method gets called by the runtime. Use this method to add services to the container.
  31:          #region ConfigureServices
  32:          public void ConfigureServices(IServiceCollection services)
  33:          {
  34:              // Add framework services.
  35:              services.AddMvc();
  36:   
  37:              services.AddDbContext<MvcMovieContext>(options =>
  38:                      options.UseSqlServer(Configuration.GetConnectionString("MvcMovieContext")));
  39:          }
  40:          #endregion
  41:   
  42:   
  43:          // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
  44:          public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
  45:          {
  46:              loggerFactory.AddConsole(Configuration.GetSection("Logging"));
  47:              loggerFactory.AddDebug();
  48:   
  49:              if (env.IsDevelopment())
  50:              {
  51:                  app.UseDeveloperExceptionPage();
  52:   
  53:                  // Browser Link is not compatible with Kestrel 1.1.0
  54:                  // For details on enabling Browser Link, see https://go.microsoft.com/fwlink/?linkid=840936
  55:                  // app.UseBrowserLink();
  56:              }
  57:              else
  58:              {
  59:                  app.UseExceptionHandler("/Home/Error");
  60:              }
  61:   
  62:              #region snippet_seed
  63:              app.UseStaticFiles();
  64:              #region snippet_1
  65:              app.UseMvc(routes =>
  66:              {
  67:                  routes.MapRoute(
  68:                      name: "default",
  69:                      template: "{controller=Home}/{action=Index}/{id?}");
  70:              });
  71:              #endregion
  72:   
  73:              SeedData.Initialize(app.ApplicationServices);
  74:          }
  75:      }
  76:  }
  77:  #endregion
  78:  #endif

EF makes it easy to search for data using the SingleOrDefaultAsync method. An important security feature built into the method is that the code verifies that the search method has found a movie before it tries to do anything with it. For example, a hacker could introduce errors into the site by changing the URL created by the links from http://localhost:xxxx/Movies/Details/1 to something like http://localhost:xxxx/Movies/Details/12345 (or some other value that doesn???t represent an actual movie). If you did not check for a null movie, the app would throw an exception.

Examine the Delete and DeleteConfirmed methods.

[!code-csharpMain]

   1:  //#define snippet_1stSearch
   2:  //#define snippet_SearchID
   3:  #define snippet_SearchGenre
   4:   
   5:   
   6:  using Microsoft.AspNetCore.Mvc;
   7:  using Microsoft.AspNetCore.Mvc.Rendering;
   8:  using Microsoft.EntityFrameworkCore;
   9:  using MvcMovie.Models;
  10:  using System;
  11:  using System.Linq;
  12:  using System.Threading.Tasks;
  13:   
  14:  namespace MvcMovie.Controllers
  15:  {
  16:      public class MoviesController : Controller
  17:      {
  18:          private readonly MvcMovieContext _context;
  19:   
  20:          public MoviesController(MvcMovieContext context)
  21:          {
  22:              _context = context;
  23:          }
  24:   
  25:          #region snippet_details
  26:          // GET: Movies/Details/5
  27:          public async Task<IActionResult> Details(int? id)
  28:          {
  29:              if (id == null)
  30:              {
  31:                  return NotFound();
  32:              }
  33:   
  34:              var movie = await _context.Movie
  35:                  .SingleOrDefaultAsync(m => m.ID == id);
  36:              if (movie == null)
  37:              {
  38:                  return NotFound();
  39:              }
  40:   
  41:              return View(movie);
  42:          }
  43:          #endregion
  44:          #region snippetCreate
  45:          // GET: Movies/Create
  46:          public IActionResult Create()
  47:          {
  48:              return View();
  49:          }
  50:   
  51:          // POST: Movies/Create
  52:          [HttpPost]
  53:          [ValidateAntiForgeryToken]
  54:          public async Task<IActionResult> Create(
  55:              [Bind("ID,Title,ReleaseDate,Genre,Price, Rating")] Movie movie)
  56:          {
  57:              if (ModelState.IsValid)
  58:              {
  59:                  _context.Add(movie);
  60:                  await _context.SaveChangesAsync();
  61:                  return RedirectToAction("Index");
  62:              }
  63:              return View(movie);
  64:          }
  65:          #endregion
  66:   
  67:          // GET: Movies/Edit/5
  68:          public async Task<IActionResult> Edit(int? id)
  69:          {
  70:              if (id == null)
  71:              {
  72:                  return NotFound();
  73:              }
  74:   
  75:              var movie = await _context.Movie.SingleOrDefaultAsync(m => m.ID == id);
  76:              if (movie == null)
  77:              {
  78:                  return NotFound();
  79:              }
  80:              return View(movie);
  81:          }
  82:   
  83:          // POST: Movies/Edit/5
  84:          // To protect from overposting attacks, please enable the specific properties you want to bind to, for 
  85:          // more details see http://go.microsoft.com/fwlink/?LinkId=317598.
  86:          [HttpPost]
  87:          [ValidateAntiForgeryToken]
  88:          public async Task<IActionResult> Edit(int id, [Bind("ID,Title,ReleaseDate,Genre,Price,Rating")] Movie movie)
  89:          {
  90:              if (id != movie.ID)
  91:              {
  92:                  return NotFound();
  93:              }
  94:   
  95:              if (ModelState.IsValid)
  96:              {
  97:                  try
  98:                  {
  99:                      _context.Update(movie);
 100:                      await _context.SaveChangesAsync();
 101:                  }
 102:                  catch (DbUpdateConcurrencyException)
 103:                  {
 104:                      if (!MovieExists(movie.ID))
 105:                      {
 106:                          return NotFound();
 107:                      }
 108:                      else
 109:                      {
 110:                          throw;
 111:                      }
 112:                  }
 113:                  return RedirectToAction("Index");
 114:              }
 115:              return View(movie);
 116:          }
 117:   
 118:          #region snippet_delete
 119:          #region snippet_delete2
 120:          // GET: Movies/Delete/5
 121:          public async Task<IActionResult> Delete(int? id)
 122:          {
 123:              #endregion
 124:              if (id == null)
 125:              {
 126:                  return NotFound();
 127:              }
 128:   
 129:              var movie = await _context.Movie
 130:                  .SingleOrDefaultAsync(m => m.ID == id);
 131:              if (movie == null)
 132:              {
 133:                  return NotFound();
 134:              }
 135:   
 136:              return View(movie);
 137:          }
 138:   
 139:          #region snippet_delete3
 140:          // POST: Movies/Delete/5
 141:          [HttpPost, ActionName("Delete")]
 142:          [ValidateAntiForgeryToken]
 143:          public async Task<IActionResult> DeleteConfirmed(int id)
 144:          {
 145:              #endregion
 146:              var movie = await _context.Movie.SingleOrDefaultAsync(m => m.ID == id);
 147:              _context.Movie.Remove(movie);
 148:              await _context.SaveChangesAsync();
 149:              return RedirectToAction("Index");
 150:          }
 151:          #endregion
 152:   
 153:          private bool MovieExists(int id)
 154:          {
 155:              return _context.Movie.Any(e => e.ID == id);
 156:          }
 157:  #if snippet_1stSearch
 158:          // First Search
 159:          #region snippet_1stSearch
 160:          public async Task<IActionResult> Index(string searchString)
 161:          {
 162:              var movies = from m in _context.Movie
 163:                           select m;
 164:   
 165:              if (!String.IsNullOrEmpty(searchString))
 166:              {
 167:                  movies = movies.Where(s => s.Title.Contains(searchString));
 168:              }
 169:   
 170:              return View(await movies.ToListAsync());
 171:          }
 172:          #endregion
 173:          // End first Search
 174:  #endif
 175:   
 176:  #if snippet_SearchID
 177:          // Search ID 
 178:          #region snippet_SearchID
 179:          public async Task<IActionResult> Index(string id)
 180:          {
 181:              var movies = from m in _context.Movie
 182:                           select m;
 183:   
 184:          #region snippet_SearchNull
 185:              if (!String.IsNullOrEmpty(id))
 186:              {
 187:                  movies = movies.Where(s => s.Title.Contains(id));
 188:              }
 189:          #endregion
 190:   
 191:              return View(await movies.ToListAsync());
 192:          }
 193:          #endregion
 194:          // End search ID
 195:  #endif
 196:   
 197:  #if SearchPost
 198:          // Search Post
 199:          #region snippet_SearchPost
 200:          [HttpPost]
 201:          public string Index(string searchString, bool notUsed)
 202:          {
 203:              return "From [HttpPost]Index: filter on " + searchString;
 204:          }
 205:          #endregion
 206:          // End SP
 207:  #endif
 208:   
 209:  #if snippet_SearchGenre
 210:          // Search by genre.
 211:          #region snippet_SearchGenre
 212:          // Requires using Microsoft.AspNetCore.Mvc.Rendering;
 213:          public async Task<IActionResult> Index(string movieGenre, string searchString)
 214:          {
 215:              #region snippet_LINQ
 216:              // Use LINQ to get list of genres.
 217:              IQueryable<string> genreQuery = from m in _context.Movie
 218:                                              orderby m.Genre
 219:                                              select m.Genre;
 220:              #endregion
 221:   
 222:              var movies = from m in _context.Movie
 223:                           select m;
 224:   
 225:              #region snippet_SearchNull2
 226:              if (!String.IsNullOrEmpty(searchString))
 227:              {
 228:                  movies = movies.Where(s => s.Title.Contains(searchString));
 229:              }
 230:              #endregion
 231:   
 232:              if (!String.IsNullOrEmpty(movieGenre))
 233:              {
 234:                  movies = movies.Where(x => x.Genre == movieGenre);
 235:              }
 236:   
 237:              var movieGenreVM = new MovieGenreViewModel();
 238:              movieGenreVM.genres = new SelectList(await genreQuery.Distinct().ToListAsync());
 239:              movieGenreVM.movies = await movies.ToListAsync();
 240:   
 241:              return View(movieGenreVM);
 242:          }
 243:          #endregion
 244:  #endif
 245:      }
 246:  }

Note that the HTTP GET Delete method doesn???t delete the specified movie, it returns a view of the movie where you can submit (HttpPost) the deletion. Performing a delete operation in response to a GET request (or for that matter, performing an edit operation, create operation, or any other operation that changes data) opens up a security hole.

The [HttpPost] method that deletes the data is named DeleteConfirmed to give the HTTP POST method a unique signature or name. The two method signatures are shown below:

[!code-csharpMain]

   1:  //#define snippet_1stSearch
   2:  //#define snippet_SearchID
   3:  #define snippet_SearchGenre
   4:   
   5:   
   6:  using Microsoft.AspNetCore.Mvc;
   7:  using Microsoft.AspNetCore.Mvc.Rendering;
   8:  using Microsoft.EntityFrameworkCore;
   9:  using MvcMovie.Models;
  10:  using System;
  11:  using System.Linq;
  12:  using System.Threading.Tasks;
  13:   
  14:  namespace MvcMovie.Controllers
  15:  {
  16:      public class MoviesController : Controller
  17:      {
  18:          private readonly MvcMovieContext _context;
  19:   
  20:          public MoviesController(MvcMovieContext context)
  21:          {
  22:              _context = context;
  23:          }
  24:   
  25:          #region snippet_details
  26:          // GET: Movies/Details/5
  27:          public async Task<IActionResult> Details(int? id)
  28:          {
  29:              if (id == null)
  30:              {
  31:                  return NotFound();
  32:              }
  33:   
  34:              var movie = await _context.Movie
  35:                  .SingleOrDefaultAsync(m => m.ID == id);
  36:              if (movie == null)
  37:              {
  38:                  return NotFound();
  39:              }
  40:   
  41:              return View(movie);
  42:          }
  43:          #endregion
  44:          #region snippetCreate
  45:          // GET: Movies/Create
  46:          public IActionResult Create()
  47:          {
  48:              return View();
  49:          }
  50:   
  51:          // POST: Movies/Create
  52:          [HttpPost]
  53:          [ValidateAntiForgeryToken]
  54:          public async Task<IActionResult> Create(
  55:              [Bind("ID,Title,ReleaseDate,Genre,Price, Rating")] Movie movie)
  56:          {
  57:              if (ModelState.IsValid)
  58:              {
  59:                  _context.Add(movie);
  60:                  await _context.SaveChangesAsync();
  61:                  return RedirectToAction("Index");
  62:              }
  63:              return View(movie);
  64:          }
  65:          #endregion
  66:   
  67:          // GET: Movies/Edit/5
  68:          public async Task<IActionResult> Edit(int? id)
  69:          {
  70:              if (id == null)
  71:              {
  72:                  return NotFound();
  73:              }
  74:   
  75:              var movie = await _context.Movie.SingleOrDefaultAsync(m => m.ID == id);
  76:              if (movie == null)
  77:              {
  78:                  return NotFound();
  79:              }
  80:              return View(movie);
  81:          }
  82:   
  83:          // POST: Movies/Edit/5
  84:          // To protect from overposting attacks, please enable the specific properties you want to bind to, for 
  85:          // more details see http://go.microsoft.com/fwlink/?LinkId=317598.
  86:          [HttpPost]
  87:          [ValidateAntiForgeryToken]
  88:          public async Task<IActionResult> Edit(int id, [Bind("ID,Title,ReleaseDate,Genre,Price,Rating")] Movie movie)
  89:          {
  90:              if (id != movie.ID)
  91:              {
  92:                  return NotFound();
  93:              }
  94:   
  95:              if (ModelState.IsValid)
  96:              {
  97:                  try
  98:                  {
  99:                      _context.Update(movie);
 100:                      await _context.SaveChangesAsync();
 101:                  }
 102:                  catch (DbUpdateConcurrencyException)
 103:                  {
 104:                      if (!MovieExists(movie.ID))
 105:                      {
 106:                          return NotFound();
 107:                      }
 108:                      else
 109:                      {
 110:                          throw;
 111:                      }
 112:                  }
 113:                  return RedirectToAction("Index");
 114:              }
 115:              return View(movie);
 116:          }
 117:   
 118:          #region snippet_delete
 119:          #region snippet_delete2
 120:          // GET: Movies/Delete/5
 121:          public async Task<IActionResult> Delete(int? id)
 122:          {
 123:              #endregion
 124:              if (id == null)
 125:              {
 126:                  return NotFound();
 127:              }
 128:   
 129:              var movie = await _context.Movie
 130:                  .SingleOrDefaultAsync(m => m.ID == id);
 131:              if (movie == null)
 132:              {
 133:                  return NotFound();
 134:              }
 135:   
 136:              return View(movie);
 137:          }
 138:   
 139:          #region snippet_delete3
 140:          // POST: Movies/Delete/5
 141:          [HttpPost, ActionName("Delete")]
 142:          [ValidateAntiForgeryToken]
 143:          public async Task<IActionResult> DeleteConfirmed(int id)
 144:          {
 145:              #endregion
 146:              var movie = await _context.Movie.SingleOrDefaultAsync(m => m.ID == id);
 147:              _context.Movie.Remove(movie);
 148:              await _context.SaveChangesAsync();
 149:              return RedirectToAction("Index");
 150:          }
 151:          #endregion
 152:   
 153:          private bool MovieExists(int id)
 154:          {
 155:              return _context.Movie.Any(e => e.ID == id);
 156:          }
 157:  #if snippet_1stSearch
 158:          // First Search
 159:          #region snippet_1stSearch
 160:          public async Task<IActionResult> Index(string searchString)
 161:          {
 162:              var movies = from m in _context.Movie
 163:                           select m;
 164:   
 165:              if (!String.IsNullOrEmpty(searchString))
 166:              {
 167:                  movies = movies.Where(s => s.Title.Contains(searchString));
 168:              }
 169:   
 170:              return View(await movies.ToListAsync());
 171:          }
 172:          #endregion
 173:          // End first Search
 174:  #endif
 175:   
 176:  #if snippet_SearchID
 177:          // Search ID 
 178:          #region snippet_SearchID
 179:          public async Task<IActionResult> Index(string id)
 180:          {
 181:              var movies = from m in _context.Movie
 182:                           select m;
 183:   
 184:          #region snippet_SearchNull
 185:              if (!String.IsNullOrEmpty(id))
 186:              {
 187:                  movies = movies.Where(s => s.Title.Contains(id));
 188:              }
 189:          #endregion
 190:   
 191:              return View(await movies.ToListAsync());
 192:          }
 193:          #endregion
 194:          // End search ID
 195:  #endif
 196:   
 197:  #if SearchPost
 198:          // Search Post
 199:          #region snippet_SearchPost
 200:          [HttpPost]
 201:          public string Index(string searchString, bool notUsed)
 202:          {
 203:              return "From [HttpPost]Index: filter on " + searchString;
 204:          }
 205:          #endregion
 206:          // End SP
 207:  #endif
 208:   
 209:  #if snippet_SearchGenre
 210:          // Search by genre.
 211:          #region snippet_SearchGenre
 212:          // Requires using Microsoft.AspNetCore.Mvc.Rendering;
 213:          public async Task<IActionResult> Index(string movieGenre, string searchString)
 214:          {
 215:              #region snippet_LINQ
 216:              // Use LINQ to get list of genres.
 217:              IQueryable<string> genreQuery = from m in _context.Movie
 218:                                              orderby m.Genre
 219:                                              select m.Genre;
 220:              #endregion
 221:   
 222:              var movies = from m in _context.Movie
 223:                           select m;
 224:   
 225:              #region snippet_SearchNull2
 226:              if (!String.IsNullOrEmpty(searchString))
 227:              {
 228:                  movies = movies.Where(s => s.Title.Contains(searchString));
 229:              }
 230:              #endregion
 231:   
 232:              if (!String.IsNullOrEmpty(movieGenre))
 233:              {
 234:                  movies = movies.Where(x => x.Genre == movieGenre);
 235:              }
 236:   
 237:              var movieGenreVM = new MovieGenreViewModel();
 238:              movieGenreVM.genres = new SelectList(await genreQuery.Distinct().ToListAsync());
 239:              movieGenreVM.movies = await movies.ToListAsync();
 240:   
 241:              return View(movieGenreVM);
 242:          }
 243:          #endregion
 244:  #endif
 245:      }
 246:  }

[!code-csharpMain]

   1:  //#define snippet_1stSearch
   2:  //#define snippet_SearchID
   3:  #define snippet_SearchGenre
   4:   
   5:   
   6:  using Microsoft.AspNetCore.Mvc;
   7:  using Microsoft.AspNetCore.Mvc.Rendering;
   8:  using Microsoft.EntityFrameworkCore;
   9:  using MvcMovie.Models;
  10:  using System;
  11:  using System.Linq;
  12:  using System.Threading.Tasks;
  13:   
  14:  namespace MvcMovie.Controllers
  15:  {
  16:      public class MoviesController : Controller
  17:      {
  18:          private readonly MvcMovieContext _context;
  19:   
  20:          public MoviesController(MvcMovieContext context)
  21:          {
  22:              _context = context;
  23:          }
  24:   
  25:          #region snippet_details
  26:          // GET: Movies/Details/5
  27:          public async Task<IActionResult> Details(int? id)
  28:          {
  29:              if (id == null)
  30:              {
  31:                  return NotFound();
  32:              }
  33:   
  34:              var movie = await _context.Movie
  35:                  .SingleOrDefaultAsync(m => m.ID == id);
  36:              if (movie == null)
  37:              {
  38:                  return NotFound();
  39:              }
  40:   
  41:              return View(movie);
  42:          }
  43:          #endregion
  44:          #region snippetCreate
  45:          // GET: Movies/Create
  46:          public IActionResult Create()
  47:          {
  48:              return View();
  49:          }
  50:   
  51:          // POST: Movies/Create
  52:          [HttpPost]
  53:          [ValidateAntiForgeryToken]
  54:          public async Task<IActionResult> Create(
  55:              [Bind("ID,Title,ReleaseDate,Genre,Price, Rating")] Movie movie)
  56:          {
  57:              if (ModelState.IsValid)
  58:              {
  59:                  _context.Add(movie);
  60:                  await _context.SaveChangesAsync();
  61:                  return RedirectToAction("Index");
  62:              }
  63:              return View(movie);
  64:          }
  65:          #endregion
  66:   
  67:          // GET: Movies/Edit/5
  68:          public async Task<IActionResult> Edit(int? id)
  69:          {
  70:              if (id == null)
  71:              {
  72:                  return NotFound();
  73:              }
  74:   
  75:              var movie = await _context.Movie.SingleOrDefaultAsync(m => m.ID == id);
  76:              if (movie == null)
  77:              {
  78:                  return NotFound();
  79:              }
  80:              return View(movie);
  81:          }
  82:   
  83:          // POST: Movies/Edit/5
  84:          // To protect from overposting attacks, please enable the specific properties you want to bind to, for 
  85:          // more details see http://go.microsoft.com/fwlink/?LinkId=317598.
  86:          [HttpPost]
  87:          [ValidateAntiForgeryToken]
  88:          public async Task<IActionResult> Edit(int id, [Bind("ID,Title,ReleaseDate,Genre,Price,Rating")] Movie movie)
  89:          {
  90:              if (id != movie.ID)
  91:              {
  92:                  return NotFound();
  93:              }
  94:   
  95:              if (ModelState.IsValid)
  96:              {
  97:                  try
  98:                  {
  99:                      _context.Update(movie);
 100:                      await _context.SaveChangesAsync();
 101:                  }
 102:                  catch (DbUpdateConcurrencyException)
 103:                  {
 104:                      if (!MovieExists(movie.ID))
 105:                      {
 106:                          return NotFound();
 107:                      }
 108:                      else
 109:                      {
 110:                          throw;
 111:                      }
 112:                  }
 113:                  return RedirectToAction("Index");
 114:              }
 115:              return View(movie);
 116:          }
 117:   
 118:          #region snippet_delete
 119:          #region snippet_delete2
 120:          // GET: Movies/Delete/5
 121:          public async Task<IActionResult> Delete(int? id)
 122:          {
 123:              #endregion
 124:              if (id == null)
 125:              {
 126:                  return NotFound();
 127:              }
 128:   
 129:              var movie = await _context.Movie
 130:                  .SingleOrDefaultAsync(m => m.ID == id);
 131:              if (movie == null)
 132:              {
 133:                  return NotFound();
 134:              }
 135:   
 136:              return View(movie);
 137:          }
 138:   
 139:          #region snippet_delete3
 140:          // POST: Movies/Delete/5
 141:          [HttpPost, ActionName("Delete")]
 142:          [ValidateAntiForgeryToken]
 143:          public async Task<IActionResult> DeleteConfirmed(int id)
 144:          {
 145:              #endregion
 146:              var movie = await _context.Movie.SingleOrDefaultAsync(m => m.ID == id);
 147:              _context.Movie.Remove(movie);
 148:              await _context.SaveChangesAsync();
 149:              return RedirectToAction("Index");
 150:          }
 151:          #endregion
 152:   
 153:          private bool MovieExists(int id)
 154:          {
 155:              return _context.Movie.Any(e => e.ID == id);
 156:          }
 157:  #if snippet_1stSearch
 158:          // First Search
 159:          #region snippet_1stSearch
 160:          public async Task<IActionResult> Index(string searchString)
 161:          {
 162:              var movies = from m in _context.Movie
 163:                           select m;
 164:   
 165:              if (!String.IsNullOrEmpty(searchString))
 166:              {
 167:                  movies = movies.Where(s => s.Title.Contains(searchString));
 168:              }
 169:   
 170:              return View(await movies.ToListAsync());
 171:          }
 172:          #endregion
 173:          // End first Search
 174:  #endif
 175:   
 176:  #if snippet_SearchID
 177:          // Search ID 
 178:          #region snippet_SearchID
 179:          public async Task<IActionResult> Index(string id)
 180:          {
 181:              var movies = from m in _context.Movie
 182:                           select m;
 183:   
 184:          #region snippet_SearchNull
 185:              if (!String.IsNullOrEmpty(id))
 186:              {
 187:                  movies = movies.Where(s => s.Title.Contains(id));
 188:              }
 189:          #endregion
 190:   
 191:              return View(await movies.ToListAsync());
 192:          }
 193:          #endregion
 194:          // End search ID
 195:  #endif
 196:   
 197:  #if SearchPost
 198:          // Search Post
 199:          #region snippet_SearchPost
 200:          [HttpPost]
 201:          public string Index(string searchString, bool notUsed)
 202:          {
 203:              return "From [HttpPost]Index: filter on " + searchString;
 204:          }
 205:          #endregion
 206:          // End SP
 207:  #endif
 208:   
 209:  #if snippet_SearchGenre
 210:          // Search by genre.
 211:          #region snippet_SearchGenre
 212:          // Requires using Microsoft.AspNetCore.Mvc.Rendering;
 213:          public async Task<IActionResult> Index(string movieGenre, string searchString)
 214:          {
 215:              #region snippet_LINQ
 216:              // Use LINQ to get list of genres.
 217:              IQueryable<string> genreQuery = from m in _context.Movie
 218:                                              orderby m.Genre
 219:                                              select m.Genre;
 220:              #endregion
 221:   
 222:              var movies = from m in _context.Movie
 223:                           select m;
 224:   
 225:              #region snippet_SearchNull2
 226:              if (!String.IsNullOrEmpty(searchString))
 227:              {
 228:                  movies = movies.Where(s => s.Title.Contains(searchString));
 229:              }
 230:              #endregion
 231:   
 232:              if (!String.IsNullOrEmpty(movieGenre))
 233:              {
 234:                  movies = movies.Where(x => x.Genre == movieGenre);
 235:              }
 236:   
 237:              var movieGenreVM = new MovieGenreViewModel();
 238:              movieGenreVM.genres = new SelectList(await genreQuery.Distinct().ToListAsync());
 239:              movieGenreVM.movies = await movies.ToListAsync();
 240:   
 241:              return View(movieGenreVM);
 242:          }
 243:          #endregion
 244:  #endif
 245:      }
 246:  }

The common language runtime (CLR) requires overloaded methods to have a unique parameter signature (same method name but different list of parameters). However, here you need two Delete methods ??? one for GET and one for POST ??? that both have the same parameter signature. (They both need to accept a single integer as a parameter.)

There are two approaches to this problem, one is to give the methods different names. That???s what the scaffolding mechanism did in the preceding example. However, this introduces a small problem: ASP.NET maps segments of a URL to action methods by name, and if you rename a method, routing normally wouldn???t be able to find that method. The solution is what you see in the example, which is to add the ActionName("Delete") attribute to the DeleteConfirmed method. That attribute performs mapping for the routing system so that a URL that includes /Delete/ for a POST request will find the DeleteConfirmed method.

Another common work around for methods that have identical names and signatures is to artificially change the signature of the POST method to include an extra (unused) parameter. That???s what we did in a previous post when we added the notUsed parameter. You could do the same thing here for the [HttpPost] Delete method:

Publish to Azure

See (xref:)Publish an ASP.NET Core web app to Azure App Service using Visual Studio for instructions on how to publish this app to Azure using Visual Studio. The app can also be published from the (xref:)command line.

Thanks for completing this introduction to ASP.NET Core MVC. We appreciate any comments you leave. (xref:)Getting started with MVC and EF Core is an excellent follow up to this tutorial.

Previous





Comments ( )
<00>  <01>  <02>  <03>  <04>  <05>  <06>  <07>  <08>  <09>  <10>  <11>  <12>  <13>  <14>  <15>  <16>  <17>  <18>  <19>  <20>  <21>  <22>  <23
Link to this page: //www.vb-net.com/AspNet-DocAndSamples-2017/aspnetcore/tutorials/first-mvc-app/details.htm
<SITEMAP>  <MVC>  <ASP>  <NET>  <DATA>  <KIOSK>  <FLEX>  <SQL>  <NOTES>  <LINUX>  <MONO>  <FREEWARE>  <DOCS>  <ENG>  <CHAT ME>  <ABOUT ME>  < THANKS ME>