Enkeltsideapplikation: KnockoutJS-mall

Knockout MVC-mallen är en del av ASP.NET och webbverktyg 2012.2

Ladda ned ASP.NET och webbverktyg 2012.2

Uppdateringen ASP.NET och Web Tools 2012.2 innehåller en Single-Page-mall (SPA) för ASP.NET MVC 4. Den här mallen är utformad för att komma igång med att snabbt skapa interaktiva webbappar på klientsidan.

"Enkelsidigt program" (SPA) är den allmänna termen för ett webbprogram som läser in en enda HTML-sida och sedan uppdaterar sidan dynamiskt, i stället för att läsa in nya sidor. Efter den första sidinläsningen pratar SPA med servern via AJAX-begäranden.

Diagram som visar två rutor med etiketten Klient och Server. En pil med etiketten AJAX går från klient till server. En pil med etiketten H T M L och en pil med etiketten J SON går från Server till Klient.

AJAX är inget nytt, men idag finns det JavaScript-ramverk som gör det enklare att bygga och underhålla ett stort avancerat SPA-program. Dessutom gör HTML 5 och CSS3 det enklare att skapa omfattande UIs.

För att komma igång skapar SPA-mallen ett exempelprogram med "Att göra-listan". I den här handledningen tar vi en guidad rundtur i mallen. Först ska vi titta på själva att göra-listprogrammet och sedan undersöka de teknikdelar som får det att fungera.

Skapa ett nytt SPA-mallprojekt

Krav:

  • Visual Studio 2012 eller Visual Studio Express 2012 för webben
  • ASP.NET Web Tools 2012.2-uppdatering. Du kan installera uppdateringen här.

Starta Visual Studio och välj Nytt projekt på startsidan. Eller så väljer du NyttArkiv-menyn och sedan Projekt.

I fönstret Mallar väljer du Installerade mallar och expanderar noden Visual C# . Under Visual C# väljer du Webb. I listan över projektmallar väljer du ASP.NET MVC 4-webbprogram. Namnge projektet och klicka på OK.

Skärmbild som visar dialogrutan Nytt projekt. En S P-punkt NET M V C 4-webbapp väljs från listan över webbmallar.

I guiden Nytt projekt väljer du Enkelsidigt program.

Skärmbild som visar dialogrutan för Nytt A S P dot NET M V C 4-projekt. Ensidesprogram-mallen är markerad.

Tryck på F5 för att skapa och köra programmet. När programmet körs första gången visas en inloggningsskärm.

Skärmbild som visar inloggningsskärmen Min att göra-lista.

Klicka på länken "Registrera dig" och skapa en ny användare.

Skärmbild som visar skärmen Registrera dig.

När du har loggat in skapar programmet en todo-standardlista med två objekt. Du kan klicka på "Lägg till att göra-lista" för att lägga till en ny lista.

Skärmbild som visar två Att göra-listor och knappen Lägg till att göra-lista överst.

Byt namn på listan, lägg till objekt i listan och markera dem. Du kan också ta bort objekt eller ta bort en hel lista. Ändringarna sparas automatiskt i en databas på servern (i själva verket LocalDB just nu, eftersom du kör programmet lokalt).

Skärmbild som visar en lista med tre objekt. Det sista objektet är markerat och har en genomstrykning.

Arkitektur för SPA-mallen

Det här diagrammet visar de viktigaste byggstenarna för programmet.

Diagram som visar de separata byggstenarna i Klient och Server. Knockout dot j s, H T M L och J SON är under Klient. A S P-punkt NET M V C, A S P-punkt NET Web A P I, Entity Framework och Databas finns under Server.

På serversidan hanterar ASP.NET MVC HTML och hanterar även formulärbaserad autentisering.

ASP.NET webb-API hanterar alla begäranden som är relaterade till ToDoLists och ToDoItems, inklusive att hämta, skapa, uppdatera och ta bort. Klienten utbyter data med webb-API i JSON-format.

Entity Framework (EF) är O/RM-lagret. Den förmedlar mellan det objektorienterade världen av ASP.NET och den underliggande databasen. Databasen använder LocalDB, men du kan ändra detta i filen Web.config. Vanligtvis använder du LocalDB för lokal utveckling och distribuerar sedan till en SQL-databas på servern med hjälp av EF Code-First-migrering.

På klientsidan hanterar Knockout.js-biblioteket siduppdateringar från AJAX-begäranden. Knockout använder databindning för att synkronisera sidan med de senaste data. På så sätt behöver du inte skriva någon av koden som går igenom JSON-data och uppdaterar DOM. I stället placerar du deklarativa attribut i HTML-koden som talar om för Knockout hur data ska presenteras.

