Este artigo foi traduzido por máquina.

Estruturas do RIA

Criando aplicativos Web centrados em dados com o ASP.NET MVC e o Ext JS

Juan Carlos Carlos

Baixe o código de exemplo

Um aplicativo avançado de Internet (RIA) combina a usabilidade de um aplicativo de desktop com a flexibilidade de implantação baseada na Web e revisão. Há duas abordagens principais para a criação de RIAs. Em primeiro lugar, há plug-ins do navegador que hospedam os ambientes de execução, como o Flash, Java e o Silverlight. Em segundo lugar, há bibliotecas de extensão baseados no JavaScript como Dojo, Ext JS, jQuery, MooTools, Prototype e YUI. Cada abordagem tem suas vantagens e desvantagens.

Bibliotecas JavaScript são uma opção popular para a criação de RIAs porque JavaScript é suportado por todos os principais navegadores e não é necessário instalar um ambiente de plug-in ou tempo de execução. Estive testando com outra das bibliotecas mencionadas — Ext JS — e descobri que ele faz uma opção interessante para a implementação de aplicativos Web. É fácil de implementar, bem documentados e é compatível com Selenium para teste. Ext JS também oferece controles predefinidos que simplificam a criação de interface do usuário do seu aplicativo da Web.

Infelizmente, a maioria dos exemplos de Ext JS são ilustradas com PHP, Python e Ruby no código do Rails no lado do servidor. Mas isso não significa que os desenvolvedores usando tecnologias da Microsoft não é possível aproveitar Ext JS. Embora seja difícil a integração Ext JS com o desenvolvimento de Web Forms (devido à camada de abstração que encapsula a natureza de solicitação-resposta da Web para fornecer um modelo de controle com stateful), você poderia usar o ASP.NET MVC framework, permitindo que você utilize o Microsoft o.NET Framework e Ext JS no mesmo aplicativo.

Neste artigo, vou fornecer o tutorial que eu não poderia encontrar, percorrendo o desenvolvimento de uma solução de Web do mundo real usando ASP.NET MVC e JS Ext que lê e grava em um banco de dados back-end.

Noções básicas do formulário ext JS

Para usar Ext JS, você primeiro precisa fazer o download do sencha.com. (Usei a versão 3.2.1, mas você deve obter a versão mais recente). Observe que uma versão de código aberto e livre de Ext JS está disponível para projetos de código-fonte aberto, as organizações sem fins lucrativos e uso educacional. Para outros usos, você talvez precise adquirir uma licença. Consulte sencha.com/products/License.PHP para obter mais informações.

Descompacte o download em um diretório no seu sistema de arquivos. Ele contém tudo que você precisa para desenvolver uma solução de Web usando Ext JS, especificamente o arquivo principal ext-all.js. (Há também uma versão de depuração para ajudar a localizar erros mais facilmente.) Dependências, documentação e código de exemplo estão incluídos no download.

As pastas necessárias para um projeto são \adapters e \resources. A pasta de adaptadores permite o uso de outras bibliotecas juntamente com Ext JS. A pasta de recursos contém dependências como, por exemplo, CSS e imagens.

Para usar o Ext JS corretamente, você também precisará incluir três referências do arquivo de chave em suas páginas:

ext-3.2.1/adapter/ext/ext-base.js
ext-3.2.1/ext-all.js
ext-3.2.1/resources/css/ext-all.css

O arquivo de ext base.js contém a funcionalidade central do Ext JS. As definições de widget estão contidas no ext-all.js e all.css ext inclui folhas de estilo para os widgets.

Vamos começar a usar Ext JS em uma página HTML estática para ilustrar os conceitos básicos. As seguintes linhas estão contidas dentro da seção head da página e vincular os arquivos necessários para desenvolver com sucesso uma solução de Ext JS (também inclui o módulo de JavaScript com alguns widgets de exemplo do download Ext JS):

<link rel="stylesheet" type="text/css" 
  href="ext-3.2.1/resources/css/ext-all.css" />
<script type="text/javascript" language="javascript" 
  src="ext-3.2.1/adapter/ext/ext-base.js"></script>
<script type="text/javascript" language="javascript" 
  src="ext-3.2.1/ext-all.js"></script>
<script type="text/javascript" language="javascript" 
  src="extjs-example.js"></script>

Dentro do corpo do arquivo, inserir um elemento div para renderizar o JS Ext principal formulário:

<div id="frame">
</div>

