ASP .NET - Trabalhando com Dynamic Data Controls


Hoje vamos abordar como usar ASP .NET e trabalhar com Dynamic Data Controls.(DDC)

Esse recurso foi introduzido no ASP.NET 3.5 SP1. Ele simplifica a tarefa da entrada de dados usando o os modelos do Entity Framework ou LINQ to SQL para gerar automaticamente todas as máscaras usadas para exibir, alterar ou inserir dados. O Controle dinâmico de dados são uma nova onda de controles declarativos que permitem desenvolver aplicações de dados simples de forma rápida.

Muitas aplicações são essencialmente orientada a dados, em vez de utilizar uma arquitetura n-camadas, os DDC manipulam diretamente os dados. A idéia por trás dos controles Dynamic Data é construir dinamicamente a view e as máscaras de edição, usando o ObjectContext do Entity Framework ou DataContext do LINQ to SQL. Para isso a ASP.NET 4.0 suporta os provedores personalizados usando o padrão de projeto Provider Model.

Se você precisa rapidamente compor uma área editável sobre seus objetos mapeados, os controles dinâmicos de dados são uma opção a considerar levando em conta a produtividade. Você pode literalmente construir uma área de administração para seus sites em segundos com os DDC.

Obs: Atente que este recurso é mais uma opção que a plataforma .NET lhe oferece e você pode decidir usá-lo ou não. Ele será útil em algumas situações e em outras será totalmente desaconselhável usar o recurso. De qualquer forma creio que você deva conhecer mais esta opção.

O Visual Studio 2010 e o Visual Web Developer 2010 Express Edition contém dois modelos voltados especificamente para os controles de dados dinâmicos. Cabe a você escolher o mais apropriado ao seu caso, dependendo se você usar o LINQ to SQL ou Entity Framework. Se você pode decidir querer construir seu próprio provedor, tudo bem, na versão 4.0 você tem suporte para este caminho.

Os controles dinâmicos de dados são um grupo de controles que aproveitam algumas das características mais interessantes da nova ASP.NET 4.0 como o roteamento de URLs e o query extender (extensor de consulta).

Usando os Dynamic Data Controls na prática

Na parte prática eu vou usar como ferramenta o Visual Web Developer 2010 Express Edition que é grátis mas se quiser pode usar o Visual Studio 2010.

Como mencionei podemos utilizar os DDC usando o Entity Framework ou o Linq to SQL. Nesta prática eu vou usar o Entity Framework 4.1 e a linguagem Visual Basic.

Abra o Visual Web Developer 2010 Express Edition e no menu File clique em New Project;

A seguir selecione os templates Visual Basic -> Web -> ASP .NET Dynamic Data Entities Web Application e informe o nome AspNet_DDC para a aplicação clicando no botão OK;

Observe que temos duas opções para usar os Dynamic Data Controls e escolhemos a que usando Entity Framework;

Uma aplicação típica dos controles dinâmicos de dados esta baseada nos seguintes conceitos:

- Cada MetaTable está dentro de um MetaModel, que detém todas as informações sobre as tabelas;
- Cada MetaTable contém informações sobre as colunas, representada por um instância de MetaColumn;
- Esta informação é registrada em tempo de execução, geralmente usando o método RegisterContext do MetaModel;
- Por padrão, todas as tabelas e as colunas são visíveis, mas podemos alterar isso;

A estrutura da solução gerada pode ser vista na janela Solution Explorer :

Note que toda a estrutura das pastas contendo as páginas já esta pronta

Para ativar o recurso basta gerar o modelo de dados e informar o nome do
contexto no arquivo Global.asax descomentando o código que é gerado
por padrão conforme veremos mais a frente.

Não é obrigatório o registro do modelo no global.asax, mas esse é o comportamento padrão. Assim você tem que registrar o modelo na inicialização, e o arquivo Global.asax é a opção padrão para fazer isso.

Após criar o projeto se você abrir o arquivo Global.asax você verá o código semelhante ao mostrado a seguir:

Imports System.Web.Routing
Imports System.Web.DynamicData

