ASP.NET MVC Futures – Gör applikationen dynamisk
Det är inte mycket som är klart angående ASP.NET MVC 3, men en sak som de har gått ut med är att det kommer att kräva .NET 4.0. För oss utvecklare så betyder det att så fort det handlar om ett ASP.NET MVC 3-projekt så kommer vi att kunna använda oss utav funktioner som dynamic, optional/named parameters, ASP.NET Charting, nya koblocket för HtmlEncode och mycket annat.
Om vi ser på ASP.NET MVC Futures så kan vi se att en av dessa saker finns med på ett antal ställen – nämligen dynamic. Bland annat så finns det en ny ViewPage-klass kallad DynamicViewPage, vilken jag kommer att ta upp strax.
För att kunna testa exemplen nedan så bör du ha tillgång till Visual Studio 2010 (RC eller senare), ASP.NET MVC 2 RTM samt ASP.NET MVC 2 RTM Futures.
Det första vi gör är att skapa upp en controller vid namn ”DynamicController”. Sedan skapar vi en vy för Index-metoden. Vyn ska inte vara hårt kodad mot någon modell, och skall inte ha någon speciell template.
Vyn skall sedan inte ärva från vanliga ViewPage, utan istället DynamicViewPage. Den finns under:
Microsoft.Web.Mvc.AspNet4.DynamicViewPage
Det vi har nu är alltså controllern:
using System.Web.Mvc;
namespace MvcFuturesWeb.Controllers
{
public class DynamicController : Controller
{
// GET: /Dynamic/
public ActionResult Index()
{
return View();
}
}
}
Och vyn:
<%@ Page Language="C#" MasterPageFile="~/Views/Shared/Site.Master"
Inherits="Microsoft.Web.Mvc.AspNet4.DynamicViewPage" %>
<asp:Content ID="Content2" ContentPlaceHolderID="MainContent" runat="server">
<h2>Index</h2>
</asp:Content>
Det är alltså en väldigt enkel controller och en väldigt enkel vy. Enda skillnaden mot vanligt är att vi nu ärver DynamicViewPage i vyn.
Så vad är det för speciellt med DynamicViewPage, och varför skulle man vilja ha den?
Det finns två olika varianter av DynamicViewPage, dels den som vi använder här, men även en som är generisk (DynamicViewPage<TModel>).
Skillnaden mellan dessa är att den som vi använder har två dynamiska propertys, Model och ViewData. Den generiska varianten har dock enbart en dynamisk ViewData. De ärver sedan ViewPage, respektive ViewPage<TModel>, vilket gör att de har alla vanliga metoder som dessa har.
I dessa metoder så anropas sedan DynamicViewDataDictionary.Wrap(…), vilket är en intern klass som ärver DynamicObject. Den använder sig utav en ViewDataDictionary, men implementerar även stöd för bland annat TryGetMember.
När ViewData och/eller Model skickas in i Wrap-metoden så mappas de om till ett DynamicViewDataDictionary och returneras som dynamic.
Det här leder till att vi har en vy med dynamisk Model samt ViewData. För att dra nytta av det här så börjar vi med att lägga till ett värde i ViewData. I Controllern så använder vi vanliga ViewData-klassen och sätter ett värde på samma sätt som vi annars hade gjort.
ViewData["Test"] = "Hello!";
När vi sedan hämtar värdet så är det ett dynamiskt Dictionary, vilket gör att vi kan hämta det med:
<%=ViewData.Test %>
Vi kan även använda oss utav en dynamisk modell då vi inte använder den generiska DynamicViewPage. För det så använder vi ExpandoObject.
dynamic d = new ExpandoObject();
d.Hej = "Hopp";
d.Hello = "Jump";
return View(d);
Då vyn nu är dynamisk så kan vi hämta värdena på följande sätt:
<%=Model.Hej %>
Det går även att gå ett steg längre. Då vår dynamiska modell returnerar ett Dictionary så kan vi loopa igenom alla värden i modellen och skriva ut.
<% foreach (var d in Model) { %>
<li><%=d.Key + " " + d.Value %></li>
<% } %>
</ul>
Resultatet efter dessa ändringar är:
Genom att använda DynamicViewPage så är vi alltså helt oberoende av vilken typ som skickas in till vyn, vilket gör att det inte finns någon som helst koppling mellan den och controllern.
Det är även möjligt att använda dynamiska objekt för andra typer av vyer. Om vi ändrar från:
return View(d);
Till:
return Json(d, JsonRequestBehavior.AllowGet);
Så får vi istället det här returnerat:
[{"Key":"Hej","Value":"Hopp"},{"Key":"Hello","Value":"Jump"}]
Vi får alltså en Json-sträng med vårt dynamiska objekt. Då det är en dictionary så får vi dock tvådelade värden (Key och Value som separata värden), men det kan komma att ändras framöver.