|
Asp.Net MVC rust voornamelijk op conventies en veel minder op XML configuratie. De configuratie wordt niet meer afgedwongen met XSD's. Dit maakt het voor ontwikkelaars prettiger om te ontwikkelen want dit is dus WYSIWYG de architectuur ontwikkelen (de project mappenstructuur is de architectuur) maar we moeten ook de ‘onzichtbare' conventies leren kennen.
|
|
De belangrijkste conventie is de synchronisatie tussen controller methodes (ook wel actions genaamd) en de bijbehorende views. Gelukkig heeft Visual Studio 2010 standaard ondersteuning voor het genereren van Views en Controllers via templates. Dit neemt veel werk uit handen want het uittypen van een view is veel werk en foutgevoelig.
Daarom gebruiken we de Add View en Add Controller wizard.
Maar helaas zijn de gegenereerde templates niet echt maatwerk. Zo ontbeert de standaard Controller template de ondersteuning van een repository (zie ook mijn vorige blog) . En ook zijn er standaard geen ActionFilters voor het opvangen van foutmeldingen en Authorisatie.
Ook aan de gegenereerde Views valt wel wat aan te merken. Ik vind het wel prettig als de cursor al op het eerste invoerveld is geplaatst. Ook zou ik iedere submit graag nogmaals door de gebruiker bevestigd willen zien.
Bij Views met een HTML Table zou ik graag een correcte THead en een TBody gebruikt zien worden. Dan wordt de header regel niet meegeteld bij de zebra formattering (de even rijen krijgen dan een andere achtergrondkleur dan de oneven rijen.)
Ik gebruik hiervoor nog al wat zelf geschreven jQuery code en/of jQuery plugins (zoals de confirm plugin en een gesorteerde tabel)
Ik wilde dus mijn templates aanpassen en dat blijkt heel goed mogelijk te zijn! Ik kwam er achter via de vermakelijke en zeer onderhoudende presentatie Microsoft ASP.NET Model View Controller (MVC): Ninja on Fire Black Belt Tips
Dus ik heb dit eens geprobeerd en inderdaad, het werkt echt fantastisch! En het is een klusje van slechts enkele minuten!
Zorg dat je het installatiepad van Visual Studio 2010 kent. Ga dan naar:
- [drive]\Program Files\Microsoft Visual Studio 10.0\Common7\IDE\ItemTemplates\CSharp\Web\MVC 2\CodeTemplates\AddController
of
- [drive]\Program Files\Microsoft Visual Studio 10.0\Common7\IDE\ItemTemplates\VisualBasic\Web\MVC 2\CodeTemplates\AddController .
Deze zal wel voor de VB.Net collega's zijn?
Maak daar een copy van de controller template:
- naar [project]\ CodeTemplates\AddController\Controller.tt
Let op: er is maar 1 controller template. Wees dus zuinig op het origineel.
Ga daarna naar:
- C:\Program Files\Microsoft Visual Studio 10.0\Common7\IDE\ItemTemplates\CSharp\Web\MVC 2\CodeTemplates\AddView
En maak een copy van de view templates:
- naar [project]\ CodeTemplates\AddController\ Create.tt
- naar [project]\ CodeTemplates\AddController\ Details.tt
- naar [project]\ CodeTemplates\AddController\ Edit.tt
- naar [project]\ CodeTemplates\AddController\ List.tt
Maak tevens een copy van iedere view template:
- naar [project]\ CodeTemplates\AddController\ ProjectCreate.tt
- naar [project]\ CodeTemplates\AddController\ ProjectDetails.tt
- naar [project]\ CodeTemplates\AddController\ ProjectEdit.tt
- naar [project]\ CodeTemplates\AddController\ ProjectList.tt
We zijn al op de helft. Voeg nu eens voor de grap een view toe aan je project:
Zie je dat de nieuwe View templates al direct te selecteren zijn?
Maar nu gaan we de inhoud aanpassen. Voeg eerst nog even T4 IntelliSence ondersteuning toe aan VS2010 via de Extension Manager:
Zie ook http://tangibleengineering.blogspot.com/2009/05/tangible-t4-editor-now-listed-in-visual.html
In deze blog wordt beperkt ingegaan op T4. Voor wie echt in T4 wilt duiken kan beter doorverwezen worden naar deze link.
Ok, we hebben nu dus een T4 editor binnen Visual Studio 2010 beschikbaar met IntelliSence.
Maar waar waren we gebleven. O ja, dus we willen Repository ondersteuning binnen de Controller:
|
... using System.Web.Mvc;
using MyProject.Models;
namespace <#= mvcHost.Namespace #> { // todo: move this interface to /Repository/<#= mvcHost.ControllerRootName #> public interface I<#= mvcHost.ControllerRootName #>Repository { }
// todo: move this class to /Repository/<#= mvcHost.ControllerRootName #> public class <#= mvcHost.ControllerRootName #>Repository : I<#= mvcHost.ControllerRootName #>Repository { private IMyProjectEntities _MyProjectEntities;
private IMembershipService _MembershipService;
public <#= mvcHost.ControllerRootName #>Repository() : this(new MyProjectEntities(), new AccountMembershipService()) { }
public <#= mvcHost.ControllerRootName #>Repository(IMyProjectEntities myProjectEntities, IMembershipService accountMembershipService) { _MyProjectEntities = myProjectEntities;
_MembershipService = accountMembershipService; } }
[HandleError] [Authorize()] public class <#= mvcHost.ControllerName #> : Controller { ... |
Door deze tekst aan te passen in de Controller template worden opeens Repository ondersteuning ‘afgedwongen'. In ieder geval wordt het handmatig aanpassen van de code sterk beperkt.
Let op: Zie dat de gegeneerde Interface en Repository class wel nog in een aparte map geplaatst moeten worden.
Ik kan in deze templates direct verwijzen naar _MyProjectEntities want deze template is alleen toepasbaar voor gebruik binnen dit project.
Hetzelfde willen we voor de Views:
|
... <asp:Content ID="Content<#= CPHCounter #>" ContentPlaceHolderID="<#= mvcHost.PrimaryContentPlaceHolderID #>" runat="server">
<script src="http://code.jquery.com/jquery-latest.js" type="text/javascript"></script> <script src="<%= Url.Content("~/jQuery/confirmplugin.js") %>" type="text/javascript"></script>
<script type="text/javascript"> $(document).ready(function () { $("form :input[type='text']:enabled:first").focus();
$('input[type=submit]').confirm({ msg: 'Are you sure?', timeout: 10000 }); }); </script>
<h2><#= mvcHost.ViewName #></h2> ... <% using (Html.BeginForm()) {%>
<%= Html.ValidationSummary(true, "Creation failed. Please check the fields.") %>
<fieldset> ... |
Met het toevoegen van bovenstaande code is opeens jQuery ondersteuning beschikbaar om de cursor binnenin het eerste tekst-invoerveld te plaatsen en er zal een bevestiging gevraagd worden bij het indrukken van een Submit knop. Ook laat ik nu een ValidationSummary aanmaken want die is standaard niet aanwezig.
Let op: De JQuery import zou ook via een MasterPage kunnen gebeuren maar ik heb dit ter illustratie hier toegevoegd.
Het aanpassen va de Index template (List.TT) voor THead en TBody en Zebra strepen in een tabel is zodoende ook erg triviaal geworden:
|
...
<script src="http://code.jquery.com/jquery-latest.js" type="text/javascript"></script> <script type="text/javascript" charset="utf-8"> // Laden $(document).ready(function () { $('tbody tr:odd', this).removeClass('even').addClass('odd'); $('tbody tr:even', this).removeClass('odd').addClass('even'); }); </script>
<h2><#= mvcHost.ViewName #></h2> ...
<table> <thead> <tr> <th></th> <# foreach(KeyValuePair<string, string> property in properties) { #> <th> <#= property.Key #> </th> <# } #> </tr> </thead> <tbody> <% foreach (var item in Model) { %>
...
<% } %>
</tbody> </table> ... |
Dus met deze simpele aanpassingen zijn de templates volledig naar onze hand te zetten. Maar pas op! Er bestaat een risico dat we nu juist te veel in onze controllers en view gaan oplossen. Plaats geen oneigenlijke logica in deze programmaonderdelen. Je kunt beter Fat Model, skinny Controllers nastreven.
Veel succes met het genereren.
Share this | 440 keer bekeken | 0 reacties




