Sdílet prostřednictvím


Zkoumání metod a zobrazení akcí pro řadič videa

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 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 v Základní třídě System.Web.Mvc.WebViewPage . 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 (vytvořená v App_Start\RouteConfig.cs) 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. Zkontrolujte následující kód ze souboru App_Start\RouteConfig.cs .

public static void RegisterRoutes(RouteCollection routes)
{
    routes.IgnoreRoute("{resource}.axd/{*pathInfo}");

    routes.MapRoute(
        name: "Default",
        url: "{controller}/{action}/{id}",
        defaults: new { controller = "Home", action = "Index", 
            id = UrlParameter.Optional }
    );
}

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 = 0)
{
    Movie movie = db.Movies.Find(id);
    if (movie == null)
    {
        return HttpNotFound();
    }
    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. Parametr ID určuje výchozí hodnotu nula, pokud Edit metoda je volána bez parametru. Pokud nelze najít video, vrátí se HttpNotFound . 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>

@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>

@section Scripts {
    @Scripts.Render("~/bundles/jqueryval")
}

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 vykreslí 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 pro element formuláře je zobrazen níže.

<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-date="The field ReleaseDate must be a date." 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="2.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>

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 MVC přebírá publikované hodnoty formuláře a vytvoří Movie objekt, který se předá jako movie parametr. Metoda ModelState.IsValid ověřuje, že data odeslaná ve formuláři lze použít k úpravě (úpravě nebo aktualizaci) objektu Movie . Pokud jsou data platná, uloží se data videa do Movies kolekce db(MovieDBContext instance. Nová data videa jsou uložena do databáze voláním SaveChanges metody MovieDBContext. Po uložení dat kód přesměruje uživatele na Index metodu MoviesController akce třídy, která zobrazí kolekci filmů včetně právě provedených změn.

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:

pokud chcete podporovat ověřování jQuery pro neanglické národní prostředí používající čárku (",") pro desetinnou čárku, musíte zahrnout globalize.js a konkrétní jazykové verze/globalize.cultures.js file(from https://github.com/jquery/globalize ) a JavaScript, aby bylo možné použít Globalize.parseFloat . Následující kód ukazuje úpravy souboru Views\Movies\Edit.cshtml pro práci s jazykovou verzí "fr-FR":

@section Scripts {
    @Scripts.Render("~/bundles/jqueryval")
    <script src="~/Scripts/globalize.js"></script>
    <script src="~/Scripts/globalize.culture.fr-FR.js"></script>
    <script>
        $.validator.methods.number = function (value, element) {
            return this.optional(element) ||
                !isNaN(Globalize.parseFloat(value));
        }
        $(document).ready(function () {
            Globalize.culture('fr-FR');
        });
    </script>
    <script>
        jQuery.extend(jQuery.validator.methods, {    
            range: function (value, element, param) {        
                //Use the Globalization plugin to parse the value        
                var val = $.global.parseFloat(value);
                return this.optional(element) || (
                    val >= param[0] && val <= param[1]);
            }
        });

    </script>
}

Desetinné pole může vyžadovat čárku, nikoli desetinnou čárku. Jako dočasnou opravu můžete přidat element globalizace do kořenového souboru web.config projektů. Následující kód ukazuje element globalizace s jazykovou verzí nastavenou na USA angličtina.

<system.web>
    <globalization culture ="en-US" />
    <!--elements removed for clarity-->
  </system.web>

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ěla být bezpečná operace, která nemá žádné vedlejší účinky a neupravuje trvalá data.

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 zadat, aby mohl hledat 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)); 
}

Výše s => s.Title uvedený kód je výraz lambda. Lambda se používají v dotazech LINQ založených na metodách jako argumenty pro standardní metody operátoru dotazu, jako je například metoda Where použitá ve výše uvedeném kódu. 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, sada Visual Studio automaticky vygenerovala (vygenerovala) v zobrazení některé výchozí revize. 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}

Původní SearchIndex metoda vypadá takto:

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); 
}

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")<br />  
         <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.

Snímek obrazovky se spuštěním aplikace a pokusem o vyhledání videa

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 že by měla být směrována 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 není prázdný, kód dále omezuje 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("SearchIndex","Movies",FormMethod.Get)){     
         <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í.

Snímek obrazovky se spuštěním aplikace a pokusem o hledání podle názvu filmu žánru a 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.