Sdílet prostřednictvím


Zkoumání metod Edit a zobrazení pro úpravy (C#)

Rick Anderson

Poznámka:

Aktualizovaná verze tohoto kurzu je k dispozici zde , která používá ASP.NET MVC 5 a Visual Studio 2013. Je bezpečnější, mnohem jednodušší sledovat a demonstrovat další funkce.

V tomto kurzu se naučíte základy vytváření webové aplikace ASP.NET MVC pomocí sady Microsoft Visual Web Developer 2010 Express Service Pack 1, což je bezplatná verze sady Microsoft Visual Studio. Než začnete, ujistěte se, že jste nainstalovali níže uvedené požadavky. Všechny z nich můžete nainstalovat kliknutím na následující odkaz: Instalační program webové platformy. Případně můžete jednotlivé požadavky nainstalovat pomocí následujících odkazů:

Pokud používáte Sadu Visual Studio 2010 místo visual web developeru 2010, nainstalujte požadované součásti kliknutím na následující odkaz: Požadavky sady Visual Studio 2010.

K tomuto tématu je k dispozici projekt Visual Web Developer se zdrojovým kódem jazyka C#. Stáhněte si verzi jazyka C#. Pokud dáváte přednost jazyku Visual Basic, přepněte do verze jazyka Visual Basic tohoto kurzu.

V této části prozkoumáte vygenerované metody akcí a zobrazení řadiče videa. Pak přidáte vlastní vyhledávací stránku.

Spusťte aplikaci a přejděte na Movies kontroler připojením /Movies k adrese URL v adresním řádku prohlížeče. Podržte ukazatel myši nad odkazem pro úpravy a zobrazte adresu URL, na kterou odkazuje.

EditLink_sm

Odkaz Edit byl vygenerován metodou Html.ActionLink v zobrazení Views\Movies\Index.cshtml :

@Html.ActionLink("Edit", "Edit", new { id=item.ID })

Html.ActionLink

Objekt Html je pomocná rutina, která je vystavena pomocí vlastnosti základní WebViewPage třídy. Metoda ActionLink pomocné rutiny usnadňuje dynamické generování hypertextových odkazů HTML, které odkazují na metody akcí na řadičích. Prvním argumentem ActionLink metody je text odkazu, který se má vykreslit (například <a>Edit Me</a>). Druhým argumentem je název metody akce, která se má vyvolat. Posledním argumentem je anonymní objekt , který generuje směrovací data (v tomto případě ID 4).

Vygenerovaný odkaz zobrazený na předchozím obrázku je http://localhost:xxxxx/Movies/Edit/4. Výchozí trasa přebírá vzor {controller}/{action}/{id}adresy URL . Proto ASP.NET převede http://localhost:xxxxx/Movies/Edit/4 na požadavek na Edit metodu Movies akce kontroleru s parametrem ID rovnajícím se 4.

Parametry metody akce můžete předat také pomocí řetězce dotazu. Například adresa URL http://localhost:xxxxx/Movies/Edit?ID=4 předá parametr ID 4 metodě Edit akce Movies kontroleru.

EditQueryString

Movies Otevřete kontroler. Níže jsou uvedené dvě Edit metody akcí.

//
// GET: /Movies/Edit/5

public ActionResult Edit(int id) 
{
    Movie movie = db.Movies.Find(id);
    return View(movie);
}

//
// POST: /Movies/Edit/5

[HttpPost]
public ActionResult Edit(Movie movie) 
{
    if (ModelState.IsValid) 
    {
        db.Entry(movie).State = EntityState.Modified;
        db.SaveChanges();
        return RedirectToAction("Index");
    }
    return View(movie);
}

Všimněte si, že před atributem HttpPost předchází druhá Edit metoda akce. Tento atribut určuje, že přetížení Edit metody lze vyvolat pouze pro požadavky POST. Atribut můžete použít HttpGet u první metody úprav, ale to není nutné, protože je to výchozí. (Budeme odkazovat na metody akcí, které jsou implicitně přiřazeny HttpGet atributu jako HttpGet metody.)

Metoda HttpGet Edit přebírá parametr ID videa, vyhledá film pomocí metody Entity Framework Find a vrátí vybraný film do zobrazení Edit. Když systém generování uživatelského rozhraní vytvořil zobrazení Edit, prozkoumal Movie třídu a vytvořil kód pro vykreslení <label> a <input> prvky pro každou vlastnost třídy. Následující příklad ukazuje vygenerované zobrazení pro úpravy:

@model MvcMovie.Models.Movie

@{
    ViewBag.Title = "Edit";
}

<h2>Edit</h2>

<script src="@Url.Content("~/Scripts/jquery.validate.min.js")" type="text/javascript"></script>
<script src="@Url.Content("~/Scripts/jquery.validate.unobtrusive.min.js")" type="text/javascript"></script>

@using (Html.BeginForm()) {
    @Html.ValidationSummary(true)
    <fieldset>
        <legend>Movie</legend>

        @Html.HiddenFor(model => model.ID)

        <div class="editor-label">
            @Html.LabelFor(model => model.Title)
        </div>
        <div class="editor-field">
            @Html.EditorFor(model => model.Title)
            @Html.ValidationMessageFor(model => model.Title)
        </div>

        <div class="editor-label">
            @Html.LabelFor(model => model.ReleaseDate)
        </div>
        <div class="editor-field">
            @Html.EditorFor(model => model.ReleaseDate)
            @Html.ValidationMessageFor(model => model.ReleaseDate)
        </div>

        <div class="editor-label">
            @Html.LabelFor(model => model.Genre)
        </div>
        <div class="editor-field">
            @Html.EditorFor(model => model.Genre)
            @Html.ValidationMessageFor(model => model.Genre)
        </div>

        <div class="editor-label">
            @Html.LabelFor(model => model.Price)
        </div>
        <div class="editor-field">
            @Html.EditorFor(model => model.Price)
            @Html.ValidationMessageFor(model => model.Price)
        </div>

        <p>
            <input type="submit" value="Save" />
        </p>
    </fieldset>
}

<div>
    @Html.ActionLink("Back to List", "Index")
</div>

Všimněte si, že šablona zobrazení obsahuje @model MvcMovie.Models.Movie příkaz v horní části souboru – určuje, že zobrazení očekává model šablony zobrazení typu Movie.

Vygenerovaný kód používá několik pomocných metod ke zjednodušení kódu HTML. Pomocník Html.LabelFor zobrazí název pole (Název, Datum vydání, Žánr nebo Cena). Pomocník Html.EditorFor zobrazí element HTML <input> . Pomocník Html.ValidationMessageFor zobrazí všechny ověřovací zprávy přidružené k této vlastnosti.

Spusťte aplikaci a přejděte na adresu URL /Movies . Klikněte na odkaz Upravit. V prohlížeči zobrazte zdroj stránky. Kód HTML na stránce vypadá jako v následujícím příkladu. (Revize nabídky byla vyloučena z důvodu přehlednosti.)

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8" />
    <title>Edit</title>
    <link href="/Content/Site.css" rel="stylesheet" type="text/css" />
    <script src="/Scripts/jquery-1.5.1.min.js" type="text/javascript"></script>
    <script src="/Scripts/modernizr-1.7.min.js" type="text/javascript"></script>
</head>
<body>
    <div class="page">
        <header>
            <div id="title">
                <h1>MVC Movie App</h1>
            </div>
           ...
        </header>
        <section id="main">

<h2>Edit</h2>

<script src="/Scripts/jquery.validate.min.js" type="text/javascript"></script>
<script src="/Scripts/jquery.validate.unobtrusive.min.js" type="text/javascript"></script>

<form action="/Movies/Edit/4" method="post">    <fieldset>
        <legend>Movie</legend>

        <input data-val="true" data-val-number="The field ID must be a number." 
    data-val-required="The ID field is required." id="ID" name="ID" type="hidden" value="4" />

        <div class="editor-label">
            <label for="Title">Title</label>
        </div>
        <div class="editor-field">
            <input class="text-box single-line" id="Title" name="Title" type="text" value="Rio Bravo" />
            <span class="field-validation-valid" data-valmsg-for="Title" data-valmsg-replace="true"></span>
        </div>

        <div class="editor-label">
            <label for="ReleaseDate">ReleaseDate</label>
        </div>
        <div class="editor-field">
            <input class="text-box single-line" data-val="true" data-val-required="The ReleaseDate field is required." 
    id="ReleaseDate" name="ReleaseDate" type="text" value="4/15/1959 12:00:00 AM" />
            <span class="field-validation-valid" data-valmsg-for="ReleaseDate" data-valmsg-replace="true"></span>
        </div>

        <div class="editor-label">
            <label for="Genre">Genre</label>
        </div>
        <div class="editor-field">
            <input class="text-box single-line" id="Genre" name="Genre" type="text" value="Western" />
            <span class="field-validation-valid" data-valmsg-for="Genre" data-valmsg-replace="true"></span>
        </div>

        <div class="editor-label">
            <label for="Price">Price</label>
        </div>
        <div class="editor-field">
            <input class="text-box single-line" data-val="true" data-val-number="The field Price must be a number." 
    data-val-required="The Price field is required." id="Price" name="Price" type="text" value="9.99" />
            <span class="field-validation-valid" data-valmsg-for="Price" data-valmsg-replace="true"></span>
        </div>

        <p>
            <input type="submit" value="Save" />
        </p>
    </fieldset>
</form>
<div>
    <a href="/Movies">Back to List</a>
</div>

        </section>
        <footer>
        </footer>
    </div>
</body>
</html>

Prvky <input> jsou v elementu HTML <form> , jehož action atribut je nastaven pro publikování na adresu URL /Movies/Edit . Data formuláře se publikují na server po kliknutí na tlačítko Upravit .

Zpracování požadavku POST

Následující výpis ukazuje HttpPost verzi Edit metody akce.

[HttpPost]
public ActionResult Edit(Movie movie) 
{
    if (ModelState.IsValid) 
    {
        db.Entry(movie).State = EntityState.Modified;
        db.SaveChanges();
        return RedirectToAction("Index");
    }
    return View(movie);
}

Pořadač modelu ASP.NET architektury přebírá publikované hodnoty formuláře a vytvoří Movie objekt, který se předá jako movie parametr. Vrácení ModelState.IsValid kódu se změnami ověří, že data odeslaná ve formuláři lze použít k úpravě objektu Movie . Pokud jsou data platná, uloží kód data videa do Movies kolekce MovieDBContext instance. Kód pak uloží nová filmová data do databáze voláním SaveChanges metody MovieDBContext, která zachovává změny v databázi. Po uložení dat kód přesměruje uživatele na Index metodu MoviesController akce třídy, která způsobí zobrazení aktualizovaného videa v seznamu filmů.

Pokud publikované hodnoty nejsou platné, zobrazí se ve formuláři znovu. Pomocné Html.ValidationMessageFor rutiny v šabloně zobrazení Edit.cshtml se postará o zobrazení odpovídajících chybových zpráv.

abcNotValid

Poznámka o národních prostředích Pokud obvykle pracujete s jiným národním prostředím než v angličtině, přečtěte si téma Podpora ASP.NET ověřování MVC 3 s neanglické národní prostředí.

Zajištění robustnější metody úprav

Metoda HttpGet Edit vygenerovaná systémem generování uživatelského rozhraní nekontroluje platnost ID, které mu bylo předáno. Pokud uživatel odebere segment ID z adresy URL (http://localhost:xxxxx/Movies/Edit), zobrazí se následující chyba:

Null_ID

Uživatel může také předat ID, které v databázi neexistuje, například http://localhost:xxxxx/Movies/Edit/1234. Pokud chcete toto omezení vyřešit, můžete v metodě akce provést dvě změny HttpGet Edit . Nejprve změňte ID parametr tak, aby měl výchozí hodnotu nula, pokud id není explicitně předáno. Můžete také zkontrolovat, zda Find metoda skutečně našla film před vrácením objektu videa do šablony zobrazení. Aktualizovaná Edit metoda je zobrazena níže.

public ActionResult Edit(int id = 0)
{
    Movie movie = db.Movies.Find(id);
    if (movie == null)
    {
        return HttpNotFound();
    }
    return View(movie);
}

Pokud se nenajde žádný film, volá se HttpNotFound metoda.

HttpGet Všechny metody se řídí podobným vzorem. Načte objekt videa (nebo seznam objektů v případě Index) a předají model do zobrazení. Metoda Create předá prázdný objekt filmu do zobrazení Create. Všechny metody, které vytvářejí, upravují, odstraňují nebo jinak upravují data, to dělají v HttpPost přetížení metody. Úprava dat v metodě HTTP GET představuje bezpečnostní riziko. Úprava dat v metodě GET také porušuje osvědčené postupy HTTP a vzor architektury REST, který určuje, že požadavky GET by neměly měnit stav vaší aplikace. Jinými slovy, provedení operace GET by mělo být bezpečná operace, která nemá žádné vedlejší účinky.

Přidání metody hledání a zobrazení hledání

V této části přidáte metodu SearchIndex akcí, která umožňuje hledat filmy podle žánru nebo názvu. Bude k dispozici pomocí adresy URL /Movies/SearchIndex . Požadavek zobrazí formulář HTML, který obsahuje vstupní prvky, které uživatel může vyplnit, aby mohl vyhledat film. Když uživatel odešle formulář, metoda akce získá hodnoty hledání publikované uživatelem a použije hodnoty k vyhledávání v databázi.

Zobrazení formuláře SearchIndex

Začněte přidáním SearchIndex metody akce do existující MoviesController třídy. Metoda vrátí zobrazení, které obsahuje formulář HTML. Tady je kód:

public ActionResult SearchIndex(string searchString)
{          
    var movies = from m in db.Movies
                 select m;

    if (!String.IsNullOrEmpty(searchString))
    {
        movies = movies.Where(s => s.Title.Contains(searchString));
    }

    return View(movies);
}

První řádek SearchIndex metody vytvoří následující dotaz LINQ pro výběr filmů:

var movies = from m in db.Movies
             select m;

Dotaz je v tomto okamžiku definovaný, ale zatím nebyl spuštěn proti úložišti dat.

searchString Pokud parametr obsahuje řetězec, dotaz filmy se upraví tak, aby filtrovaly hodnotu hledaného řetězce pomocí následujícího kódu:

if (!String.IsNullOrEmpty(searchString))
{
    movies = movies.Where(s => s.Title.Contains(searchString));
}

Dotazy LINQ se nespouštějí, pokud jsou definovány nebo když jsou upraveny voláním metody, jako Where OrderByje nebo . Místo toho je odloženo provádění dotazu, což znamená, že vyhodnocení výrazu je zpožděné, dokud se jeho dosažená hodnota ve skutečnosti iterated over nebo ToList metoda volá. V ukázce SearchIndex se dotaz spustí v zobrazení SearchIndex. Další informace o odložené spuštění dotazu naleznete v tématu Provádění dotazů.

Teď můžete implementovat SearchIndex zobrazení, které zobrazí formulář uživateli. Klikněte pravým tlačítkem myši do SearchIndex metody a potom klikněte na přidat zobrazení. V dialogovém okně Přidat zobrazení určete, že chcete předat Movie objekt šabloně zobrazení jako její třídu modelu. V seznamu šablon uživatelského rozhraní zvolte Seznam a potom klikněte na Přidat.

AddSearchView

Když kliknete na tlačítko Přidat , vytvoří se šablona zobrazení Views\Movies\SearchIndex.cshtml . Vzhledem k tomu, že jste v seznamu šablon uživatelského rozhraní vybrali seznam, visual web developer automaticky vygeneroval (vygenerovaný) nějaký výchozí obsah v zobrazení. Generování uživatelského rozhraní vytvořilo formulář HTML. Prozkoumal třídu Movie a vytvořil kód pro vykreslení <label> prvků pro každou vlastnost třídy. Následující výpis ukazuje vygenerované zobrazení Pro vytvoření:

@model IEnumerable<MvcMovie.Models.Movie>

@{
    ViewBag.Title = "SearchIndex";
}

<h2>SearchIndex</h2>

<p>
    @Html.ActionLink("Create New", "Create")
</p>
<table>
    <tr>
        <th>
            Title
        </th>
        <th>
            ReleaseDate
        </th>
        <th>
            Genre
        </th>
        <th>
            Price
        </th>
        <th></th>
    </tr>

@foreach (var item in Model) {
    <tr>
        <td>
            @Html.DisplayFor(modelItem => item.Title)
        </td>
        <td>
            @Html.DisplayFor(modelItem => item.ReleaseDate)
        </td>
        <td>
            @Html.DisplayFor(modelItem => item.Genre)
        </td>
        <td>
            @Html.DisplayFor(modelItem => item.Price)
        </td>
        <td>
            @Html.ActionLink("Edit", "Edit", new { id=item.ID }) |
            @Html.ActionLink("Details", "Details", new { id=item.ID }) |
            @Html.ActionLink("Delete", "Delete", new { id=item.ID })
        </td>
    </tr>
}

</table>

Spusťte aplikaci a přejděte na /Movies/SearchIndex. Připojte řetězec dotazu, například ?searchString=ghost k adrese URL. Zobrazí se filtrované filmy.

SearchQryStr

Pokud změníte podpis SearchIndex metody tak, aby měl název idparametru , id bude parametr odpovídat {id} zástupného symbolu pro výchozí trasy nastavené v souboru Global.asax .

{controller}/{action}/{id}

Upravená SearchIndex metoda by vypadala takto:

public ActionResult SearchIndex(string id)
{
    string searchString = id;
    var movies = from m in db.Movies
                 select m;

    if (!String.IsNullOrEmpty(searchString))
    {
        movies = movies.Where(s => s.Title.Contains(searchString));
    }

    return View(movies);
}

Název hledání teď můžete předat jako směrovací data (segment adresy URL) místo jako hodnotu řetězce dotazu.

SearchRouteData

Nemůžete ale očekávat, že uživatelé upraví adresu URL pokaždé, když chtějí hledat film. Teď tedy přidáte uživatelské rozhraní, které jim pomůže filtrovat filmy. Pokud jste změnili podpis SearchIndex metody tak, aby testoval, jak předat parametr ID vázané na trasu, změňte ho zpět tak, aby vaše SearchIndex metoda přebírá řetězcový parametr s názvem searchString:

public ActionResult SearchIndex(string searchString)
{          
     var movies = from m in db.Movies
                  select m;

    if (!String.IsNullOrEmpty(searchString))
    {
        movies = movies.Where(s => s.Title.Contains(searchString));
    }

    return View(movies);
}

Otevřete soubor Views\Movies\SearchIndex.cshtml a hned za @Html.ActionLink("Create New", "Create"), přidejte následující:

@using (Html.BeginForm()){   
         <p> Title: @Html.TextBox("SearchString") 
         <input type="submit" value="Filter" /></p>
        }

Následující příklad ukazuje část souboru Views\Movies\SearchIndex.cshtml s přidanou značkou filtrování.

@model IEnumerable<MvcMovie.Models.Movie>

@{
    ViewBag.Title = "SearchIndex";
}

<h2>SearchIndex</h2>

<p>
    @Html.ActionLink("Create New", "Create")
    
     @using (Html.BeginForm()){   
         <p> Title: @Html.TextBox("SearchString") <br />  
         <input type="submit" value="Filter" /></p>
        }
</p>

Pomocná rutina Html.BeginForm vytvoří levou <form> značku. Pomocná Html.BeginForm rutina způsobí, že se formulář publikuje, když uživatel odešle formulář kliknutím na tlačítko Filtr .

Spusťte aplikaci a zkuste vyhledat film.

SearchIndxIE9_title

Metoda není HttpPost přetížená SearchIndex . Nepotřebujete ji, protože metoda nemění stav aplikace, pouze filtrování dat.

Můžete přidat následující HttpPost SearchIndex metodu. V takovém případě by vyvolání akce odpovídalo HttpPost SearchIndex metodě a HttpPost SearchIndex metoda by se spustila, jak je znázorněno na následujícím obrázku.

[HttpPost]
public string SearchIndex(FormCollection fc, string searchString)
{
    return "<h3> From [HttpPost]SearchIndex: " + searchString + "</h3>";
}

SearchPostGhost

I když ale přidáte tuto HttpPost verzi SearchIndex metody, existuje omezení způsobu implementace. Představte si, že chcete vytvořit záložku určitého hledání nebo chcete poslat odkaz přátelům, na které můžou kliknout, aby se zobrazil stejný filtrovaný seznam filmů. Všimněte si, že adresa URL požadavku HTTP POST je stejná jako adresa URL požadavku GET (localhost:xxxxx/Movies/SearchIndex) – v samotné adrese URL nejsou žádné informace o hledání. Informace o vyhledávacím řetězci se teď odesílají na server jako hodnota pole formuláře. To znamená, že v adrese URL nemůžete zachytávat informace o hledání, které se mají posílat do záložek nebo posílat přátelům.

Řešením je použít přetížení BeginForm , které určuje, že požadavek POST by měl přidat vyhledávací informace do adresy URL a který by se měl směrovat do verze SearchIndex HttpGet metody. Nahraďte existující metodu bez BeginForm parametrů následujícím kódem:

@using (Html.BeginForm("SearchIndex","Movies",FormMethod.Get))

BeginFormPost_SM

Když teď odešlete hledání, adresa URL obsahuje řetězec vyhledávacího dotazu. Hledání také přejde na metodu HttpGet SearchIndex akce, i když máte metodu HttpPost SearchIndex .

SearchIndexWithGetURL

Přidání hledání podle žánru

Pokud jste přidali HttpPost verzi SearchIndex metody, odstraňte ji teď.

Dále přidáte funkci, která uživatelům umožní vyhledávat filmy podle žánru. Nahraďte metodu SearchIndex následujícím kódem:

public ActionResult SearchIndex(string movieGenre, string searchString)
{
    var GenreLst = new List<string>();

    var GenreQry = from d in db.Movies
                   orderby d.Genre
                   select d.Genre;
    GenreLst.AddRange(GenreQry.Distinct());
    ViewBag.movieGenre = new SelectList(GenreLst);

    var movies = from m in db.Movies
                 select m;

    if (!String.IsNullOrEmpty(searchString))
    {
        movies = movies.Where(s => s.Title.Contains(searchString));
    }

    if (string.IsNullOrEmpty(movieGenre))
        return View(movies);
    else
    {
        return View(movies.Where(x => x.Genre == movieGenre));
    }
}

Tato verze SearchIndex metody přebírá další parametr, konkrétně movieGenre. Prvních několik řádků kódu vytvoří List objekt, který bude obsahovat filmové žánry z databáze.

Následující kód je dotaz LINQ, který načte všechny žánry z databáze.

var GenreQry = from d in db.Movies
               orderby d.Genre
               select d.Genre;

Kód používá AddRange metodu obecné List kolekce k přidání všech různých žánrů do seznamu. (Bez modifikátoru Distinct by se přidaly duplicitní žánry – například comedy by byly přidány dvakrát v našem vzorku). Kód pak uloží seznam žánrů v objektu ViewBag .

Následující kód ukazuje, jak zkontrolovat movieGenre parametr. Pokud kód nevyprázdní, omezí dotaz na filmy, aby omezil vybrané filmy na zadaný žánr.

if (string.IsNullOrEmpty(movieGenre))
        return View(movies);
else
{
    return View(movies.Where(x => x.Genre == movieGenre));
}

Přidání značek do zobrazení SearchIndex pro podporu vyhledávání podle žánru

Přidejte pomocnou Html.DropDownList rutinu do souboru Views\Movies\SearchIndex.cshtml těsně před pomocnou rutinou TextBox . Dokončená revize je znázorněna níže:

<p>
    @Html.ActionLink("Create New", "Create")
    @using (Html.BeginForm()){   
         <p>Genre: @Html.DropDownList("movieGenre", "All")  
           Title: @Html.TextBox("SearchString")  
         <input type="submit" value="Filter" /></p>
        }
</p>

Spusťte aplikaci a přejděte na /Movies/SearchIndex. Zkuste hledat podle žánru, podle názvu filmu a podle obou kritérií.

V této části jste prozkoumali metody akcí CRUD a zobrazení vygenerovaná architekturou. Vytvořili jste metodu akce hledání a zobrazení, které uživatelům umožní hledat podle názvu filmu a žánru. V další části se podíváte, jak do modelu přidat vlastnost Movie a jak přidat inicializátor, který automaticky vytvoří testovací databázi.