Breno Ferreira

Opniões e códigos de um desenvolvedor de software .NET.

Customizando os templates do MvcScaffolding

leave a comment »

Olá pessoal,

Muitos já devem ter usado, ou pelo menos ouvido falar do MvcScaffolding, uma ferramenta muito útil para nos ajudar a agilizar algumas tarefas digamos, tediosas, como criação de CRUDs. Se você não conhece, o Vinicius Quaiato tem dois posts no blog dele que explicam muito bem como você pode começar a utilizar a ferramenta.

Mas, as vezes, a funcionalidade padrão do MvcScaffolding não nos atende, e precisamos customizar o código gerado. Para fazermos isso, precisamos primeiramente, entender como que o código é gerado.

HowStuffWorks? – MvcScaffolding

O MvcScaffolding funciona utilizando duas tecnologias: T4 (Text Template Transformation Toolkit) Templates e Powershell. T4 Template, basicamente, é um código que gera código, e o alguns scripts Powershell utilizam esses templates para automatizar a geração do código que precisamos.

Por exemplo: o comando que executamos no Package Manager Console do Nuget, nada mais é do que um comando Powershell. Então, quando executamos o comando abaixo, estamos chamando um script Powershell que irá gerar o nosso código baseado nos arquivos T4 Templates apropriados.

Scaffold Controller Person –Repository
 

Se você for na pasta “%solution_folder%\packages\MvcScaffolding.1.0.0\tools”, você irá encontrar algumas pastas, e lá, voce irá encontrar alguns arquivos .ps1 e outros .t4. Esses arquivos que são utilizados quando executamos o Scaffolder que precisamos. No caso do comando acima, ele irá gerar o código baseado nos templates nas pastas: “Controller”, “RazorView” caso você esteja utilizando a Razor View Engine, ou “AspxView”, caso você esteja utilizando a WebForms View Engine.

Para podermos customizar o código gerado, há um comando do MvcScaffolding que automaticamente coloca o arquivo .t4 em uma pasta no nosso projeto. Assim, quando o Scaffolder for utilizar o template, ele irá utilizar este arquivo, e não o arquivo padrão localizado na pasta acima.

Customizando Templates T4

Para podermos customizar o arquivo .t4, basta executar o comando abaixo:

Scaffold CustomTemplate ScaffolderName TemplateName
 

Basta substituir o “ScaffolderName” e o “TemplateName” pelo template do Scaffolder que voce deseja customizar. Para isso, você pode ir na pasta onde estão localizados os templates (veja acima), ou então seguir a tabela abaixo:

ScaffolderName TemplateName
DbContext DbContext
DbContext DbContextEntityMember
Repository Repository
Action Action
Action ActionPost
Action ViewModel
ActionUnitTest TestClass
ActionUnitTest TestMethod
View Index, Create, _CreateOrEdit, Details, Edit, Delete, Empty,
Controller ControllerWithContext
Controller ControllerWithRepository

Após executar o comando, ele irá gerar um arquivo .t4 na seguinte pasta do nosso projeto:

“Code Templates\Scaffolders\<ScaffolderName>\<TemplateName>.t4”

Agora, basta editar este arquivo. A sintaxe é bem simples: os trechos que estiverem entre <#= #> irão ser executados para gerar um código de saída. Pense como uma ViewEngine do MVC, os blocos que estão com um @ (no caso do Razor) ou um <% %> (no caso do WebForms) são executados para gerar algum HTML. No template T4 é a mesma coisa, só a sintaxe que muda, e ao invés de gerar HTML, ele gera código C# (ou VB se dependendo da sua linguagem de preferência). Caso queira saber mais sobre a sintaxe dos T4 Templates, veja aqui na documentação da MSDN.

Como exemplo prático, criei um template customizado para a View Index, e substitui a <table> padrão por uma gerada utilizando o Helper WebGrid.

O código T4 ficou assim:

Antes:

   1: <table>

   2:     <tr>

   3:         <th></th>

   4: <#

   5: List<ModelProperty> properties = GetModelProperties(Model.ViewDataType, true);

   6: foreach (ModelProperty property in properties) {

   7:     if (!property.IsPrimaryKey && !property.IsForeignKey) {

   8: #>

   9:         <th>

  10:             <#= property.Name #>

  11:         </th>

  12: <#

  13:     }

  14: }

  15: #>

  16:     </tr>

  17:  

  18: @foreach (var item in Model) {

  19:     <tr>

  20: <# if (!String.IsNullOrEmpty(Model.PrimaryKeyName)) { #>

  21:         <td>

  22:             @Html.ActionLink("Edit", "Edit", new { id=item.<#= Model.PrimaryKeyName #> }) |

  23:             @Html.ActionLink("Details", "Details", new { id=item.<#= Model.PrimaryKeyName #> }) |

  24:             @Html.ActionLink("Delete", "Delete", new { id=item.<#= Model.PrimaryKeyName #> })

  25:         </td>

  26: <# } else { #>

  27:         <td>

  28:             @Html.ActionLink("Edit", "Edit", new { /* id=item.PrimaryKey */ }) |

  29:             @Html.ActionLink("Details", "Details", new { /* id=item.PrimaryKey */ }) |

  30:             @Html.ActionLink("Delete", "Delete", new { /* id=item.PrimaryKey */ })

  31:         </td>

  32: <# } #>

  33: <#  

  34: foreach (ModelProperty property in properties) {

  35:     if (!property.IsPrimaryKey && !property.IsForeignKey) {

  36: #>

  37:         <td>

  38:             @<#= property.ValueExpression.Replace("Model.", "item.") #>

  39:         </td>

  40: <#

  41:     }

  42: }

  43: #>

  44:     </tr>

  45: }

  46:  

  47: </table>

Depois

   1: @{

   2:     var grid = new WebGrid(Model);

   3: }

   4:  

   5: <# List<ModelProperty> properties = GetModelProperties(Model.ViewDataType, true); #>

   6:  

   7: @grid.GetHtml(

   8:     tableStyle: "webgrid",

   9:     rowStyle: "webgrid-row",

  10:     alternatingRowStyle: "webgrid-alternaterow",

  11:     headerStyle: "webgrid-header",

  12:     columns: grid.Columns(

  13:         <# foreach(var property in properties) { #>

  14:             grid.Column("<#= property.Name #>", "<#= property.Name #>", format:@<span>@item.<#= property.Name #></span>),

  15:         <# } #>

  16:     )

  17: )

Você pode ver que estamos alternando entre código C# utilizando a ViewEngine Razor (como na linha 1 até 3), e logo em seguida, trocamos para um bloco <# #> (linha 5). Aqui, estamos executando um código que irá me retornar todas as proprieades do tipo que estamos “Scaffoldando”. Logo em seguida, voltamos para código comum, e na linha 13, executamos um foreach para gerarmos as colunas do WebGrid, e definimos o nome da coluna e seu Header baseado no nome da propriedade, e o valor no item da tabela (<#= property.Name #>). Esse bloco irá ser substituído no arquivo gerado pelo nome da propriedade (por exemplo, Email).

Quando executamos o Scaffolder agora, o código gerado agora utiliza o WebGrid para exibir os dados (neste caso, há uma classe com as propriedades ID, Name e Email:

   1: @{

   2:     var grid = new WebGrid(Model);

   3: }

   4:  

   5:  

   6: @grid.GetHtml(

   7:     tableStyle: "webgrid",

   8:     rowStyle: "webgrid-row",

   9:     alternatingRowStyle: "webgrid-alternaterow",

  10:     headerStyle: "webgrid-header",

  11:     columns: grid.Columns(

  12:                     grid.Column("ID", "ID", format:@<span>@item.ID</span>),

  13:                     grid.Column("Name", "Name", format:@<span>@item.Name</span>),

  14:                     grid.Column("Email", "Email", format:@<span>@item.Email</span>)

  15:             )

  16: )

Repare que os lugares onde haviam os blocos <#= #> agora há o nome das propriedades do meu Model, que foi gerado pelo T4 template.

Voce pode baixar o código fonte da aplicação de exemplo no link abaixo:

https://skydrive.live.com/embedicon.aspx/Blog/CustomScaffoldingTemplates.zip?cid=1498c467c14dc20b&sc=documents

Agora voce poderá customizar o código gerado pelo Scaffolder, poderá criar Scaffolders para View Engines diferentes, como NHaml, Repositórios que não utilizam Entity Framework, etc..

Abraços

Breno

Written by Breno Ferreira

20/07/2011 at 20:11

Posted in Dev

Tagged with , , ,

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s