Liever lui dan moe: combineer MVC2 met Dynamic Data Web App

Bij mijn huidige MVC2 project zijn we in de testfase aanbeland. En we zitten
nu met een dilemma.

Hoewel MVC2 vooral voor CRUD applicaties toegepast zal worden, hoeft dit nog niet te betekenen dat ook alle vier de acties: create, read, update en delete geïmplementeerd gaan worden. De daadwerkelijke functionaliteit van de applicatie bepaalt namelijk wat er met de data gebeurt.

Lui

Dit maakt het functioneel testen dus niet eenvoudiger. Een applicatie welke alleen invoegen, wijzigen en tonen ondersteunt is heel erg cru (..) voor de tester. Hoe kan de functionaliteit getest worden rond het representeren van een lege selectie of tabel? Wat zal een gridview tonen: “geen data aanwezig”? Of zal er een foutmelding getoond worden? Dit is lastig te testen zonder dat de mogelijkheid bestaat om ook eens een record te verwijderen. Hetzelfde geldt voor het wijzigen van records waarvoor alleen invoeg-functionaliteit is geboden.

Daarom heb ik even een onderzoekje gedaan of ik een Dynamic Data Web
Application (DDWA) hiervoor kom toepassen. Ik heb hier in het verleden al eens over geblogd en dit leek mij wel weer een poging waard.

Nou, om kort te gaan, het kan en het is bijzonder eenvoudig.

Open dus eerst de VS2010 solution met daarin jouw MVC2 applicatie.
Voeg dan een DDWA project toe, in dit geval eentje voor het Entity
framework.

Voeg DDWA toe

In de meeste MVC2 applicaties is de Entity Framework context binnen
die applicatie gecreëerd. Voeg dus een referentie toe van het MVC2 project aan
het DDWA project.

Onthoudt nog even wat de naam is van de context. In mijn geval was
dat “DatabaseEntities”.

In de global.asax van moet vervolgens die regel uit het commentaar
gehaald worden en voorzien worden van de context naam:


DefaultModel.RegisterContext(typeof(DatabaseEntities), new
ContextConfiguration() { ScaffoldAllTables = true });

Standaard staat ScaffoldAllTables op false. Zet deze op true. Dit
forceert dat alle tabellen standaard beschikbaar zijn voor onderhoud via deze
DDWA applicatie.

Als laatste moet wel dezelfde database aangeroepen worden. Kopieer
dus de Entity Framework connectionstring uit de MVC2 applicatie en plaats deze
in de DDWA web.config:

<connectionStrings>

<add    

name=”DatabaseEntities”

connectionString=”metadata=res://*/Models.Model1.csdl|res://*/Models.Model1.ssdl|

res://*/Models.Model1.msl;provider=System.Data.SqlClient;

provider connection string=&quot;Integrated Security=SSPI;Persist
Security Info=False;

Initial Catalog=DATABASE.MDF;Data
Source=.\sqlexpress&quot;”

providerName=”System.Data.EntityClient”/>

</connectionStrings>

Let op, de database moet via een server gedeeld worden. Het
dynamisch koppelen van een Sql Server Express database (b.v. “Data
Source=.\SQLEXPRESS;AttachDbFilename=|DataDirectory|\Database1.mdf” ) werkt niet en zal bij de DDWA tot een vage foutmelding leiden.

En dat is alles. Makkelijk.

Nu kan via de DDWA applicatie snel onderhoud gepleegd worden op de (test) database. En nu kan ook snel inzichtelijk gemaakt worden hoe de ingevoerde informatie in de database opgeslagen wordt. Handig toch?

Gebruik geen Dynamic Data Web Application projecten?

Na enkele maanden in beta te zijn geweest, is er nu eindelijk Visual Studio
2008 Service pack 1. Op zich waren veel features al bekend maar de beta had ik
laten schieten en dus ben ik best onder de indruk van wat er allemaal in zit.
Wil je het allemaal nog eens nalezen dan mag je best wel de tijd nemen. Na drie pogingen en enkele uren installeren (tijd genoeg dus voor het leeswerk) stond het weer netjes op de harde schijf en het voelt dan toch een beetje alsof je een kadootje uitpakt.

Nu zit er genoeg in SP1 voor vele avonden uitzoekwerk maar ik wil hier het
Dynamic Data Web Application project bespreken. Het is een hele mond vol terwijl de project de eenvoud zelfe is / kan zijn.

Wat doet het dan? De DDWA genereert aan de hand van een opgegeven Entity Data Model context of een LINQ to SQL context voor alle opgegeven tabellen navigatie, gefilterde overzichten en CRUD onderhoudschermen. En dit alles is nog configurabel ook. Voordat u nu direct alle webontwikkeling wilt stilleggen, wil ik er toch even op wijzen dat dit niet de ‘silver bullet’ is. Zoals met veel
zaken moet ook dit met mate toegepast worden.