O arquivo extjs-example.js fornece algum esclarecimento sobre como os aplicativos de Ext JS são construídos. O modelo para qualquer aplicativo Ext JS usa o ramal. NS, instruções Ext.BLANK_IMAGE_URL e Ext.onReady:

Ext.ns('formextjs.tutorial');
Ext.BLANK_IMAGE_URL = 'ext-3.2.1/resources/images/default/s.gif';
formextjs.tutorial.FormTutorial = {
  ...
}
Ext.onReady(formextjs.tutorial.FormTutorial.init, 
  formextjs.tutorial.FormTutorial);

O ramal. instrução NS permite organizar logicamente o seu código em um namespace, a fim de evitar conflitos de nomes e problemas de escopo.

A instrução Ext.BLANK_IMAGE_URL é importante para os widgets de processamento. Ele tem chamado a imagem do espaçador (uma imagem transparente de 1 x 1 pixel) e usado principalmente para gerar o espaço em branco, bem como para colocar os ícones e separadores.

A instrução Ext.onReady é o primeiro método para definir com código Ext JS. Este método é chamado automaticamente depois que o DOM estiver totalmente carregado, garantindo que todos os elementos HTML que você pode fazer referência está disponível quando o script é executado. No caso de extjs-example.js, aqui está o próprio script:

formextjs.tutorial.FormTutorial = {
  init: function () {
    this.form = new Ext.FormPanel({
      title: 'Getting started form',
      renderTo: 'frame',
      width: 400,
      url: 'remoteurl',
      defaults: { xtype: 'textfield' },
      bodyStyle: 'padding: 10px',
      html: 'This form is empty!'
    });
  }
}

Uma instância da classe Ext.FormPanel é criado como um contêiner para os campos. A propriedade renderTo aponta para o elemento div onde o formulário será processado. A propriedade de padrões Especifica o tipo de componente padrão do formulário. A propriedade url Especifica o URI para enviar a solicitação do formulário. Finalmente, a propriedade html Especifica o texto (com a formatação HTML) como a saída padrão.

Para adicionar campos, você precisará substituir a propriedade de html com a propriedade items:

items: [ nameTextField, ageNumberField ]

Os dois primeiros itens para adicionar são um campo de texto e um campo de número:

var nameTextField = new Ext.form.TextField({
  fieldLabel: 'Name',
  emptyText: 'Please, enter a name',
  name: 'name'
});
var ageNumberField = new Ext.form.NumberField({
  fieldLabel: 'Age',
  value: '25',
  name: 'age'
});

As propriedades necessárias são: a propriedade fieldLabel (para definir uma mensagem descritiva que acompanha o componente do formulário) e a propriedade name (para definir o nome do parâmetro de solicitação). A propriedade emptyText define o texto de marca d'água que o campo conterá quando ela está vazia. A propriedade value é o valor padrão para o controle.

Outra maneira de declarar controles é imediatamente:

items: [
  { fieldLabel: 'Name', emptyText: 'Please, enter a name', name: 'name' },
  { xtype: 'numberfield', fieldLabel: 'Age', value: '25', name: 'age' }
]

Como você pode ver, para o campo de nome não precisa especificar o tipo, pois ela será retirada das propriedades padrão do formulário.

Alguns elementos adicionais se adicionará ao formulário, acaba parecida a Figura 1.

Figura 1 O formulário preenchido

Até agora, criamos um formulário usando Ext JS para tirar os dados do usuário. Agora, vamos enviar os dados para o servidor. Você precisará adicionar um botão para manipular o processo de envio e mostrar o resultado para o usuário, conforme mostrado na a Figura 2.

Figura 2 os botões de formulário

buttons: [{
  text: 'Save', 
  handler: function () {
    form.getForm().submit({
      success: function (form, action) {
        Ext.Msg.alert('Success', 'ok');
      },
      failure: function (form, action) {
        Ext.Msg.alert('Failure', action.result.error);
      }
    });
  }
},
{
  text: 'Reset',
  handler: function () {
    form.getForm().reset();
  }
}]

A propriedade botões habilita o formulário para gerenciar todas as ações possíveis. Cada botão possui propriedades name e manipulador. A propriedade de manipulador contém a lógica associada com a ação executada no botão. Nesse caso, existem dois botões, cujos nomes são de salvamento e redefinir. O manipulador do botão Salvar executa uma ação de envio do formulário e mostra uma mensagem indicando êxito ou falha. O manipulador do botão de Reset redefine os valores dos campos no formulário.