Public Class Global_asax
    Inherits HttpApplication

    Private Shared s_defaultModel As New MetaModel
    Public Shared ReadOnly Property DefaultModel() As MetaModel
        Get
            Return s_defaultModel
        End Get
    End Property
    
    Public Shared Sub RegisterRoutes(ByVal routes As RouteCollection)
        '                     IMPORTANT: DATA MODEL REGISTRATION 
        ' Uncomment this line to register an ADO.NET Entity Framework model for ASP.NET Dynamic Data.
        ' Set ScaffoldAllTables = true only if you are sure that you want all tables in the
        ' data model to support a scaffold (i.e. templates) view. To control scaffolding for
        ' individual tables, create a partial class for the table and apply the
        ' <ScaffoldTable(true)> attribute to the partial class.
        ' Note: Make sure that you change "YourDataContextType" to the name of the data context
        ' class in your application.
        ' DefaultModel.RegisterContext(GetType(YourDataContextType), New ContextConfiguration() With {.ScaffoldAllTables = False})
    
        ' The following statement supports separate-page mode, where the List, Detail, Insert, and 
        ' Update tasks are performed by using separate pages. To enable this mode, uncomment the following 
        ' route definition, and comment out the route definitions in the combined-page mode section that follows.
        routes.Add(New DynamicDataRoute("{table}/{action}.aspx") With {
            .Constraints = New RouteValueDictionary(New With {.Action = "List|Details|Edit|Insert"}),
            .Model = DefaultModel})
    
        ' The following statements support combined-page mode, where the List, Detail, Insert, and
        ' Update tasks are performed by using the same page. To enable this mode, uncomment the
        ' following routes and comment out the route definition in the separate-page mode section above.
        'routes.Add(New DynamicDataRoute("{table}/ListDetails.aspx") With {
        '    .Action = PageAction.List,
        '    .ViewName = "ListDetails",
        '    .Model = DefaultModel})
       'routes.Add(New DynamicDataRoute("{table}/ListDetails.aspx") With {
        '    .Action = PageAction.Details,
        '    .ViewName = "ListDetails",
        '    .Model = DefaultModel})
    End Sub
    
    Private Sub Application_Start(ByVal sender As Object, ByVal e As EventArgs)
        RegisterRoutes(RouteTable.Routes)
    End Sub
    
End Class

Neste exemplo, estamos usando Entity Framework, mas com o LINQ to SQL tanto o código como os conceitos são idênticos. A propriedade ScaffoldAllTables é importante porque, por padrão o seu valor é false. Definindo-a como true, você vai automaticamente mostrar todas as tabelas na primeira página.

Quando você cria um novo aplicativo com base neste projeto, você vai perceber que todo o código já está pronto, e você não precisa escrevê-lo! Uma nova rota também já esta registrada:

routes.Add(New DynamicDataRoute("{table}/{action}.aspx") With { .Constraints = New RouteValueDictionary(New With {.Action = "List|Details|Edit|Insert"}),.Model = DefaultModel})

Observe que o código gerado esta comentado e devemos informar o nome do nosso contexto de dados gerado usando o Entity Framework.

Vamos então gerar um modelo de entidades usando como exemplo o banco de dados Northwind.mdf.

No menu Project clique em Add New Item;

A seguir clique no template Data -> ADO .NET Entity Data Model e informe o nome Northwind.edmx e clique em Add;

Na próxima janela do assistente escolha a opção : Generate from database e clique em Next>;

A seguir escolha a conexão com o banco de dados Northwind.mdf e clique em Next>

A seguir selecione as tabelas Categories, Customers, Orders, Orders Details e Products e clique em Finish;

O modelo gerado pode ser visto na figura abaixo. O nome do contexto é NorthwindEntities.

Vamos agora descomentar o código do arquivo Global.asax e informar o nome do contexto gerado. O código deverá ficar conforme abaixo:

Imports System.Web.Routing
Imports System.Web.DynamicData