En stor fördel med den här arkitekturen är att den separerar presentationsskiktet från programlogik. Du kan skapa webb-API-delen utan att veta något om hur webbsidan kommer att se ut. På klientsidan skapar du en "vymodell" för att representera dessa data, och vymodellen använder Knockout för att binda till HTML. Det gör att du enkelt kan ändra HTML-koden utan att ändra vymodellen. (Vi tittar på Knockout lite senare.)

Modeller

I Visual Studio-projektet innehåller mappen Modeller de modeller som används på serversidan. (Det finns även modeller på klientsidan. Vi kommer till dem.)

Skärmbild som visar mappen Modeller öppen.

TodoItem, TodoList

Det här är databasmodellerna för Entity Framework Code First. Observera att dessa modeller har egenskaper som pekar på varandra. ToDoList innehåller en samling ToDoItems, och varje ToDoItem har en referens tillbaka till sin föräldra-ToDoList. Dessa egenskaper kallas navigeringsegenskaper och representerar en-till-många-relationen mellan en att-göra-lista och dess att-göra-objekt.

Klassen ToDoItem använder också attributet [ForeignKey] för att ange att det ToDoListId är en sekundärnyckel i ToDoList tabellen. Detta instruerar EF att lägga till en främmande nyckelbegränsning i databasen.

[ForeignKey("TodoList")]
public int TodoListId { get; set; }
public virtual TodoList TodoList { get; set; }

TodoItemDto, TodoListDto

Dessa klasser definierar de data som ska skickas till klienten. "DTO" står för "dataöverföringsobjekt". DTO definierar hur entiteterna ska serialiseras till JSON. I allmänhet finns det flera orsaker till att använda DTU:er:

  • För att styra vilka egenskaper som serialiseras. DTO:en kan innehålla en delmängd av egenskaperna från domänmodellen. Du kan göra detta av säkerhetsskäl (för att dölja känsliga data) eller bara för att minska mängden data som du skickar.
  • Om du vill ändra formen på data – t.ex. för att platta ut en mer komplex datastruktur.
  • För att hålla all affärslogik borta från DTO:n (separation av ansvar).
  • Om dina domänmodeller inte kan serialiseras av någon anledning. Cirkelreferenser kan till exempel orsaka problem när du serialiserar ett objekt Det finns sätt att hantera det här problemet i webb-API :et (se Hantera cirkelobjektreferenser); men att använda en DTO undviker helt enkelt problemet helt och hållet.

I SPA-mallen innehåller DTU:erna samma data som domänmodellerna. De är dock fortfarande användbara eftersom de undviker cirkelreferenser från navigeringsegenskaperna och visar det allmänna DTO-mönstret.

AccountModels.cs

Den här filen innehåller modeller för webbplatsmedlemskap. Klassen UserProfile definierar schemat för användarprofiler i medlemskapsdatabasen. (I det här fallet är den enda informationen användar-ID:t och användarnamnet.) De andra modellklasserna i den här filen används för att skapa användarregistrerings- och inloggningsformulären.

Entity Framework

SPA-mallen använder EF Code First. I Kod första utveckling definierar du modellerna först i kod och sedan använder EF modellen för att skapa databasen. Du kan också använda EF med en befintlig databas (Database First).

Klassen TodoItemContext i mappen Models härleds från DbContext. Den här klassen tillhandahåller "limmet" mellan modellerna och EF. TodoItemContext håller en ToDoItem-samling och en TodoList-samling. Om du vill köra frågor mot databasen skriver du bara en LINQ-fråga mot dessa samlingar. Här är till exempel hur du kan välja alla to-do listor för användaren "Alice":

TodoItemContext db = new TodoItemContext();
IEnumerable<TodoList> lists = 
    from td in db.TodoLists where td.UserId == "Alice" select td;

Du kan också lägga till nya objekt i samlingen, uppdatera objekt eller ta bort objekt från samlingen och spara ändringarna i databasen.

ASP.NET webb-API-styrenheter

I ASP.NET webb-API är kontrollanter objekt som hanterar HTTP-begäranden. Som nämnts använder SPA-mallen webb-API för att aktivera CRUD-åtgärder på ToDoList och ToDoItem instanser. Kontrollanterna finns i mappen Controllers i lösningen.

Skärmbild som visar mappen Controllers öppen. Filnamnen

  • TodoController: Hanterar HTTP-begäranden för to-do objekt
  • TodoListController: Hanterar HTTP-begäranden för to-do listor.

