ASP.NET MVC 5 Scaffolding

W Visual Studio 2013 oraz ASP.NET MVC 5 dodano nową funkcję, ułatwiającą wykonywanie powtarzalnych czynności. Od razu dodam, że istnieje możliwość pisania własnych szablonów. Najpierw (dzisiaj) pokażę jak skorzystać z domyślnego szablonu, który korzysta z Entity Framework. Jeśli często musimy tworzyć encje, kontroler, widoki i zapisywać dane w bazie to domyślny szablon zautomatyzuje  to. W praktyce jednak częściej korzysta się z jakiś usług niż bezpośrednio z Entity Framework, stąd opcja tworzenia własnych szablonów jest dosyć ważna, ale o tym w następnym w wpisie.

Załóżmy, że mamy następujący model:

public class Person
{
   public int Id { get; set; }
   public string FirstName { get; set; }        
   public string LastName { get; set; }
}

Chcemy wygenerować kontroler, widoki oraz kontekst, który umożliwi nam zapis danych do bazy. Innymi słowy, klasyczny CRUD. Najpierw klikamy w Solution Explorer i wybieramy Add->New Scafffolded Item…:

image

Następnie wybieramy szablon, który chcemy użyć. Dla tego przykładu wybieramy “MVC 5 controller with views, using Entity Framework”:

image

Kolejne okno dialogowe umożliwia konfiguracje kontrolera, widoków oraz kontekstu danych:

image

Po wygenerowaniu zobaczymy nowe pliki w Solution Explorer:

image

 

Kontroler zawiera operacje CRUD oraz również zostały wygenerowane stosowne widoki:

public class PersonController : Controller
{
   private WebApplication3Context db = new WebApplication3Context();

   // GET: /Person/
   public ActionResult Index()
   {
       return View(db.People.ToList());
   }

   // GET: /Person/Details/5
   public ActionResult Details(int? id)
   {
       if (id == null)
       {
           return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
       }
       Person person = db.People.Find(id);
       if (person == null)
       {
           return HttpNotFound();
       }
       return View(person);
   }

   // GET: /Person/Create
   public ActionResult Create()
   {
       return View();
   }

   // POST: /Person/Create
   // To protect from overposting attacks, please enable the specific properties you want to bind to, for 
   // more details see http://go.microsoft.com/fwlink/?LinkId=317598.
   [HttpPost]
   [ValidateAntiForgeryToken]
   public ActionResult Create([Bind(Include="Id,FirstName,LastName")] Person person)
   {
       if (ModelState.IsValid)
       {
           db.People.Add(person);
           db.SaveChanges();
           return RedirectToAction("Index");
       }

       return View(person);
   }

   // GET: /Person/Edit/5
   public ActionResult Edit(int? id)
   {
       if (id == null)
       {
           return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
       }
       Person person = db.People.Find(id);
       if (person == null)
       {
           return HttpNotFound();
       }
       return View(person);
   }

   // POST: /Person/Edit/5
   // To protect from overposting attacks, please enable the specific properties you want to bind to, for 
   // more details see http://go.microsoft.com/fwlink/?LinkId=317598.
   [HttpPost]
   [ValidateAntiForgeryToken]
   public ActionResult Edit([Bind(Include="Id,FirstName,LastName")] Person person)
   {
       if (ModelState.IsValid)
       {
           db.Entry(person).State = EntityState.Modified;
           db.SaveChanges();
           return RedirectToAction("Index");
       }
       return View(person);
   }

   // GET: /Person/Delete/5
   public ActionResult Delete(int? id)
   {
       if (id == null)
       {
           return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
       }
       Person person = db.People.Find(id);
       if (person == null)
       {
           return HttpNotFound();
       }
       return View(person);
   }

   // POST: /Person/Delete/5
   [HttpPost, ActionName("Delete")]
   [ValidateAntiForgeryToken]
   public ActionResult DeleteConfirmed(int id)
   {
       Person person = db.People.Find(id);
       db.People.Remove(person);
       db.SaveChanges();
       return RedirectToAction("Index");
   }

   protected override void Dispose(bool disposing)
   {
       if (disposing)
       {
           db.Dispose();
       }
       base.Dispose(disposing);
   }
}

Widoki zawierają podstawowe formularze itp.  Mamy plik Index, który wyświetla listę encji wraz z linkami do edycji (Edit), dodawania (Add), usuwania oraz wyświetlenia szczegółów (Details).

W praktyce niestety wiele rzeczy trzeba samemu modyfikować. Na przykład, kontekst jest inicjalizowany w samej klasie, co prawie zawsze jest nieakceptowalne – w realnych projektach korzysta się z IoC. Dlatego w następnym poście, pokażę jak pisać własne szablony, które możemy dostosować do konkretnego projektu i infrastruktury. Rozwiązanie generyczne zwykle nadają się wyłącznie do prototypów albo wymaga po prostu wielu modyfikacji.

Leave a Reply

Your email address will not be published.