O último — mas importante — etapa na criação do formulário é a validação. Para especificar os campos obrigatórios, precisamos definir a propriedade allowBlank como false e a propriedade blankText para uma mensagem de erro é exibida quando a validação necessária falhar. Por exemplo, aqui está o campo nome do formulário:

{ fieldLabel: 'Name', emptyText: 'Please, enter a name', name: 'name', allowBlank: false }

Quando você executa o aplicativo e clique no botão Salvar sem inserir todos os dados nos campos nome e idade, você recebe uma mensagem de erro, e os campos obrigatórios estão sublinhados em vermelho.

Para personalizar as mensagens de erro nos campos, adicione a seguinte linha de código logo abaixo a função Ext.onReady:

Ext.QuickTips.init();

Agora, quando o usuário move o ponteiro do mouse sobre o campo, um balão com uma mensagem exibindo o erro é exibido.

Conjunto de várias regras de validação para os campos como especificar o tamanho mínimo e máximo permitido, adiando a validação de campo até o envio do formulário e a criação de validação funciona para URLs, endereços de email e outros tipos de dados. Você pode ver os detalhes sobre essa validação no código para download.

Criando o aplicativo da Web

Agora, vamos desenvolver uma solução de Web usando Ext JS e ASP.NET MVC. Eu usei o ASP.NET MVC 2, mas essa solução deve ser aplicadas ao ASP.NET MVC 3 também. O cenário que vou endereço está adicionando um funcionário em um sistema de gerenciamento de recursos humanos.

Descrição de uso do funcionário adicionar caso é o seguinte: uma tela solicita que o usuário insira informações válidas para um novo funcionário, como o identificador de funcionário, nome completo, endereço, idade, salário e departamento. O campo departamento é uma lista de departamentos do qual escolher.

A estratégia de implementação principal é criar um JS Ext formulário no lado do cliente — como você já viu — e processe os dados usando ASP.NET MVC. A camada de persistência irá usar o LINQ para representar as entidades comerciais e para persistir os dados no sistema de banco de dados. O banco de dados back-end é o Microsoft SQL Server 2008.

Comece abrindo o Visual Studio 2010 e criando um novo projeto com o ASP.Modelo de aplicativo da Web do NET MVC 2.

Em seguida, crie o esquema de banco de dados. Neste exemplo, o esquema conterá duas entidades: departamento e funcionários. Figura 3 mostra como eu criei o banco de dados e as tabelas subjacentes e restrições de recursos humanos.

Figura 3 criar o banco de dados de recursos humanos

create table department(
  deptno varchar(20) primary key,
  deptname varchar(50) not null,
  location varchar(50)
);
create unique index undx_department_deptname on department(deptname);
insert into department
  values('HQ-200','Headquarter-NY','New York');
insert into department
  values('HR-200','Human Resources-NY','New York');
insert into department
  values('OP-200','Operations-NY','New York');
insert into department
  values('SL-200','Sales-NY','New York');
insert into department
  values('HR-300','Human Resources-MD','Maryland');
insert into department
  values('OP-300','Operations-MD','Maryland');
insert into department
  values('SL-300','Sales-MD','Maryland');
create table employee(
  empno varchar(20) primary key,
  fullname varchar(50) not null,
  address varchar(120),
  age int,
  salary numeric(8,2) not null,
  deptno varchar(20) not null,
  constraint fk_employee_department_belong_rltn foreign key(deptno)
    references department(deptno)
);
create unique index undx_employee_fullname on employee(fullname);

Agora vamos usar o LINQ to SQL para definir a estrutura de entidades e o mecanismo de persistência. Comece criando uma classe EmployeeRepository para gerenciar a lógica de acesso a dados para a tabela de funcionários. Nesse caso, você só precisa implementar a operação de criação:

public class EmployeeRepository {
  private HumanResourcesDataContext _ctxHumanResources = 
    new HumanResourcesDataContext();
  public void Create(employee employee) {
    this._ctxHumanResources.employees.InsertOnSubmit(employee);
    this._ctxHumanResources.SubmitChanges();
  }
}

Você também precisa de uma classe DepartmentRepository para gerenciar a lógica de acesso a dados para a tabela de departamento. Novamente, neste caso simples você só precisa implementar a operação de leitura para encontrar uma lista de departamentos:

public class DepartmentRepository {
  private HumanResourcesDataContext _ctxHumanResources = 
    new HumanResourcesDataContext();
  public IQueryable<department> FindAll() {
    return from dept in this._ctxHumanResources.departments
           orderby dept.deptname
           select dept;
  }
}

Agora vamos definir outra peça importante da arquitetura: o controlador. Para definir um controlador, clique com o botão direito na pasta Controllers na janela Solution Explorer e selecione Add | Controlador. Usei o HumanResourcesController como o nome do controlador.

Camada de apresentação ext JS

Agora, voltemos à Ext JS e usar a estrutura para criar a camada de apresentação do aplicativo. Para esta solução, você só precisará importar ext-all.js e as pastas \adapter e \resources.

Vá para a página de Site.Master e adicionar referências aos arquivos Ext JS dentro do elemento head, bem como um < asp: ContentPlaceHolder >elemento de marca como um recipiente do código JavaScript e CSS personalizado para cada página, conforme mostrado na a Figura 4.

Figura 4 Site.Master

<head runat="server">
  <title><asp:ContentPlaceHolder ID="TitleContent" 
    runat="server" /></title>
  <link href="../../Content/Site.css" rel="stylesheet" 
    type="text/css" />
  <!-- Include the Ext JS framework -->
  <link href="<%= Url.Content("~/Scripts/ext-3.2.1/resources/css/ext-all.css") %>" 
    rel="stylesheet" type="text/css" />
  <script type="text/javascript" 
    src="<%= Url.Content("~/Scripts/ext-3.2.1/adapter/ext/ext-base.js") %>">
  </script>
  <script type="text/javascript" 
    src="<%= Url.Content("~/Scripts/ext-3.2.1/ext-all.js") %>">
  </script>    
  <!-- Placeholder for custom JS and CSS and JS files 
    for each page -->
  <asp:ContentPlaceHolder ID="Scripts" runat="server" />
</head>

Agora vamos adicionar outras partes importantes da arquitetura do MVC: o modo de exibição. O modo de exibição apresentará o formulário para obter os dados relacionados a um funcionário. Vá para HumanResourcesController, clique com o botão direito sobre o método de ação de índice e selecione Adicionar modo de exibição. Clique no botão Adicionar na caixa de diálogo Adicionar modo de exibição.

Para implementar o formulário Ext JS criado anteriormente neste artigo, você precisará adicionar um arquivo JavaScript para o diretório de Scripts e uma referência a esse arquivo JavaScript no modo de exibição. Em seguida, incluir a referência ao arquivo employee_form.js e adicionar um elemento div no modo de exibição Index.aspx (consulte a Figura 5).

Figura 5 adicionando o formulário Funcionário

<%@ Page Title="" Language="C#" 
  MasterPageFile="~/Views/Shared/Site.Master" 
  Inherits="System.Web.Mvc.ViewPage" %>
<asp:Content ID="Content1" ContentPlaceHolderID="TitleContent" 
  runat="server">
Index
</asp:Content>
<asp:Content ID="Content2" ContentPlaceHolderID="MainContent" 
  runat="server">
  <h2>Add a New Employee</h2>
  <div id="employeeform"></div>
</asp:Content>
<asp:Content ID="Content3" ContentPlaceHolderID="Scripts" 
  runat="server">
  <script type="text/javascript" 
    src="<%= Url.Content("~/Scripts/employee_form.js") %>">
  </script>
</asp:Content>

Vá para o arquivo employee_form.js e adicionar algum código para configurar o formulário ExtJS e seus widgets subjacentes. A primeira etapa é definir uma instância da classe Ext.data.JsonStore para obter uma lista de departamentos:

var departmentStore = new Ext.data.JsonStore({
  url: 'humanresources/departments',
  root: 'departments',
  fields: ['deptno', 'deptname']
});

A propriedade url aponta para o método de ação de departamentos no controlador de HumanResourceController. Esse método é acessado pelo verbo HTTP POST. A propriedade de raiz é o elemento raiz da lista de departamentos. A propriedade fields Especifica os campos de dados. Agora, defina o formulário. As propriedades são auto-descritivo:

var form = new Ext.FormPanel({
  title: 'Add Employee Form',
  renderTo: 'employeeform',
  width: 400,
  url: 'humanresources/addemployee',
  defaults: { xtype: 'textfield' },
  bodyStyle: 'padding: 10px',

Nesse caso, a propriedade url aponta para o método de ação AddEmployee no controlador de HumanResourceController. Esse método também é acessado por meio de HTTP POST.

A propriedade items fornece a lista de widgets que representa os campos do formulário (a Figura 6). Aqui, o widget padrão é um campo de texto (isso é especificado na propriedade padrões). O primeiro campo é o número de funcionário, o que é necessário (especificado pela propriedade allowBlank). O segundo campo é o nome completo, que também é um campo de texto obrigatório. O campo Endereço é uma área de texto opcional. O campo de idade é um campo numérico opcional. O campo salary é um campo de número necessário. E, finalmente, o campo de número do departamento é uma string de identificador é selecionada em uma lista de departamentos.

Figura 6 Widgets do campo de formulário

items: [
  { fieldLabel: 'Employee ID', name: 'empno', allowBlank: false },
  { fieldLabel: 'Fullname', name: 'fullname', allowBlank: false },
  { xtype: 'textarea', fieldLabel: 'Address', name: 'address', 
    multiline: true },
  { xtype: 'numberfield', fieldLabel: 'Age', name: 'age' },
  { xtype: 'numberfield', fieldLabel: 'Salary', name: 'salary', 
    allowBlank: false },
  { xtype: 'combo', fieldLabel: 'Department', name: 'deptno', 
    store: departmentStore, hiddenName: 'deptno', 
    displayField: 'deptname', valueField: 'deptno', typeAhead: true,
    mode: 'remote', forceSelection: true, triggerAction: 'all', 
    emptyText: 'Please, select a department...', editable: false }
],

Finalmente, a propriedade de botões é definida para lidar com as ações ao longo do formulário. Isso é configurado como a Figura 2, mas a propriedade de texto tem o valor "Adicionar".

Agora o arquivo employee_form.js foi concluído. (Passei por meio da maioria dos elementos do arquivo aqui. Consulte o download de código para o código-fonte completo para este arquivo de listagem.)

Agora vejamos HumanResourceController e implementar os métodos de ação correspondente, conforme mostrado na a Figura 7.

Figura 7 HumanResourceController

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using HumanResources_ExtJS_ASPNETMVC.Models;
namespace HumanResources_ExtJSASPNETMVC.Models.BusinessObjects {
  public class HumanResourcesController : Controller {
    DepartmentRepository _repoDepartment = new DepartmentRepository();
    EmployeeRepository _repoEmployee = new EmployeeRepository();
    // GET: /HumanResources/
    public ActionResult Index() {
      return View();
    }
    // POST: /HumanResource/Departments
    [HttpPost]
    public ActionResult Departments() {
      var arrDepartment = this._repoDepartment.FindAll();
      var results = (new {
        departments = arrDepartment
      });
      return Json(results);
    }
    // POST: /HumanResource/AddEmployee
    [HttpPost]
    public ActionResult AddEmployee(employee employee) {
      string strResponse = String.Empty;
      try {
        this._repoEmployee.Create(employee);
        strResponse = "{success: true}";
      }
      catch {
        strResponse = "{success: false, error: \"An error occurred\"}";
      }
      return Content(strResponse);
    }
  }
}

Isso é tudo!

Agora execute a solução. Você verá a página da Web mostrada na a Figura 8. Inserir alguns dados no formulário e, em seguida, clique em Adicionar. Você verá uma caixa de mensagem de confirmação. Você também verá a linha inserida na tabela dbo.employee no banco de dados.

Figura 8 executando o aplicativo.

Isso é realmente todos os há para criar um simple RIA. Dependendo dos recursos que você deseja utilizar, um aplicativo semelhante poderia ser criado com qualquer uma das outras estruturas JavaScript populares enquanto ainda que utilize ASP.NET MVC. Facilmente você poderia substituir o Entity Framework para a camada de dados e usar armazenamento de Azure do Windows ou SQL Azure como o armazenamento de dados back-end. Esses blocos de construção simples tornam a criação de um RIA centrado em dados básico rápida e fácil.

Juan Carlos Olamendy é um arquiteto sênior, desenvolvedor e consultor. Ele foi reconhecido como um Microsoft Most Valuable Professional (MVP) e a Oracle ACE várias vezes. Ele é especialista de tecnologia Microsoft Certified no Windows Communication Foundation. Você pode entrar em contato com Olamendy em johnx_olam@fastmail.

Graças aos seguintes especialistas técnicos para revisão deste artigo: Scott hanselman e eilon Lipton