Dessa namn är viktiga eftersom webb-API:et matchar URI-sökvägen till kontrollantnamnet. (Information om hur webb-API dirigerar HTTP-begäranden till kontrollanter finns i Routning i ASP.NET webb-API.)

Låt oss titta på ToDoListController klassen. Den innehåller en enskild datamedlem:

private TodoItemContext db = new TodoItemContext();

TodoItemContext Används för att kommunicera med EF enligt beskrivningen tidigare. Metoderna på kontrollanten implementerar CRUD-åtgärderna. Webb-API mappar HTTP-begäranden från klienten till kontrollantmetoder på följande sätt:

HTTP-begäran Kontrollantmetod Beskrivning
GET /api/todo GetTodoLists Hämtar en samling to-do listor.
GET /api/todo/id GetTodoList Hämtar en att göra-lista via ID
PUT /api/todo/id PutTodoList Uppdaterar en att-göra-lista.
POST /api/todo PostTodoList Skapar en ny to-do lista.
DELETE /api/todo/id DeleteTodoList Tar bort en TODO-lista.

Observera att URI:erna för vissa åtgärder innehåller platshållare för ID-värdet. Om du till exempel vill ta bort en till-lista med ett ID på 42 är URI:n /api/todo/42.

Mer information om hur du använder webb-API för CRUD-åtgärder finns i Skapa ett webb-API som stöder CRUD-åtgärder. Koden för den här kontrollanten är ganska enkel. Här är några intressanta punkter:

  • Metoden GetTodoLists använder en LINQ-fråga för att filtrera resultatet efter ID:t för den inloggade användaren. På så sätt ser en användare bara de data som tillhör honom eller henne. Observera också att en Select-instruktion används för att konvertera ToDoList instanserna till TodoListDto instanser.
  • PUT- och POST-metoderna kontrollerar modelltillståndet innan du ändrar databasen. Om ModelState.IsValid är falskt returnerar dessa metoder HTTP 400, felaktig begäran. Läs mer om modellverifiering i webb-API på modellverifiering.
  • Kontrollantklassen är också dekorerad med attributet [Auktorisera]. Det här attributet kontrollerar om HTTP-begäran autentiseras. Om begäran inte autentiseras tar klienten emot HTTP 401, Obehörig. Läs mer om autentisering vid autentisering och auktorisering i ASP.NET webb-API.

Klassen TodoController är mycket lik TodoListController. Den största skillnaden är att den inte definierar några GET-metoder, eftersom klienten får to-do objekt tillsammans med varje to-do lista.

MVC-kontroller och vyer

MVC-styrenheterna finns också i mappen Controllers i lösningen. HomeController renderar huvud-HTML för programmet. Vyn för startkontrollanten definieras i Views/Home/Index.cshtml. Vyn Start renderar olika innehåll beroende på om användaren är inloggad:

@if (@User.Identity.IsAuthenticated)
{
    // ....
}

När användare är inloggade ser de huvudgränssnittet. Annars visas inloggningspanelen. Observera att den här villkorliga återgivningen sker på serversidan. Försök aldrig att dölja känsligt innehåll på klientsidan – allt som du skickar i ett HTTP-svar är synligt för någon som tittar på råa HTTP-meddelanden.

Client-Side JavaScript och Knockout.js

Nu ska vi gå från serversidan av programmet till klienten. SPA-mallen använder en kombination av jQuery och Knockout.js för att skapa ett smidigt, interaktivt användargränssnitt. Knockout.js är ett JavaScript-bibliotek som gör det enkelt att binda HTML till data. Knockout.js använder ett mönster med namnet "Model-View-ViewModel".

  • Modellen är domändata (ToDo-listor och ToDo-objekt).
  • Vyn är HTML-dokumentet.
  • View-model är ett JavaScript-objekt som innehåller modelldata. Vymodellen är en kodabstraktion av användargränssnittet. Den har ingen kunskap om HTML-representationen. I stället representerar den abstrakta funktioner i vyn, till exempel "en lista över ToDo-objekt".

Vyn är databunden till view-model. Uppdateringar av vymodellen återspeglas automatiskt i vyn. Bindningar fungerar också åt andra hållet. Händelser i DOM (till exempel klick) är databundna till funktioner i vymodellen, som utlöser AJAX-anrop.

SPA-mallen organiserar JavaScript på klientsidan i tre lager:

  • todo.datacontext.js: Skickar AJAX-begäranden.
  • todo.model.js: Definierar modellerna.
  • todo.viewmodel.js: Definierar vymodellen.

Diagram som visar en pil som går från Knockout dot j s till Visa modell till Modeller till Datakontext. Pilen mellan Knockout dot j s och View Model är märkt databindning och pekar på båda objekten.