Na het starten van een DDWA project (voor LINQ to SQL) of de DDEWA
project (voor het Entity framework) zijn er maar twee handelingen nodig! Eerst
moet de database in een model gevangen worden. Genereer dus binnen het project voor een (SQL Server) database een ADO.NET Entity Data Model (Model.edmx) of een verzameling LINQ to SQL klassen (DataClasses.dbml). Voor beide handelingen is een wizard aanwezig dus daar kom je wel uit.

Dan start de magie: ga naar de Global.asax en haal het commentaar weg voor de
regel beginnende met model.RegisterContext.

model.RegisterContext(typeof(EntitiesContext),
  new ContextConfiguration() { ScaffoldAllTables = true }); // Let op: True

OF

model.RegisterContext(typeof(DataClassesDataContext),
  new ContextConfiguration() { ScaffoldAllTables = true }); // Let op: True

Een scaffold is een steiger. Door de ScaffoldAllTables waarde op true te
zetten worden automatisch alle in de context aangetroffen tabellen ‘in de
steigers’ gezet. Start de applicatie en zie wat er allemaal gegenereerd
wordt.

En ja, het ziet er aardig uit maar hoe pas je het in je project toe? Mijn
eerste gedacht is dat nu op een heel Agile manier het onderhoud van b.v.
stamtabellen toegevoegd kan worden aan het project. Dit betekent wel dat er een
tweede webapplicatie opgeleverd wordt maar er zijn mogelijkheden om een dynamic data website met maatwerk te combineren. Ook is het zo mogelijk om ‘power’ tester een simpel kijkje in de database keuken te geven. Hierbij wordt het dan ook mogelijk om b.v. bepaalde velden te wijzigen. Wellicht ideaal om toch te kunnen anti-dateren?

Wil je meer of minder tabellen zien, pas dan gewoon je context aan. Maar hoe
kunnen tabellen uit het onderhoudscherm weglaten worden welke in een bestaand model aanwezig zijn? Dit kan via het scaffolding (steigeren?) gedaan worden. De tabellen worden ieder door een entity vertegenwoordigd. Maak een partial class aan voor de tabel welke verborgen moet worden. Zet hierna op de klas het attribuut [ScaffoldTable(false)]. Er is overigens een aardige wisselwerking met ScaffoldAllTables om in te stellen welke tabellen wel en niet zichtbaar
zijn.

Als een kolom onzichtbaar gemaakt moet worden, is er net iets meer werk
nodig. Er is wel een attribute [ScaffoldColumn(false)] maar het is niet mogelijk
om op de partial class de eigenschap te herhalen om het attribuut daarop te
herhalen.

Hiervoor maken we eerst een extra klas aan met eenzelfde eigenschap als de te
verbergen kolom.

[ScaffoldTableAttribute(true)]  // steiger
public class EntiteitMetadata
{
  [ScaffoldColumn(false)]
  public Object Waarde { get; set; }
}

Deze klas is een meta beschrijving en wordt op de partial klas geplaatst via
het MetaDataType attribuut.

[MetadataType(typeof(EntiteitMetadata))]
public partial class Entiteit
{
  // plaats hier b.v. een property beschrijving met extra attributen
}

Binnen het project is in de map \DynamicData\FieldTemplates een verzameling
usercontrols opgenomen. Dit zijn de controls (default field templates) welke
gebruikt worden voor het representeren en onderhouden van de waarden in de
kolommen. Deze zijn te wijzigen maar die wijzigingen gelden dan voor alle
pagina’s in de gegenereerde website.

Er wordt bij Dynamic Data Web applicaties veel met conventies gewerkt. Voor
de field templates geldt dat templates, aanwezig met _Edit in de naam, specifiek
bij wijzigen van kolommen worden toegepast. De templates zonder _Edit zijn voor alleen-lezen gebruik.

Wat betreft conventies is het ook nog mogelijk om specifiek voor bepaalde
tabellen aparte schermen te definieren. Meer hierover wordt hier uitgelegd. Maar je kunt je hierbij al snel verliezen in het ‘goldplaten’ binnen het redelijk strikte keurslijf van de Dynamic Data Web application conventies.

Conclusie, wat een gouden greep lijkt om snel een user interface op te
leveren richting de klant kan al snel tegen je keren als je meer wilt dan alleen
maar wat data ophoesten. Zo is het lastig om data b.v. alleen maar readonly aan
te bieden. Maar al met al is het handig om functionaliteit voor het onderhoud
van stamtabellen hiermee op te leveren totdat deze typische adminstrator
schermen binnen het project een echte invulling hebben gekregen.