Public Class Global_asax
    Inherits HttpApplication

    Private Shared s_defaultModel As New MetaModel
    Public Shared ReadOnly Property DefaultModel() As MetaModel
        Get
            Return s_defaultModel
        End Get
    End Property
    
    Public Shared Sub RegisterRoutes(ByVal routes As RouteCollection)
        '                     IMPORTANT: DATA MODEL REGISTRATION 
        ' Uncomment this line to register an ADO.NET Entity Framework model for ASP.NET Dynamic Data.
        ' Set ScaffoldAllTables = true only if you are sure that you want all tables in the
        ' data model to support a scaffold (i.e. templates) view. To control scaffolding for
        ' individual tables, create a partial class for the table and apply the
        ' <ScaffoldTable(true)> attribute to the partial class.
        ' Note: Make sure that you change "YourDataContextType" to the name of the data context
        ' class in your application.
        DefaultModel.RegisterContext(GetType(NorthwindEntities), New ContextConfiguration() With {.ScaffoldAllTables = True})
    
        ' The following statement supports separate-page mode, where the List, Detail, Insert, and 
        ' Update tasks are performed by using separate pages. To enable this mode, uncomment the following 
        ' route definition, and comment out the route definitions in the combined-page mode section that follows.
        routes.Add(New DynamicDataRoute("{table}/{action}.aspx") With {
            .Constraints = New RouteValueDictionary(New With {.Action = "List|Details|Edit|Insert"}),
            .Model = DefaultModel})
    
        ' The following statements support combined-page mode, where the List, Detail, Insert, and
        ' Update tasks are performed by using the same page. To enable this mode, uncomment the
        ' following routes and comment out the route definition in the separate-page mode section above.
        routes.Add(New DynamicDataRoute("{table}/ListDetails.aspx") With {
            .Action = PageAction.List,
            .ViewName = "ListDetails",
            .Model = DefaultModel})
    
        routes.Add(New DynamicDataRoute("{table}/ListDetails.aspx") With {
            .Action = PageAction.Details,
            .ViewName = "ListDetails",
            .Model = DefaultModel})
    End Sub
    
    Private Sub Application_Start(ByVal sender As Object, ByVal e As EventArgs)
        RegisterRoutes(RouteTable.Routes)
    End Sub
    
End Class

O código destacado em azul foi descomentado e o nosso contexto foi incluído na linha de código abaixo:

DefaultModel.RegisterContext(GetType(NorthwindEntities), New ContextConfiguration() With {.ScaffoldAllTables = True})

Como definimos a propriedade ScaffoldAllTables como True veremos todas as tabelas na primeira página.

E com isso terminamos o nosso trabalho (que trabalhão hein !!!). Vamos agora testar e verificar o resultado.

Executando o projeto iremos obter:

Na primeira página visualizamos todas as tabelas do modelo gerado:

Clicando na tabela Categories obtemos a seguinte página:

Clicando no link View Products obtemos:

Note que todas as opções para editar, deletar, visualizar, filtrar e paginar os dados das tabelas já estão disponíveis.

- Do ponto de vista técnico, os modelos das página são definidos na pasta: DynamicData/PageTemplates;
- A mágica é executada por um controle especial: o DynamicControl, que trabalha com os controles GridView e DetailsView para exibir campos dinamicamente;
- Esses controles foram adaptados para trabalhar facilmente com esses novos recursos fornecidos por dados dinâmicos. Você também pode usar outros controles, como ListView ou FormView, utilizando a mesma abordagem;
- O controle DynamicControl trabalha com a informação chamada metadata;
- Você pode usar os recursos da anotações de dados do namespace System.ComponentModel.DataAnnonations para decorar as classes e para fornecer informações; adicionais que os DDC podem ler para entender como uma coluna é composta, qual o tipo que possui, e assim por diante;
- Graças às anotações de dados (Data Annotations), os DDC fornecem automaticamente a validação do formulário, com base nos metadados disponíveis;
- A renderização está associada a controles específicos, dependendo do tipo de dados;

Dessa forma os Controles Dinâmicos de Dados apresentam uma tecnologia poderosa que simplifica a entrada de dados, onde a sua estratégia de dados coincide com o seu modelo mapeado.

E você pode estender ainda mais esse comportamento mas isso é assunto para outro artigo.

Pegue o projeto completo aqui: AspNet_DDC.zip

"Vigiai pois, porque não sabeis o dia nem a hora em que o Filho do homem há de vir." Mateus 25:13

Referências:


José Carlos Macoratti