Dessa skriptfiler finns i mappen Skript/app i lösningen.

Skärmbild som visar den undermappsmärkta appen öppen.

todo.datacontext hanterar alla AJAX-anrop till webb-API-kontrollanterna. (AJAX-anrop för inloggning definieras någon annanstans, i ajaxlogin.js.)

todo.model.js definierar klientsidans modeller (webbläsare) för to-do-listorna. Det finns två modellklasser: todoItem och todoList.

Många av egenskaperna i modellklasserna är av typen "ko.observable". Observables är hur Knockout utför sin magi. Från knockout-dokumentationen: Ett observerbart är ett "JavaScript-objekt som kan meddela prenumeranter om ändringar". När värdet för en observerbar ändring uppdateras alla HTML-element som är bundna till dessa observerbara element. TodoItem har till exempel observerbara objekt för rubriken och isDone-egenskaper:

self.title = ko.observable(data.title);
self.isDone = ko.observable(data.isDone);

Du kan också prenumerera på en observerbar kod. Till exempel prenumererar klassen todoItem på ändringar i egenskaperna "isDone" och "title":

saveChanges = function () {
    return datacontext.saveChangedTodoItem(self);
};

// Auto-save when these properties change
self.isDone.subscribe(saveChanges);
self.title.subscribe(saveChanges);

View Model

Vymodellen definieras i todo.viewmodel.js. Vymodellen är den centrala punkten där programmet binder HTML-sidelementen till domändata. I SPA-mallen innehåller vymodellen en observerbar matris med todoLists. Följande kod i vymodellen säger till Knockout att tillämpa bindningarna:

ko.applyBindings(window.todoApp.todoListViewModel);

HTML och databindning

Huvud-HTML för sidan definieras i Views/Home/Index.cshtml. Eftersom vi använder databindning är HTML bara en mall för det som faktiskt renderas. Knockout använder deklarativa bindningar. Du binder sidelement till data genom att lägga till ett "databindning"-attribut till elementet. Här är ett mycket enkelt exempel som tas från Knockout-dokumentationen:

<p>There are <span data-bind="text: myItems().count"></span> items<p>

I det här exemplet uppdaterar Knockout innehållet i <span-elementet> med värdet myItems.count(). När det här värdet ändras uppdaterar Knockout dokumentet.

Knockout innehåller ett antal olika bindningstyper. Här är några av de bindningar som används i SPA-mallen:

  • foreach: Låter dig iterera genom en loop och tillämpa samma markering på varje objekt i listan. Detta används för att återge att-göra-listor och att-göra-punkter. Inom foreach tillämpas bindningarna på elementen i listan.
  • synlig: Används för att växla synlighet. Dölj markering när en samling är tom eller gör felmeddelandet synligt.
  • värde: Används för att fylla i formulärvärden.
  • klicka: Binder en klickhändelse till en funktion i vymodellen.

Skydd mot CSRF

Förfalskning av begäranden mellan webbplatser (CSRF) är ett angrepp där en skadlig webbplats skickar en begäran till en sårbar webbplats där användaren för närvarande är inloggad. För att förhindra CSRF-attacker använder ASP.NET MVC antiförfalskningstoken, även kallat verifieringstoken för begäran. Tanken är att servern placerar en slumpmässigt genererad token på en webbsida. När klienten skickar data till servern måste den inkludera det här värdet i begärandemeddelandet.

Anti-förfalskningstoken fungerar eftersom den skadliga sidan inte kan läsa användarens token på grund av same-origin-policy. (Principer för samma ursprung hindrar dokument som finns på två olika webbplatser från att komma åt varandras innehåll.)

ASP.NET MVC har inbyggt stöd för antiförfalskningstoken, via klassen AntiForgery och attributet [ValidateAntiForgeryToken]. För närvarande är den här funktionen inte inbyggd i webb-API:et. SPA-mallen innehåller dock en anpassad implementering för webb-API:et. Den här koden definieras i ValidateHttpAntiForgeryTokenAttribute klassen, som finns i mappen Filter i lösningen. Mer information om anti-CSRF i Web API finns i Förhindra förfalskning av begäranden mellan webbplatser (CSRF)-attacker.

Conclusion

SPA-mallen är utformad för att komma igång med att snabbt skriva moderna, interaktiva webbprogram. Det använder Knockout.js-biblioteket för att separera presentation (HTML-kod) från data- och programlogik. Men Knockout är inte det enda JavaScript-bibliotek som du kan använda för att skapa ett SPA. Om du vill utforska några andra alternativ kan du ta en titt på de community-skapade SPA-mallarna.