guia do programador - sefaz.ba · acesso a dados com unicommand.....13 2.5. unicomponentbsdb

68
Versão 1.6.7 – 13/5/2005 Guia do Programador Tecnologia de Informação http://www.unitech.com.br Av. ACM, Ed. Fernandez Plaza, 22º andar Cidadela, Salvador - BA CEP: 40.280-630 Tel: (71) 350-9777 FAX: (71) 350-9778

Upload: vodang

Post on 04-Nov-2018

240 views

Category:

Documents


0 download

TRANSCRIPT

Versão 1.6.7 – 13/5/2005

Guia do Programador

Tecnologia de Informação http://www.unitech.com.br Av. ACM, Ed. Fernandez Plaza, 22º andar Cidadela, Salvador - BA CEP: 40.280-630 Tel: (71) 350-9777 FAX: (71) 350-9778

Pág.:2

INDICE Objetivo........................................................................................................................................................3 A quem se destina?.....................................................................................................................................3 Pré-Requisitos .............................................................................................................................................3 O que há de novo? ......................................................................................................................................3 1. UniFw.Net ................................................................................................................................................4

1.1. Objetivo ........................................................................................................................................4 1.2. Projeto básico das aplicações .NET com o UNIFW.....................................................................4 1.3. Camada de apresentação ............................................................................................................5 1.4. Camada de negócio .....................................................................................................................6 1.5. Camada de dados ........................................................................................................................6 1.6. Sequência básica de execução....................................................................................................7

2. Implementando a camada de Dados e/ou Negócio ............................................................................8 2.1. UniComponent..............................................................................................................................8 2.2. Interface IDataBase....................................................................................................................12 2.3. ResultSets através de Stored Procedures no OracleDatabase e OracleDatabaseTM .............12 2.4. Acesso a dados com UniCommand ...........................................................................................13 2.5. UniComponentBSDB..................................................................................................................14 2.6. Auditoria .....................................................................................................................................20 2.7. Transaction Manager (TM).........................................................................................................25 2.8. Integração com Workflow...........................................................................................................26 2.9. Tratamento de Erros...................................................................................................................28

3. Implementando a camada de apresentação .....................................................................................29 3.1. Introdução...................................................................................................................................29 3.2. Projeto da Camada de Apresentação ........................................................................................29 3.3. ASPX x ASCX ............................................................................................................................29 3.4. A Classe Unitech.Web.FWPage ................................................................................................29 3.5. A Classe Unitech.Web.Template ...............................................................................................30 3.6. A Classe Unitech.Web.Frame ....................................................................................................30 3.7. O processo de desenvolvimento de telas ..................................................................................31 3.8 Usando o BookMark ...................................................................................................................37 3.9 Redirecionamento de Páginas ...................................................................................................38 3.10 Componentes Visuais ................................................................................................................38 3.11. Dicionário ................................................................................................................................44 3.12. Ajuda.......................................................................................................................................45

4. Log e Tratamento de Erros................................................................................................................49 5. Configuração do Ambiente/Componentes ........................................................................................51

5.1. WebConfig..................................................................................................................................51 5.2. Página inicial ..............................................................................................................................53 5.3. Página de autenticação (login)...................................................................................................53

6. Tópicos Avançados ...........................................................................................................................54 6.1. Envio de Emails..........................................................................................................................54 6.2. Informações sobre o usuário autenticado ..................................................................................54 6.3. Ciclo de vida de uma Página ASP.NET .....................................................................................54 6.4. Utilização do GAC ......................................................................................................................55 6.5. Inspetores WEB..........................................................................................................................55 6.6. Autenticadores............................................................................................................................56 6.7. Serviços......................................................................................................................................57 6.8. Tracer .........................................................................................................................................59 6.9. Add-Ins do Visual Studio .NET...................................................................................................59

7. Preparação do Ambiente de Desenvolvimento do UNIFW.NET.......................................................64 7.1. Softwares Básicos e Ambiente...................................................................................................64 7.2. Passos para preparação do ambiente .......................................................................................64

8. F.A.Q. ................................................................................................................................................65 9. Bibliografia .........................................................................................................................................68

Pág.:3

Objetivo Este documento tem como objetivo servir de referência rápida para desenvolvedores que pretendem

utilizar os recursos do UniFW.Net para desenvolver suas aplicações. Através deste documento, pode-se obter tanto uma visão geral sobre o funcionamento e programação com o UniFW.Net, quanto às formas de utilização de diversos dos seus componentes.

A quem se destina? Desenvolvedores que procuram conhecer ou lembrar, da correta utilização de um determinado

componente ou funcionalidade existente no UniFW.Net versão 1.6. Pode ser utilizado também por desenvolvedores que pretendem aprender a utilizar um novo recurso disponibilizado pelo mesmo e que podem ser utilizados no desenvolvimento de novas aplicações ou funcionalidades.

Pré-Requisitos • Fluência no desenvolvimento de aplicações WEB na plataforma MS.NET • Fluência nas linguagens VB.NET ou C#. • Fluência na linguagem DDL e TransactSQL no MS SQLServer

O que há de novo? • Documentação dos novos componentes visuais UniBusinessBox, UniDateBox e UniNumberBox

na sessão 3.7.5.

• Documentação das alterações no componente visual UniTextBox na sessão 3.7.5. • Inclusão da seção 6.9 - Add-Ins do Visual Studio .NET

• Inclusão da sessão 2.5 - UniComponentBSDB

Pág.:4

1. UniFw.Net

1.1. Objetivo Este documento tem como objetivo fornecer informações essenciais aos desenvolvedores de páginas

ASPX e controles ASCX que utilizem o framework Unifw para este fim.

1.2. Projeto básico das aplicações .NET com o UNIFW

O Unifw (Unitech Framework WEB) é um framework para desenvolvimento de aplicações WEB para a plataforma .NET 1.1 da Microsoft, desenvolvido pela Unitech. Composto por diversos módulos, o UNIFW fornece ao desenvolvedor soluções prontas para serem reutilizadas e especializadas para novas aplicações em fase de projeto, ou implementação. O diagrama abaixo demonstra a arquitetura básica do Unifw:

De acordo com o diagrama acima, diferente de uma simples biblioteca de componentes, o framework UNIFW representa o núcleo da aplicação desenvolvida. É ele quem possui os principais algoritmos e estruturas normalmente utilizadas pelas aplicações WEB feitas na plataforma .NET, assim como os ganchos utilizados para se integrar e especializar seu comportamento básico. O UNIFW é composto dos seguintes módulos:

• Web: representado pelo assembly Unitech.Web. Possui estruturas que possibilitam o controle de

execução das páginas, tais como FWPage, Templates e Frames. Além disso, esse módulo possui uma biblioteca de componentes para composição de telas WEB através de ASPXs/ASCXs. Essa biblioteca possui classes que representam componentes visuais HTML tais como UniTextBox, UniDataGrid, UniTreeView, UniDropDownList e outras mais, que herdam de componentes já existentes no Framework .NET Microsoft.

• Segurança: representado pelo assembly Unitech.UNIFW.Seguranca. Possui as estruturas para configuração das políticas de segurança, tais como domínios, usuários, papeis e grupos de trabalho.

• Workflow: representado pelo assembly Unitech.UNIFW.Workflow. Módulo com as estruturas de controle e configuração de aplicações que utilizam Workflow, tais como fluxos, transições, entidades de fluxo e solicitações de transição.

Aplicação X

UNIFW

Segurança

Web

Workflow

Ajuda

Auditoria

Serviço

Conteúdo

Inspetores

Validators

Serviços

Sequenciador

WebControls

Dicionário

Pág.:5

• Auditoria: representado pelo assembly Unitech.UNIFW.Auditoria. Possui as estruturas para implementação da auditoria de operações nas aplicações.

• Serviço: representado pelo assembly Unitech.UNIFW.Servico. Possui as estruturas para implementação de serviços assíncronos executados pelas aplicações. Com elas, pode-se implementar classes que representam serviços que serão executados em intervalos previamente configurados no framework.

• Ajuda: representado pelo assembly Unitech.UNIFW.Ajuda. Estrutura para implementação de Help integrado à aplicação. Ou seja, pode-se cadastrar os tópicos associados às telas e, em tempo de execução, montar a página de help de acordo com a configuração feita.

• Conteúdo: representado pelo assembly Unitech.UNIFW.Conteúdo. Possui as estruturas para gerência de notícias e banners a serem disponibilizadas pela aplicação.

• Dicionário: representado pelo assembly Unitech.UNIFW.Dicionário. Possui as estruturas para gerência de Mensagens e Textos dicionarizados. Pode-se cadastrar Textos para os controles visuais, ou mensagens de erros das páginas em diversos idiomas, e conforme a configuração da aplicação, o Framework se encarregará de mostrar o texto no idioma correto.

Voltado para o aumento da produtividade no desenvolvimento de aplicações WEB, na plataforma .NET,

o projeto do Unifw é feito para melhor se encaixar na estrutura de aplicações em 3 camadas: apresentação, negócio e dados, normalmente utilizadas para este fim. Para cada camada o Unifw fornece a infra-estrutura necessária para seu correto projeto e controle de execução, possibilitando ao projetista e desenvolvedor uma maior chance de sucesso em seu desenvolvimento. È importante lembrar que o Unifw .NET é um framework criado sobre o Framework .Net Microsoft, portanto parte deste pôde ser reaproveitada e especializada, tal como os componentes visuais e componentes validators.

1.3. Camada de apresentação

A camada de apresentação tem como objetivo fornecer ao usuário todas as funcionalidades existentes na aplicação. Baseada na linguagem HTML e Javascript, as interfaces de aplicações WEB são construídas em tempo de execução no servidor WEB associado. Na plataforma .NET há uma separação visível entre o layout da página (HTML – ASPX/ASCX) e seu código de execução (CodeBehind). Estes componentes devem ser combinados de forma a manter as seguintes características:

• Limpeza de codificação: páginas ASPX/ASCX não devem conter códigos embutidos, apesar de

poderem ter, assim como seu CodeBehind não serve para montar páginas HTML. • Reutilização de código: é desejável que se possa reutilizar código de montagem de páginas, tais

bcomo lógica de validação de campos e seqüência básica de execução de telas semelhantes. • Transparência de controle: funcionalidades de controle tais como segurança e auditoria devem ser

aplicadas de forma transparente aos componentes implementados.

Para esta camada, o Unifw fornece componentes que possibilitam o controle desde o recebimento da requisição HTTP, à montagem da página solicitada. Neste documento, serão discutidas as principais estruturas e componentes envolvidos com o controle de execução da camada de apresentação, que serão devidamente detalhados mais adiante.

Pág.:6

1.4. Camada de negócio A camada de negócio tem como objetivo fornecer à aplicação todas as funcionalidades de controle da

lógica de negócio da aplicação. É nesta camada que estão representadas as entidades e processos envolvidos com as funcionalidades disponibilizadas pela camada de apresentação. Todas as regras de validação, controle de processos e integridade lógica dos dados são devidamente implementados nesta camada. Fazem parte desta camada componentes que se utilizam de Transações, DataSets e etc. Um bom projeto e implementação de componentes da camada de negócio deve possibilitar as seguintes características:

• Independência da camada de apresentação: componentes de negócio devem poder ser utilizados por componentes da camada de interface de forma independente. Ou seja, componentes de negócio não podem fazer referência a componentes da camada de interface, pois se criará um acoplamento indesejado.

• Performance adequada: a depender do tipo de solução a ser implementada, uma diferente estrutura de programação deve ser utilizada para atender ao requisito levantado.

• Flexibilidade de configuração: mudanças previstas de comportamento devem ser disponibilizadas sem a necessidade de reprogramação de componentes. Isto só é possível com um projeto de baixo acoplamento entre componentes estratégicos.

O framework Unifw fornece a classe Unitech.Component.UniComponent para apoio ao desenvolvimento

da camada de negócio.

1.5. Camada de dados

A plataforma .Net não dispõe atualmente de recursos de persistência automática em banco de dados, portanto se faz necessário o acesso ao mesmo através de objetos ADO.NET para atualização ou apenas consulta dos dados existentes. Um projeto de componentes da camada de dados deve possuir as seguintes características:

1. Independência da camada de negócio: componentes da camada de dados não devem fazer referência à estruturas da camada de negócio.

2. Desacoplamento e Flexibilidade: em muitos casos ocorrem mudanças do banco de dados que se está utilizando para o acesso. Nestes casos se faz necessária a implementação de novas classes de acesso a banco de dados (utilizando o ADO.NET) que o façam da maneira adequada para o novo banco de dados utilizado. Com isso, se faz necessária a implementação de uma estrutura que possibilite a mudança dos componentes de acesso a dados sem que isto implique em qualquer impacto para classes de negócio que os utilizem.

O Unifw disponibiliza componentes que auxiliam a implementação de componentes de acesso a base

de dados de diversos tipos. Componentes como Classes Unitech.Component.UniComponent, Unitech.Data, fornecem funcionalidades prontas de abertura de conexão, conversão de resultados de Stored Procedures em DataSets, formatação de dados SQL. Os detalhes sobre a implementação dos componentes da camada de dados com o Unifw serão detalhados mais adiante.

Pág.:7

1.6. Sequência básica de execução Aplicações projetadas para utilizar as estruturas do Unifw possuem em comum uma sequência básica

de execução. Esta sequência se inicia no recebimento da requisição HTTP e finaliza com o término do processamento da página solicitada. O diagrama abaixo exibe os principais passos envolvidos no processamento das requisições recebidas:

No diagrama anterior, é exibida a sequência básica de execução de uma típica aplicação WEB que se

utiliza do Unifw. Seguem as descrições dos principais componentes envolvidos: • Browser: aplicação cliente WEB. É ele que exibe a interface ao usuário e cria as novas

requisições HTTP que serão enviadas ao servidor. Estas requisições contém informações que indicam qual tela, ação e parâmetros da solicitação.

• FWPage: componente integrante do Unifw, que centraliza o recebimento das requisições HTTP enviadas pelos clientes. Cabe a este componente efetuar as validações e encaminhar o processamento das requisições recebidas. Este encaminhamento pode ser resumido na verificação de segurança(Inspetor) e carregamento do arquivo de Template.

• Inspetor: cabe ao inspetor, efetuar todas as validações e verificações necessárias para se autenticar e autorizar o usuário que enviou a requisição. Além disso, efetua os registros de auditoria, conforme configurado.

• Template: cabe ao template identificar quais arquivos (.ASCX) que deverão ser carregados nos quadros do template da tela requisitada.

• Arq.ASCX: implementação de um arquivo ASCX que constrói a interface HTML que será exibida para o cliente, normalmente composta por tabelas, campos de entrada de dados e javascripts. Cabe a esta implementação apenas a formatação adequada do resultado da solicitação feita. Qualquer implementação mais complexa, que envolva chamada de componentes de negócio, condições ou laços, devem ser feitas no CodeBehind deste ASCX que fará o processamento necessário.

• Classes BS: implementação da camada de negócio da aplicação. São classes implementam todas as rotinas de validação e processamento necessárias para a operação e integridade das informações mantidas.

• Classes DB: implementação da camada de dados da aplicação. São classes que implementam consultas e execuções no banco.

• BD: banco de dados utilizado. Contém as tabelas com os dados das entidades utilizadas na aplicação. A depender do projeto, pode ainda conter procedures.

A descrição detalhada de implementação de cada componente e dos recursos do Unifw existentes para

cada situação será devidamente feita nas próximas sessões deste documento.

Browser FWPage Inspetor Arq. ASCX Classes BS Classes DB BD Template

HTTP ValidaSeguranca

MontaPagina

Load

exec negócio exec. dados persistir

Pág.:8

2. Implementando a camada de Dados e/ou Negócio

A camada de dados e negócio é composta por um conjuto de classes cujo principal objetivo é,

respectivamente, acessar uma determinada base de dados e tratar das regras de negócio. Porém o Unifw não exige que os projetos tenham esta divisão. Sugere-se que as classes que visam acessar a dados e/ou tratar das regras de negócio herdem de Unitech.Component.UniComponent, sendo a sua utilização decisão de projeto. Na sessão a seguir será detalhada as funcionalidades e facilidades que a classe UniComponent proporciona.

2.1. UniComponent O Unitech.Component.UniComponent foi criado com o intuito de fornecer um conjunto de

funcionalidades prontas para as classes que o estendem. Basicamente, o UniComponent fornece funcionalidades de acesso a banco de dados, geração de seqüências e tratamento de erros que podem ser reutilizadas e estendidas pelos demais componentes.

A figura abaixo apresenta a estrutura do UniComponent.

Segue um exemplo de código de um componente que se utiliza do UniComponent:

1. Public Class Template 2. Inherits UniComponent

3. Public Sub New() 4. SiglaDataSource = "sigla_do_data_source" 5. End Sub

6. Function Inserir(ByRef DS As DataSet) As Int32 Implements BS.ITemplate.Inserir 7. Dim Retorno As Int32

8. Dim SGBD As Unitech.Data.IDatabase = CreateDataBaseInstance(“minhaorigemdados”)

9. DS.Tables(0).Rows(0)("Identificador") = GetNewNumber(“minhasequencia”) 10. Retorno = SGBD.SPExecute("SEGURTemplateINS", SGBD.FillParameters("SEGURTemplateINS",

DS.Tables(0).Rows(0)))

11. Return Retorno 12. End Function

13. Function ObterTodos() As DataSet Implements BS.ITemplate.ObterTodos 14. Dim dsRetorno As DataSet

15. Dim SGBD As Unitech.Data.IDatabase = CreateDataBaseInstance(SiglaDataSource)

16. dsRetorno = SGBD.GetData("Select * from Template")

17. Return dsRetorno 18. End Function 19. End Class

Pág.:9

No trecho acima, pode-se ver a utilização das principais funcionalidades do UniComponent, que serão

descritas em detalhes a seguir.

2.1.1. Acesso a Banco de Dados

O UniComponent fornece aos componentes de negócio/dados das aplicações a possibilidade de acessar base de dados de forma transparente. Essa transparência se dá em dois aspectos: o componente não precisa se acoplar a uma implementação específica do ADO.NET e a string de conexão com o banco de dados não precisa ser mantida/gerenciada em código.

Para não acoplar o código do componente à uma bibilioteca de acesso a dados específica do ADO.NET(ex.: SQLServer, Oracle, OLEDB etc), o UniComponent se integra à estrutura IDataBase. Essa estrutura será descrita em detalhes mais adiante, mas representa uma interface genérica de acesso aos dados que pode ser utilizada para qualquer tipo de banco de dados. Para se obter uma instância de uma classe de acesso a dados(IDataBase) o método CreateDataBaseInstance deve ser utilizado. Segue um exemplo:

Dim SGBD As Unitech.Data.IDatabase = CreateDataBaseInstance(“minhaorigemdados”)

Resta um questionamento: como definir qual o tipo e qual a string de conexão que será

utilizado pelo componente? O UniComponent se utiliza do conceito de OrigemDados(ou DataSource) do UniFW.Net.

Uma origem de dados é uma estrutura que permite ao UniFW identificar o tipo de banco de dados assim como sua string de conexão através de uma simples sigla. No exemplo acima, vê-se o uso do método CreateDataBaseInstance, que recebe um parâmetro denominado “minhaorigemdados”. Para o UniFW, este parâmetro é suficiente para identificar o tipo de banco, assim como a sua string de conexão. Essas informações são obtidas do cadastro de OrigemDados realizado através da interface de acesso a dados do UniFW(ver Guia do Administrador).

Outra opção de uso do método CreateDataBaseInstance é sua chamada sem passagem de nenhum parâmetro. Segue exemplo:

Dim SGBD As Unitech.Data.IDatabase = CreateDataBaseInstance()

Ao não passar nenhum parâmetro para o método CreateDataBaseInstance, será utilizado

como OrigemDados(ou DataSource) um valor padrão definido na propriedade “SiglaDataSource” existente no UniComponent. Esta forma de uso é muito prática quando um determinado componente acessa semrpe a mesma OrigemDados, pois reduz a quantidade de código na chamada de CreateDataBaseInstance, porém, necessita que a propriedade seja atualizada. Um exemplo de atualização da OrigemDados padrão do componente está apresentada abaixo.

Public Sub New() SiglaDataSource = "minhaorigemdados" End Sub

No trecho acima, vê-se a utilização do construtor do componente de negócio para atualizar a

OrigemDados(ou DataSource) que o mesmo irá utilizar por padrão.

Pág.:10

2.1.2. Geração de Números Seqüenciais Muitas vezes, entidades necessitam de números seqüenciais únicos para serem utilizados

como suas chaves primárias, por exemplo. O UniComponent fornece aos componentes de negócio/dados a funcionalidade de geração de números sequenciais. Essa funcionalidade se baseia no recurso de seqüências existente no UniFW.Net e que é configurado através de sua interface de adminsitração(ver Guia do Administrador).

O método GetNewNumber do UniComponent recebe como parâmetro a sigla da seqüência desejada. Segue um exemplo de seu uso:

Dim X as Integer = GetNewNumber(“minhasequencia”)

No exemplo acima, é solicitado, através do método GetNewNumber, o próximo número da

seqüência de sigla “minhasequencia”. Para que funcione de acordo, a sequência deve estar devidamente cadastrada na base de dados do UniFW (ver Guia do Administrador).

2.1.3. Tratamento de Erros Muito freqüentemente, a rotina de tratamento de erros de componentes possui a mesma

lógica. No caso de aplicações que se utilizam do UniFW, o mais comum é identificar se o erro(ou Exception) ocorrido se trata de um erro de négocio ou de ambiente, por exemplo. Outro passo comum é encapsular uma Exception nativa do ambiente em uma outra exception da família Unitech.Exception. O UniFW.Net já fornece um conjunto básico de Exceptions para utilização por parte do desenvolvedor e que serão descritas mais em detalhes adiante. São duas as classes de Exceptions mais utilizadas : Unitech.Exception.EnvironmentException e Unitech.Exception.ApplicationException.

EnvironmentExceptions são erros de ambiente, muitos deles imprevisíveis para o desenvolvedor. Pode-se citar como exemplo a impossibilidade de abrir conexão com o banco de dados. Já ApplicationExceptions são erros de aplicação/negócio. Ou seja, são erros que já são esperados pelo desenvolvedor pois os mesmos estão previstos nas validações das regras de negócio da aplicação.

Com o objetivo de reutilizar a rotina de tratamento o UniComponent fornece o método TrataErro, declarado da seguinte forma:

protected virtual void TrataErro(System.Exception PobjException, string PsigErroAmbientePadrao)

O objetivo deste método é identificar o tipo do erro recebido como parâmetro e levantar um

erro da família das Unitech.Exceptions. O Unicomponent fornece uma implementação pronta para este método cuja lógica segue abaixo:

protected virtual void TrataErro(System.Exception PobjException, string PsigErroAmbientePadrao) {

if (this.isBI(PobjException)) { // Somente lança a exception throw PobjException; } else { // Lança uma nova exception de ambiente, empilhando a anterior throw new Unitech.Exception.EnvironmentException(PsigErroAmbientePadrao, PobjException); }

}

Pág.:11

O método “isBI” usado acima tem como papel retornar verdadeiro caso a exception recebida

como parâmetro possa ser considerada uma exception de negócio(BI=business inteligence). Para responder isso, o mesmo se utiliza de uma propriedade do tipo Hash denominada ChstBIExceptions. Caso a exception recebida como parâmetro esteja nessa Hash, o método retornará TRUE. Segue a implementação básica do método

public virtual bool isBI(System.Exception PobjException) { return this.BIExceptions.ContainsKey(PobjException.GetType().ToString()); } A Hash com as exceptions que serão consideradas exceptions de negócio(BI) é preenchida

através do método “CarregaBIExceptions()”. Esse método tanto cria a instância da Hash quanto a popula com as exceptions já conhecidas. Segue a lógica interna do método já implementada pelo UniComponent:

protected virtual void CarregaBIExceptions() { this.ChstBIExceptions = new Hashtable(); this.ChstBIExceptions.Add("Unitech.Exception.ValidacaoException", null); this.ChstBIExceptions.Add("Unitech.Exception.ValorInvalidoException", null); this.ChstBIExceptions.Add("Unitech.Exception.ValorNaoDefinidoException", null); this.ChstBIExceptions.Add("Unitech.Exception.TamanhoException", null); this.ChstBIExceptions.Add("Unitech.Exception.ApplicationException", null); this.ChstBIExceptions.Add("Unitech.Exception.SecurityException", null); this.ChstBIExceptions.Add("Unitech.Exception.DominioInvalidoException", null); this.ChstBIExceptions.Add("Unitech.Exception.LoginInvalidoException", null); this.ChstBIExceptions.Add("Unitech.Exception.AcessoNegadoException", null); this.ChstBIExceptions.Add("Unitech.Exception.UsuarioNaoAutenticadoException", null); this.ChstBIExceptions.Add("Unitech.Exception.IntervaloException", null); }

Qualquer código de componentes de negócio/dados podem se utilizar do método TrataErro

para tratar seus erros de forma genérica. Como exemplo de seu uso, pode-se tratar um erro ocorrido de acordo com o trecho abaixo:

Try . . . Catch ex as System.Exception

TrataErro(ex) End Try Componentes de negócio/dados que estendam do UniComponent, ficam livres para

modificar o comportamento padrão de tratamento de erros, bastando para isso a redefinição de um de seus métodos básicos: TrataErro, isBI e CarregarBIExceptions.

Pág.:12

2.2. Interface IDataBase O ADO.Net disponibiliza diversas bibliotecas de acesso a dados como OLEDB, ORACLE e SQL. Com o

tuito de prover um serviço de auditoria de acesso a dados e reduzir o acoplamento do código com a bibliboteca SQLData e ORACLEData, por exemplo, foi criada a interface Unitech.Data.IDatabase.

Atualmente, o UniFW disponibiliza as seguintes classes de acesso a dados que implementam a interface IDataBase: SQLDataBase, SQLDataBaseTM, OracleDataBase e OracleDataBaseTM. A figura abaixo apresenta a estrutura do IDataBase:

Abaixo será apresentada uma visão geral dos métodos mostrados na figura acima: • Execute: Executa a query SQL ou o command passado como parâmetro. Este método deve ser

usado, por exemplo, quando deseja fazer insert, delete ou update. • FillParameters: Preenche os parâmetros da Procedure com os valores passado no DataRow.

Vale lembrar que para fazer a sincronia entre os campos do dataRow e os parâmetros da procedure só é feita caso o nome do campo seja igual ao nome do parâmetro.

1. SGBD.SPExecute("SEGURTemplateINS", SGBD.FillParameters("SEGURTemplateINS", tabela.Rows(0)))

• GetData: Obtém dados a partir da query SQL ou command passado como parâmetro. • Init: Esse método é responsável por informar a string de conexão ao objeto do tipo IDataBase.

Caso a classe herde de UniComponent não será necessário utilizar esse método, pois o método CreateDataBaseInstance de UniComponent já se preocupa em informar a string de conexão ao objeto do tipo IDataBase criado.

• SPExecute: Executa a procedure passada como parâmetro. Este método deve ser usado, por exemplo, quando deseja fazer insert, delete ou update.

• SPGetData: Obtém dados a partir da procedure passada como parâmetro. • SPGetParameters: Retorna a coleção de parâmetros da procedure passada como parâmetro.

1. 2. 3.

Dim Parametros() As System.Data.SqlClient.SqlParameter Parametros = SGBD.SPGetParameters("SEGURUsuarioSELDOM") Parametros(0).Value = IdenDominio

2.3. ResultSets através de Stored Procedures no OracleDatabase e OracleDatabaseTM

Diferente do SQLServer o Oracle não retorna um resultset na execução de uma query de consulta, e sim uma referência para um cursor (OracleType.Cursor) o qual é tratada de forma especial dentro da classe OracleDatabase (classe que implementa IDatabase) para retornar finalmente um dataset com o resultset da consulta. Para maiores detalhes sobre a implementação de stored procedures de consulta no Oracle e o seu

Pág.:13

acesso através do provider OracleClient leia o artigo em http://support.microsoft.com/default.aspx?scid=KB;EN-US;Q322160&ID=KB;EN-US;Q322160.

Diante dessa particulariedade do Oracle em retornar o cursor do resultset ao invés do mesmo, o UniFW.NET obriga que a stored procedure tenha como primeiro parâmetro um CURSOR de direção OUT para a recuperação desse resultset referenciado. Veja o codigo da stored procedure a seguir:

1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. 16. 17.

PACKAGE PackageUniFW AS TYPE t_cursor IS REF CURSOR ; Procedure SP_APLICACAO(cursor_retorno IN OUT t_cursor, IDENT IN NUMBER); END PackageUniFW; PACKAGE BODY PackageUniFW AS Procedure SP_APLICACAO (cursor_retorno IN OUT t_cursor, IDENT IN NUMBER) IS v_cursor t_cursor; BEGIN OPEN v_cursor FOR SELECT * FROM APLICACAO A WHERE A.IDENTIFICADOR=IDENT; cursor_retorno := v_cursor; END SP_APLICACAO; END PackageUniFW;

Acima temos o codigo da criação de um package (linhas 1 a 4) definindo um tipo referente a CURSOR

denominada t_cursor e a definição de uma stored procedure chamada sp_aplicacao com a sua respectiva assinatura. Logo a seguir temos o codigo (linhas 6 e 7) da stored procedure SP_APLICACAO que possui como parâmetros cursor_retorno do tipo t_cursor de direção OUT e o IDENT do tipo number. Nas linhas 12 a 16 temos a abertura do meu cursor v_cursor (alias para t_cursor) a qual irá apontar para o resultado da consulta na tabela APLICACAO, através da query SELECT * FROM APLICACAO WHERE A.IDENTIFICADOR=IDENT (linhas 13 a 14).

Apesar do que foi relatado acima não existem mudanças quanto a forma de obter dados através de

stored procedures em relação ao outros SGBDs. Conforme já foi visto no tópico anterior temos o método SPGetData das classes que implementam IDatabase o qual é responsável pela obtenção de um resultset através de uma stored procedure. Esse método recebe como parâmetros o nome da stored procedure, o nome da tabela que será retornada com o resultset (existe uma assinatura recebendo um array de nomes de tabela – não suportado pela OracleDataBase e OracleDataBaseTM) e um array de parâmetros (do tipo IParameters), existem diferentes sobrecargas desse método (inclusive recebendo Command) tornando opcional a informação do nome da tabela assim como a dos parâmetros.

Abaixo segue um exemplo de código utilizando a funcionalidade:

1. 2. 3.

Dim param(0) As OracleClient.OracleParameter param(0) = New OracleClient.OracleParameter("IDENT", 32) Dim ds As DataSet = objDadosORACLE.SPGetData("PackageUniFW.SP_APLICACAO", param)

No exemplo acima nas linhas 1 e 2 é criado um parâmetro denominado IDENT com o valor 32. Na linha

3 é chamado o método SPGetData da classe OracleDatabase passando o nome da stored procedure (se a stored procedure tiver dentro de um package não se esqueça de informar o nome no seguinte formato: nome_package.nome_storedprocedure) e o parâmetro definido na linha anterior. Note que não se deve informar o 1º parâmetro do tipo Cursor pois essa operação é transparente no processamento do método SPGetData.

2.4. Acesso a dados com UniCommand Os comandos de acesso a dados do ADO .Net são específicos para cada SGBD, ex: SQLCommand,

OracleCommand, OleDbCommand, cada um com uma syntaxe específica para montagens de queries parametrizadas. Visando a criação de comandos no padrão ANSI que sirvam para mais de um tipo de SGBD

Pág.:14

o UniFW disponibiliza a classe UniCommand que possui a inteligência interna de decidir a partir da Sigla da Origem de Dados qual tipo de IDBCommand irá montar para o acesso ao banco. O UniCommand pode gerar SQLCommands, OracleCommands e OleDbCommands. A syntaxe de acesso a dados com um UniCommand fica assim:

1. Dim SGBD as Unitech.Data.IDatabase = CreateDataBaseInstance(getSiglaDataSource) 2. UniCommand cmdSql = new UniCommand(getSiglaDataSource) 3. cmdSql.CommandText = "Select * from Servico where Identificador = @Id" 4. cmdSql.Parameters.Add("@Id",ds.Tables(0).Rows(0)("Identificador")) 5. dsRetorno = SGBD.GetData(cmdSql.ObjCommand,"Servico")

O código acima serve para conexões SQL, Oracle ou OleDb. O UniCommand saberá montar

internamente o IDBCommand do tipo correto a partir da sigla da origem de dados que lhe foi fornecida. Pode-se notar que a função GetData (linha 5) recebe como parâmetro a propriedade ObjCommand do UniCommand que possui o command interno gerado corretamente. O mesmo vale para as funções Execute, SPGetData e SPExecute.

As chaves dos parâmetros devem estar sempre de acordo com a syntaxe padrão a seguir: @nome_do_parâmetro.

2.5. UniComponentBSDB

O UniFW.NET com objetivo de facilitar a implementação de classes básicas1 de negócio/dados

disponibiliza o componente UniComponentBSDB2 que oferece os seguintes recursos e características:

1. Facilidade de implementação através da simplificação. O componente necessita para seu

funcionamento tão somente da propriedade SiglaDataSource3 e informação do nome da tabela padrão

(propriedade TabelaPadrao). Em alguns casos específicos da necessidade de utilizar o recurso de

Seqüência, será necessário informar a sigla da seqüência (propriedade SiglaSequencia) do cadastro

do UniFW.NET assim como o campo seqüencial da tabela (propriedade CampoSequencial).

2. Novas propriedades para manipulação de dados, tais como:

o InnerDataSet

�� DataSet com a coleção de tabelas acessadas pelo componente. Inicialmente o

componente traz automaticamente a estrutura da tabela padrão4, essa estrutura por

sua vez será uma DataTable com o nome configurado da propriedade TabelaPadrao.

o InnerDataTable

�� DataTable referente à tabela padrão.

o InnerDataRow

�� DataRow referente a InnerDataTable. É criada uma instância na primeira solicitação

dessa DataRow.

1 Entende-se por classes que estão diretamente relacionadas com uma tabela, também denominada de tabelas do sistema, na base de dados. 2 Sendo esse componente uma extensão (herda diretamente) do UniComponent. 3 Propriedade herdade de UniComponent. 4 Nome da tabela padrão foi especificado na propriedade TabelaPadrao. Tabela a qual a classe está diretamente relacionada.

Pág.:15

3. Obtenção automática da estrutura da tabela padrão, dispensando dessa forma a implementação do

método de obtenção do DataStructure5, antes obrigatório. Obtenção da estrutura de qualquer tabela

da origem de dados do componente através do método ObterEstrutura6.

Atenção: A estrutura obtida será adicionada ao InnerDataSet assim como retornada. Um outro

aspecto importante que a estrutura obtida da base de dados não incluem as chaves primárias assim

como as definições se as colunas das tabela suportam ou não valores do tipo nulo (DBNull).

4. Oferece uma abstração OO do objeto através de propriedades indexadas. Ao instanciar um objeto

UniComponentBSDB já é disponibilizado automaticamente uma linha (InnerDataRow) pronta da tabela

padrão como propriedade indexada do mesmo. Exemplo: myObjeto(“Identificador”)

o Essa propriedade indexada acessa indiretamente o InnerDataRow;

5. Automatização de Operações Básicas

o ObterPorPK

o ObterPorFiltro

�� Estará considerando no filtro somente os campos configurados no InnerDataRow.

Atenção: Não é possível configurar um campo no filtro para buscar o valor DBNull.

o ObterTodos

o Inserir

�� Se tiver configurado a propriedade SiglaSequencia e o campo seqüenciado do

InnerDataRow estiver nulo (DBNull) o componente automaticamente realizará o

GetNewNumber7 para esse campo, atualizando o mesmo para futura consulta.

o Alterar

o Excluir

Atenção: Todas as operações são configuradas através de propriedade indexadas ou acesso

direto ao InnerDataRow. Todos métodos de consulta (ObterPorPK, ObterPorFiltro,

ObterTodos) atualizam o InnerDataSet com o resultado da mesma, além de retorná-lo por

referência. Além disso, os métodos de consulta possuem uma sobrecarga para receber os

campos de retorno da consulta – note que esse recurso irá trazer ao InnerDataSet uma tabela

que não condiz com a estrutura na base de dados.

6. Validação automática dos dados submetidos nas Operações Básicas para os seguintes casos:

o Verifica se foi indicada a chave primária8 na realização das operações de ObterPorPK, Inserir,

Alterar e Excluir.

o Verifica se foram preenchidos os campos obrigatórios na realização das operações de Inserir,

Alterar.

Atenção: É disponibilizado o método Validar que pode ser facilmente sobrescrito ou estendido.

5 Método responsável pelo retorno de um DataSet com um DataTable contendo a estrutura da tabela padrão da classe. 6 Esse método atualiza o InnerDataSet com a estrutura obtida além de retorná-lo por referencia. Note que essa estrutura estará disponível no InnerDataSet através de uma DataTable com o nome da estrutura solicitada. 7 Método original de UniComponent. 8 Os campos obrigatórios e a chave primária são obtidos através da configuração do esquema da tabela da base de dados.

Pág.:16

7. Flexibilidade. O componente flexibiliza ao programador a possibilidade de sobrescrever a

implementação de qualquer dos seus métodos, assim como de reutilizar a sua implementação. Todos

os recursos pré-existentes no UniComponent se mantiveram possibilitando a realização de

implementações mais complexas.

o Alguns métodos específicos tais como:

�� Reset – Reinicializa o componente descartando o InnerDataSet conseqüentemente o

InnerDataTable e InnerDataRow.

�� ResetCacheSchemas – Limpa o armazenamento temporário (cache) da aplicação

referente às estruturas da tabelas.

Para utilizar os recursos de automatização de operações básicas em base de dados tais como

ObterEstrutura, ObterTodos, ObterPorFiltro, ObterPorPK, Inserir, Alterar e Excluir disponibilizados pelo

UniFW.NET na camada de negócio/dados é necessário que cada classe herde direta ou indiretamente da

classe Unitech.Component.UniComponentBSDB. É considerado como boa prática, cada projeto de

negócio/dados ter sua classe ComponentBSDB. Essa classe a princípio só precisará herdar de

Unitech.Component.UniComponent, porém caso o projeto tenha algum requisito especial para as classes que

herdem de UniComponentBSDB basta implementar na classe criada tais requisitos e com isso todas as

classes que herdem da mesma possuirá tais características. Como por exemplo, no projeto de negócio/dados

do BiblioTech, foi criada a classe BiblioTechComponentBSDB que herda de

Unitech.Component.UniComponentBSDB e possui o construtor que informa para a classe pai (UniComponent)

qual a sigla da origem de dados que foi cadastrada para a aplicação.

Mais detalhes sobre o cadastramento de origem de dados ver o Guia do Administrador.

Veja abaixo a implementação de uma classe que implementa UniComponentBSDB para servir como classe

base para implementação das classes de negócio e dados.

1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15.

Public Class BibliotechComponentBSDB Inherits Unitech.Component.UniComponentBSDB Public Sub New() 'Informe para a classe pai (UniComponentBSDB) qual é a origem dados que 'será utilizada. SiglaDataSource = "BIBLIO" 'Se existir um nome padrão para os campos sequenciados aproveite 'para definir também nessa herança. 'Exemplo: ' CampoSequencial = "Identificador" End Sub

End Class

A implementação de uma classe a partir da BibliotechComponentBSDB se torna bastante trivial.

Vejamos abaixo o código de implementação da classe Editora. 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11.

Public Class Editora Inherits BibliotechComponentBSDB Public Sub New() 'A configuração mais importante está na determinação do nome da tabela 'padrão a qual essa classe fará acesso na base de dados. TabelaPadrao = "Editora"

Pág.:17

12. 13. 14. 15. 16. 17. 18. 19. 20. 21. 22. 23.

'Se existir um nome diferente para o campo seqüenciado dessa classe 'configure a propriedade CampoSequencial exemplo: ' CampoSequencial = "Codigo" 'O componente UniComponentBSDB (BibliotechComponentBSDB herdar dessa

classe) necessita para inserir um registro em uma tabela que possui campo seqüenciador 'o nome da sigla dessa sequência no UniFW.NET SiglaSequencia = "Editora" End Sub

End Class

Utilizando uma classe que herda de UniComponentBSDB

Abaixo teremos alguns trechos de código auto-explicativos que guiarão o programador na utilização

de uma classe de negócio e dados implementada a partir de UniComponentBSDB (diretamente ou

indiretamente).

Obtendo Estrutura da Tabela Padrão 1. 2. 3. 4. 5.

' Editora é uma classe que herda de UniComponentBSDB. Dim objEditora As Editora = New Editora

'InnerDataSet do componente possui uma tabela com estrutura da Tabela Padrão InnerDataSet = objEditora.InnerDataSet

Método ObterEstrutura() 1. 2. 3. 4. 5.

' Editora é uma classe que herda de UniComponentBSDB. Dim objEditora As Editora = New Editora

'Posso obter a estrutura de qualquer tabela da Origem de Dados atual InnerDataSet = objEditora.ObterEstrutura(“Livro”)

Método ObterTodos() 1. 2. 3. 4. 5.

' Editora é uma classe que herda de UniComponentBSDB. Dim objEditora As Editora = New Editora

'A consulta é retornada e carregada no InnerDataSet do componente. objEditora.ObterTodos()

Método ObterPorPK() 1. 2. 3. 4. 5. 6. 7. 8.

' Editora é uma classe que herda de UniComponentBSDB Dim objEditora As Editora = New Editora objEditora("Identificador") = Marcados(0)(0) 'Marcados possui a chave

procurada. 'A consulta é retornada e carregada no InnerDataSet do componente. InnerDataSet = objEditora.ObterPorPK()

Método ObterPorPK( Lista de Campos )

Método ObterPorPK trazendo somente os campos Nome e Endereco na consulta. Esse recurso

também está disponível no ObterPorFiltro().

1. 2. 3. 4. 5.

' Editora é uma classe que herda de UniComponentBSDB Dim objEditora As Editora = New Editora objEditora("Identificador") = Marcados(0)(0) 'Marcados possui a chave procurada. 'A consulta é retornada e carregada no InnerDataSet do componente.

Pág.:18

6. 7.

objEditora.ObterPorPK("Nome, Endereco") InnerDataSet = objEditora.InnerDataSet

Método ObterPorFiltro()

Método ObterPorFiltro trará todas as linhas no banco de dados que atenderem o filtro no campo

Endereco e Telefone. 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12.

' Autor é uma classe que herda de UniComponentBSDB Dim objAutor As Autor = New Autor

objAutor("Endereco") = Marcados(0)(0)

'Outra forma de configurar o componente é acessando direto o InnerDataRow. objAutor.InnerDataRow("Telefone") = Marcados(0)(1) 'A consulta é retornada e carregada no InnerDataSet do componente. objAutor.ObterPorFiltro() InnerDataSet = objEditora.InnerDataSet

Método Inserir() 1. 2. 3. 4. 5. 6. 7. 8. 9. 10.

' Editora é uma classe que herda de UniComponentBSDB que utiliza de Seqüência. Dim objEditora As Editora = New Editora objEditora("Nome") = "Abril" objEditora("Endereco") = "Rua ABCD"

objEditora.Inserir()

'Obtém o identificador obtido na Inserção Dim NovoIdentificador As Integer = objEditora("Identificador")

Método Alterar() 1. 2. 3. 4. 5. 6. 7.

' Editora é uma classe que herda de UniComponentBSDB que utiliza de Seqüência. Dim objEditora As Editora = New Editora

objEditora("Identificador") = 10 objEditora("Endereco") = "Rua EFGH" objEditora.Alterar()

Método Excluir() 1. 2. 3. 4. 5. 6.

' Editora é uma classe que herda de UniComponentBSDB que utiliza de Seqüência. Dim objEditora As Editora = New Editora

objEditora("Identificador") = 10 objEditora.Excluir()

Customizando classes que usam de UniComponentBSDB

Conforme foi visto no tópico anterior a classe UniComponentBSDB prover diversas funcionalidades

para facilitar a implementação de classes de dados e negócios referentes às tabelas de cadastro. No entanto

vão existir casos onde o componente precisará de uma customização em seu comportamento, ou até mesmo

uma sobreposição de funcionalidade. Veremos a seguir alguns casos que poderão ser comuns:

1. Validação de uma Operação

Pág.:19

O componente UniComponentBSDB oferece o método Validar() recebendo o parâmetro com o tipo da

operação que irá ser executada. Esse método é chamado antes do componente executar uma operação na

base de dados, exceto no caso do ObterTodos(). Conforme vimos no tópico anterior o comportamento padrão

desse método é o seguinte:

o Verifica se foi indicada a chave primária na realização das operações de ObterPorPK, Inserir,

Alterar e Excluir.

o Verifica se foram preenchidos os campos obrigatórios na realização das operações de Inserir,

Alterar.

Os casos acima nem sempre corresponderão a necessidade de negócio das implementações do dia-

dia, muitas das vezes se faz necessário realizar validações de contexto de negócio, como por exemplo a

verificação de um intervalo de data, ou do tamanho de um parâmetro do tipo string, entre outras diversas

validações.

Veremos abaixo um exemplo de implementação o qual iremos validar se o campo endereço não

possui um tamanho superior a 50 caracteres, caso o campo esteja inválido estaremos levantando uma

exceção.

1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. 16. 17. 18. 19. 20. 21.

Private Const cErrCampoTamanhoInvalido As String = "ErrCampoTamanhoInvalido"

Protected Overrides Sub Validar(ByVal TipoOperacao As Unitech.Component.UniComponentBSDB.enumTipoOperacao)

'Reaproveito a implementação do Validar do UniComponentBSDB MyBase.Validar(TipoOperacao) If (TipoOperacao = Unitech.Component.UniComponentBSDB.enumTipoOperacao.Inserir Or TipoOperacao = Unitech.Component.UniComponentBSDB.enumTipoOperacao.Alterar) Then

'Só permitirá inserção ou alteração na base de dados do campo Endereco 'com uma string menor ou igual a 50 caracteres. If (InnerDataRow("Endereco").ToString().Length > 50) Then Dim mensagem As String = BS.Dicionario.GetString(cErrCampoTamanhoInvalido, New String() {"campo"}, New String() {"endereco"}) 'Recuperação de Mensagem Dinâmica Throw New Unitech.Exception.ValorInvalidoException(mensagem) End If

End If End Sub

Como podemos ver no código acima a ampliação do comportamento do método Validar é simples,

basta para isso sobrescrever o método, como é realizado na linha 3. Note também que é reaproveitado o

comportamento original através da chamada do Validar da classe ancestral (linha 7). Na linha 8 é restringida a

validação somente para as operações de Inserir e Alterar. Utilizamos também de uma mensagem de erro

dinâmica dicionarizada o qual irá trazer uma informação referenciando o campo endereço. Caso a validação

verifique a irregularidade do tamanho campo será levantado um erro de valor inválido com a mensagem

descrevendo o mesmo (linha 18).

2. Sobrescrevendo uma operação básica

Existirão casos particulares em que será necessário sobrescrever o comportamento padrão do

componente referente a alguma operação, tais como Inserir, Alterar, Excluir, ObterPorPk, entre outros. Todos

os métodos da componente foram implementados possibilitando uma futura sobreposição.

Abaixo temos um exemplo de como re-implementar o método Inserir.

Pág.:20

1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. 16. 17. 18. 19. 20. 21. 22. 23. 24. 25. 26. 27. 28. 29. 30. 31. 32. 33. 34. 35. 36. 37. 38.39. 40. 41. 42. 43.

<TransactionContext(Transaction.Required, Isolation:=Isolation.ReadCommitted)> _ Public Overrides Sub Inserir() Dim Retorno As Int32

Try Dim cmd As Unitech.Data.UniCommand = New Unitech.Data.UniCommand(SiglaDataSource) Dim query As String

'Monta a query query = "INSERT INTO Editora " & _ "(Identificador, Nome, Endereco) " & _ "VALUES " & _ "(@Identificador, @Nome, @Endereco)" cmd.CommandText = query 'Atribui valores aos parâmetros que estão na query montada acima InnerDataRow("Identificador") = GetNewNumber("Editora") cmd.Parameters.Add("@Identificador", InnerDataRow("Identificador")) cmd.Parameters.Add("@Nome", InnerDataRow("Nome")) cmd.Parameters.Add("@Endereco", InnerDataRow("Endereco")) 'Chama o método de Validação do UniComponentBSDB Validar(Unitech.Component.UniComponentBSDB.enumTipoOperacao.Inserir) 'Instancia um objeto do tipo IDataBase de acordo com a sigla da origem 'dados informada no contrutor da classe pai Dim SGBD As Unitech.Data.IDatabase = CreateDataBaseInstance() 'Executa o command passado com parâmetro SGBD.Execute(cmd.ObjCommand) 'Informa ao gerenciador de transação que toda os passos 'do método foi executado com sucesso. TransactionManager.SetComplete()

Catch ex As System.Exception 'Informa ao gerenciador de transação que houve problemas 'durante a execução do método. TransactionManager.SetAbort() Throw ex

End Try End Sub

2.6. Auditoria

O UNIFW possui recursos de Auditoria que possibilitam que operações realizadas pelo usuário possam ser auditadas mais adiante. A partir do cadastramento de Trilhas, Alvos e Escopos(ver Guia do Administrador), o UniFW automaticamente cria registros de operação(tabela OperacaoAuditoria) com as seguintes informações:

• Identificador: chave primária. Número que identifica unicamente um registro de operação criado pelo UniFW.

• IdenTrilhaAuditoria: identificador da trilha de auditoria que enquadrou a operação realizada em seu escopo e alvo, provocando a sua criação.

• IdenUsuario: Identificador do Usuário que está solicitando a execução da operação. • IdenTela: identificador da Tela utilizada para solicitação da operação. • IdenFuncao: identificador da função associada com a operação solicitada. • Data: data em que a operação foi solicitada. • EnderecoRemoto: Endereço IP, ou Host, da máquina cliente usada para solicitar a operação. • SiglaDominioUsuario: sigla do domínio do usuário que está solicitando a execução da operação. • LoginUsuario: login do usuário que está solicitando a execução da operação. • NomeUsuario: nome do usuário que está solicitando a execução da operação. • Interface: definição da interface utilizada para executar a operação. Usado o padrão “ SiglaAplicacao/SiglaModulo/NomeTela”

• Função: nome da função que está relacionada com a operação solicitada. Ex.:”Cadastrar Funcionário”

Pág.:21

Além dessas informações, se faz necessária a possibilidade de registrar quais as modificações realizadas nos registros(tabelas) das aplicações. Ou seja, que registros foram modificados/excluídos/alterados durante a execução de uma determinada operação. No UniFW, através de suas classes IDataBase de acesso a base de dados, para realizar os registros de alteração/exclusão/inclusão de registros em banco de dados, cada tabela a ser controlada deverá possui uma outra tabela de auditoria que armazene as modificações feitas na mesma. Por exemplo, para uma tabela “FUNCIONARIOS” deverá existir uma outra tabela de auditoria chamada “AUDIT_FUNCIONARIOS” com a mesma estrutura básica de campos da primeira. Sempre que uma alteração/exclusão/inclusão for realizada na tabela “FUNCIONARIOS”, um trigger na mesma deverá inserir um novo registro na tabela “AUDIT_FUNCIONARIO” para registrar os dados alterados/excluídos/incluídos.

Como dito anteriormente, a tabela de auditoria possui a mesma estrutura básica de campos de sua

tabela referência. Porém, alguns campos adicionais são necessários na mesma: • IdenAuditoria: campo IDENTITY que deverá ser a chave primária da tabela de auditoria. • IdenOperacaoAuditoria: campo que armazenará o identificador da operação de auditoria criada pelo UniFW e relacionada com a alteração de dados que está sendo feita.

• IndicadorExclusao: campo que indica se é uma operação de exclusão de registro=>valor 1. Segue abaixo um script exemplificando a criação de uma tabela de auditoria:

CREATE TABLE [NomeTabelaAuditoria] ( [IdenAuditoria] [int] IDENTITY (1, 1) NOT NULL , [IdenOperacaoAuditoria] [int] NOT NULL , [IndicadorExclusao] [bit] NOT NULL , [Campo1] [int] NULL , [Campo2] [varchar] (20), [Campo3] [varchar] (50), [Campo4] [varchar] (150) ) ON [PRIMARY] GO

Onde [Campo1], [Campo2], [Campo3] e [Campo4] são os campos da tabela de dados referenciada(Ex.:

FUNCIONARIOS) e que armazenarão os dados da mesma na tabela de auditoria(Ex.: AUDIT_FUNCIONARIOS).

Por fim o desenvolvedor deverá criar uma trigger para a tabela de referência desejada. Seguem

exemplos: SQL CREATE TRIGGER trNomeTabelaAuditoria ON NomeTabela FOR INSERT, UPDATE, DELETE AS DECLARE @IdenOperacao INT exec INFRAObtemIdOperacaoAuditoria @IdenOperacao OUTPUT IF @IdenOperacao IS NOT NULL BEGIN IF EXISTS(SELECT * FROM inserted) INSERT NomeTabelaAuditoria (IdenOperacaoAuditoria, IndicadorExclusao, campo1, campo2, campo3, campo4...) SELECT @IdenOperacao, 0, d.* FROM inserted d ELSE INSERT NomeTabelaAuditoria (IdenOperacaoAuditoria, IndicadorExclusao, campo1, campo2, campo3, campo4...) SELECT @IdenOperacao, 1, d.* FROM deleted d END ORACLE TRIGGER TR_AUDIT_NOMETABELA BEFORE DELETE OR INSERT OR UPDATE ON NOMETABELA FOR EACH ROW DECLARE ID_OPERACAO NUMBER(9); BEGIN ID_OPERACAO := NVL(PKG_UFW_AUDITORIA.IDENTIFICADOR_OPERACAO ,0); -- Verifica se existe uma operação auditoria criada pela UniFW.NET IF ID_OPERACAO <> 0 THEN -- Realiza a auditoria para os casos de inserção ou alteração IF INSERTING OR UPDATING THEN INSERT INTO AuditoriaNomeTabela (IdenAuditoria, IdenOperacaoAuditoria, IndicadorExclusao, campo1, campo2, campo3...) VALUES

Pág.:22

(SEQUENCIA.nextval, ID_OPERACAO, 0, :new.CAMPO1, :new.CAMPO2, :new.CAMPO3...); END IF; -- Registra exclusão IF DELETING THEN INSERT INTO AuditoriaNomeTabela (IdenAuditoria, IdenOperacaoAuditoria, IndicadorExclusao, campo1, campo2, campo3...) VALUES (SEQUENCIA.nextval, ID_OPERACAO, 0, :old.CAMPO1, :old.CAMPO2, :old.CAMPO3...); END IF; END IF; END; A procedure INFRAObtemIdOperacaoAuditoria busca o valor do Identificador da operação e grava na variável passada como parâmetro de OUTPUT, no exemplo acima @IdenOperacao, declarada como INT. O valor do identificador da operação corrente é responsabildiade do UniFW. Analogamente, existe uma variável PKG_UFW_AUDITORIA.IDENTIFICADOR_OPERACAO que serve para a mesma finalidade em bases Oracle. Chamaremos estes dois recursos de Identificador da Operação no decorrer deste documento. Existem casos em que operações de alteração em banco de dados são realizadas através de apliações não implementadas através do UniFW. Por exemlpo, pode-se, através do QueryAnalyzer ou SQL Plus, efetuar um INSERT em uma determinada tabela do sistema. Neste caso, o Identificador da Operação sempre retornará Null através de seu parâmetro. Isso se deve ao fato de a operação não ter passado pelo controle do UniFW para ser realizada, logo a mesma não foi registrada. Para que o registro de operação de auditoria seja possível nesses casos, se faz necessário verificar o valor do Identificador da Operação no trigger. Caso o mesmo seja Null, dois são os significados possíveis:

1. Apesar de ter passado pelo controle do UniFW, a operação solicitada não se enquadrou em nenhuma trilha cadastrada no UniFW. Logo, para o UniFW não é necessário registrar a operação de auditoria.

2. A operação realizada não passou pelo controle do UniFW(classes IDataBase), logo o mesmo não pôde verificar se um registro de auditoria deveria ser criado.

Para ambas as situações, o desenvolvedor do trigger de auditoria deverá identificar, a partir de critérios específicos da sua aplicação, a necessidade de efetuar os registros de auditoria. Caso seja identificado que existe a necessidade de registrar a operação de auditoria, tendo o Identificador da Operação retornado Null, poderá ser utilizada uma outra procedure disponibilizada pelo UniFW, denominada INFRAObtemIdOperacaoExternaAuditoria(SQLServer) ou INFRAObtemIdOperExternaAudit(Oracle). Esta procedure tem como objetivo criar um registro de operação a partir de informações passadas pelo desenvolvedor e retornar para o identificador dado à mesma. Abaixo seguem exemplos de trigger de auditoria que se utilizam dessa procedure(destaque em vermelho): SQL CREATE TRIGGER trAuditoriaFuncionarios ON Funcionarios FOR INSERT, UPDATE, DELETE AS DECLARE @IdenOperacao INT exec INFRAObtemIdOperacaoAuditoria @IdenOperacao OUTPUT -- Verifica se existe uma operação auditoria criada pela UniFW.NET IF @IdenOperacao IS NULL BEGIN -- Caso essa operação não exista, decide-se pela criação manual de uma operação auditoria. exec INFRAObtemIdOperacaoExternaAuditoria @IdenOperacao OUTPUT, null, null, null, null, 'IPHostCliente', 'DOMUSR', 'LoginUSR', 'Nome do usuário', 'Query Analyzer', 'Inclusão de Funcionario' END -- Verifica qual é o tipo da operação IF EXISTS(SELECT * FROM inserted) -- Realiza a auditoria para os casos de inserção e alteração INSERT Audit_Funcionario (IdenOperacaoAuditoria, IndicadorExclusao, Matricula, Nome, Cargo, Salario) SELECT @IdenOperacao, 0, d.* FROM inserted d ELSE -- Realiza a auditoria para os casos de exclusão INSERT Audit_Funcionario (IdenOperacaoAuditoria, IndicadorExclusao, Matricula, Nome, Cargo, Salario)

Pág.:23

SELECT @IdenOperacao, 1, d.* FROM deleted d

ORACLE TRIGGER TR_AUDIT_NOMETABELA BEFORE DELETE OR INSERT OR UPDATE ON NOMETABELA FOR EACH ROW DECLARE ID_OPERACAO NUMBER(9); BEGIN ID_OPERACAO := NVL(PKG_UFW_AUDITORIA.IDENTIFICADOR_OPERACAO ,0); -- Verifica se existe uma operação auditoria criada pela UniFW.NET IF ID_OPERACAO = 0 THEN -- Caso essa operação não exista, decide-se pela criação manual de uma operação auditoria. INFRAObtemIdOperExternaAudit(ID_OPERACAO, null, null, null, null, 'IPHostCliente', 'DOMUSR', 'LoginUSR', 'Nome do usuário', 'SQL Plus', 'Nome da Funcionalidade'); END IF; -- Realiza a auditoria para os casos de inserção ou alteração IF INSERTING OR UPDATING THEN INSERT INTO AuditoriaNomeTabela (IdenAuditoria, IdenOperacaoAuditoria, IndicadorExclusao, campo1, campo2, campo3...) VALUES (SEQUENCIA.nextval, ID_OPERACAO, 0, :new.CAMPO1, :new.CAMPO2, :new.CAMPO3...); END IF; -- Registra exclusão IF DELETING THEN INSERT INTO AuditoriaNomeTabela (IdenAuditoria, IdenOperacaoAuditoria, IndicadorExclusao, campo1, campo2, campo3...) VALUES (SEQUENCIA.nextval, ID_OPERACAO, 0, :old.CAMPO1, :old.CAMPO2, :old.CAMPO3...); END IF; END; O trecho em vermelho exemplifica o uso da procedure responsável pela criação de uma operação auditoria a partir de parâmetros passados pelo desenvolvedor. Seus parâmetros são:

• IdenOperacao: (obrigatório) Parâmetro OUTPUT que retornará o identificador dado à nova operação criada.

• IdenTrilhaAuditoria: Identificador da trilha de auditoria cadastrada no UniFW responsável pela realização do registro de operação. Null quando não identificado.

• IdenUsuario: Identificador do usuário cadastrado no UniFW que solicitou a execução da operação. Null quando não identificado.

• IdenTela: Identificador da tela da aplicação cadastrada no UniFW que foi utilizada para executar a operação. Null quando não identificada.

• IdenFunção: Identificador da função cadastrada no UniFW que representa a operação executada. Null quando não identificada.

• EnderecoRemoto: HOST/IP da máquina cliente utilizada para executar a operação. Null quando não possível a identificação.

• SiglaDominioUsuario: (obrigatório) Sigla do domínio do usuário que solicitou a execução da operação. Pode não ser um domínio cadastrado no UniFW, mas poderá ser usado como critério de busca no relatório de auditoria disponibilizado pelo UniFW.

• LoginUsuario: (obrigatório) Login do usuário que solicitou a execução da operação. Pode não ser um login de usuário cadastrado no UniFW, mas poderá ser usado como critério de busca no relatório de auditoria disponibilizada pelo UniFW.

• NomeUsuario: (obrigatório) Nome do usuário que solicitou a execução da operação. • Interface: (obrigatório) Nome ou descrição da interface usada para executar a operação. Ex.:

“QueryAnalyser” ou “AplicacaoX/ModuloY/TelaZ”. • Função: (obrigatório) Nome da função que está sendo executada. Ex.: “Cadastro de clientes”,

“Aprovação de Crédito”. Não necessita ser uma das funções cadastradas no UniFW, mas poderá ser usado como critério de busca no relatório de auditoria disponibilizada pelo UniFW.

Pág.:24

2.6.1. Registro de Atributo de Auditoria

Em certas situações, a utilização de triggers não é suficiente para a auditoria de informações que foram manipuladas por uma operação realizada na aplicação. Por exemplo, como nenhum trigger é executado em operações de consulta, não se tinha como saber qual o número do Processo Administrativo consultado por um determinado usuário em um determinado dia, pois para consultar os dados de um Processo Administrativo apenas comandos de SELECT foram executados na base de dados.

Como solução para esse problema o UniFW possibilita fazer registros de informações relacionadas com a operação de auditoria corrente em tempo de execução mesmo sem a execução de triggers. Ou seja, além das informações já existentes sobre uma operação auditoria (ex.: Data, LoginUsuario, Função etc) é possível definir outros atributos para as entidades e definir seus valores em tempo de execução do sistema. Depois de registrados, esses valores podem ser consultados através da ‘Consulta de Auditoria’ do UniFW na tela de detalhamento(ver Guia do Administrador) como um atributo qualquer de uma entidade.

Para se registrar um novo atributo de auditoria, utiliza-se do método RegistraAtributo da classse UNIFW.Auditoria.BS.Auditoria. Este método recebe como parâmetros duas Strings: o nome do novo atributo a ser definido e o valor do mesmo. Vale ressaltar que a nomenclatura para nomes de atributos deve ter o seguinte padrão:

“EntidadeAuditoria.NomeAtributo”

Onde: • EntidadeAuditoria é o nome da entidade de auditoria cadastrada no UniFW(ver guia do Adminsitrador) relacionada com o novo atributo definido.

• NomeAtributo é o nome do novo atributo que receberá um valor. Esse atributo também deverá estar cadastrado no UniFW(ver guia do Administrador) como um atributo da entidade.

Abaixo, segue um exemplo de código que registra um novo atributo na operação de auditoria corrente

através da classe UNIFW.Auditoria.BS.Auditoria:

Dim Audita As Unitech.UNIFW.Auditoria.BS.Auditoria = New Unitech.UNIFW.Auditoria.BS.Auditoria() Audita.RegistrarAtributo("Processo.numero",”1350”)

No exemplo acima, é inserido um novo atributo de nome “numero” na entidade de nome “Processo” com o valor “1350”. Se não existir operação corrente, nada será registrado. Na tela de relatório de auditoria do UniFW(ver Guia do Administrador) o mesmo poderá ser utilizado como critério de busca ou como informação a ser consultada.

2.6.2. Criação de uma nova Operação de Auditoria Existirão alguns casos na auditoria de consulta (vide tópico Registro de Atributo Auditoria) onde será

necessária a criação de uma nova operação auditoria. Esses casos geralmente envolvem situações de postback as quais recuperam a operação de auditoria anterior não possibilitando a criação de mais de um atributo de auditoria com o mesmo nome. Um caso de exemplo para essa funcionalidade são telas de consulta as quais possuem variáveis de filtro a serem auditadas, dessa forma para evitar que esses atributos auditados sejam sobrescritos a cada postback utiliza-se o recurso de criação de uma nova operação auditoria.

Para realização dessa funcionalidade temos o método CriarNovaOperacaoAuditoria da classe Auditoria referente ao namespace Unitech.UNIFW.Auditoria.BS, abaixo temos um exemplo de como utilizar o recurso:

Dim Audita As Unitech.UNIFW.Auditoria.BS.Auditoria = New Unitech.UNIFW.Auditoria.BS.Auditoria() Audita.CriarNovaOperacaoAuditoria()

2.6.3. Auditoria automática em POSTBACK

O UniFW.NET ainda disponibiliza uma outra forma de auditoria em POSTBACK. Para isso é preciso ter toda a configuração da trilha a ser auditada feita no UniFW.NET e algum controle que implemente Unitech.Web.WebControls.ISubmitControl na página. Atualmente apenas o UniButton, o UniLinkButton e o UniImageButton implementam esta interface.

Pág.:25

Controles que implementam esta interface possuem as propriedades Aplicação, Modulo, Tela, Ação e AuditaPostBack. De posse destas propriedades o UniFW, a cada PostBack, terá condições de verificar se uma função será auditada ou não. Para isto, as quatro primeiras propriedades (Aplicação, Modulo, Tela e Ação) devem estar obrigatoriamente preenchidas e de acordo com o cadastro do banco do UniFW.NET e a propriedade AuditaPostBack deve estar com o valor True.

O funcionamento se dá da seguinte forma: No momento em que um ISubmitControl causa um POSTBACK, a sua propriedade AuditaPostBack é avaliada, caso ela esteja definida como true o UniFW verificará as outras 4 propriedades e fará a verificação se a funcionalidade deve ser auditada ou não. Obs.: caso uma das quatro propriedades não seja informada, o UniFW não chamará o Auditor. Só depois disso os eventos associados ao contorle serão disparados.

2.7. Transaction Manager (TM)

Conforme foi visto no tópico anterior o UniComponent permite que o programador possa utilizar origem de dados diferentes para suas classes de dados / negócios, mas para isso basta informar a SiglaDataSource referente a origem de dados a ser acessada.

O SQLDatabaseTM segue os mesmos padrões do SQLDatabase pois ambos implementam IDataBase, a diferença é que o SQLDatabaseTM utiliza o componente de acesso a dados TM (Transaction Manager) enquanto que o SQLDatabase não possui um componente controle de transação.

O componente TM é uma solução que vem representar uma alternativa ao COM+ em relação a gerenciamento de transações de forma declarativa. Essa substituição veio no sentido de oferecer melhor desempenho em relação ao COM+.

O diagrama abaixo apresenta o modelo conceitual do TM.

O diagrama acima demonstra que a partir de uma interface IData se instancia objetos de acesso a base

de dados MSSql, OleDbData e XMLData.

Abaixo segue exemplo de uma classe de dados utilizando o UniComponent e referenciando SQLDatabaseTM. 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. 16. 17.

Public Class Template Inherits UniComponent Public Sub New() SiglaDataSource = "UNIFWTM" End Sub Function NewNumber() As Integer Return GetNewNumber(Me.GetType().Name.ToString()) End Function <TM.TransactionContext(Transaction.Required, Isolation:=Isolation.ReadCommitted)> _ Function Inserir(ByRef DS As DataSet) As Int32 Implements BS.ITemplate.Inserir Dim Retorno As Int32 Try Dim SGBD As Unitech.Data.IDatabase = CreateDataBaseInstance(SiglaDataSource)

Pág.:26

18. 19. 20.

21. 22. 23. 24. 25. 26. 27. 28. 29. 30. 31. 32. 33. 34. 35. 36. 37. 38. 39. 40. 41. 42. 43. 44. 45. 46.

DS.Tables(0).Rows(0)("Identificador") = NewNumber() Retorno = SGBD.SPExecute("SEGURTemplateINS", SGBD.FillParameters("SEGURTemplateINS", DS.Tables(0).Rows(0))) TransactionManager.SetComplete() Return Retorno Catch ex As System.Exception TransactionManager.SetAbort() Throw ex End Try End Function <TM.TransactionContext(Transaction.Supported, Isolation:=Isolation.ReadCommitted)> _ Function ObterTodos() As DataSet Implements BS.ITemplate.ObterTodos Dim dsRetorno As DataSet Try Dim SGBD As Unitech.Data.IDatabase = CreateDataBaseInstance(SiglaDataSource) dsRetorno = SGBD.SPGetData("SEGURTemplateSEL", "Template") TransactionManager.SetComplete() Return dsRetorno Catch ex As System.Exception TransactionManager.SetAbort() Throw ex End Try End Function End Class

Abaixo, o exemplo acima é mais detalhado: 1. O construtor dessa classe deve especificar a propriedade SiglaDataSource. (linhas 4 à 6) 2. O método NewNumber() nada mais é que o GetNewNumber() recebendo o nome da classe como

parâmetro. (linhas 8 à 10) 3. Em todo método que realizará acesso a base de dados deverá ter o atributo <TM.TransactionContext>,

conforme é apresentado nas linhas 12 e 30. Esse atributo é responsável pela configuração do tipo de transação que será realizada. È necessário que alguns parâmetros sejam especificados que são: (i) o comportamento da transação e (ii) o nível de isolamento da mesma (isolation level). 3.1. O contexto da transação possui quatro possíveis comportamentos:

3.1.1. Disabled: Suporte a transação esta desabilitada. 3.1.2. NotSupported: O objeto nunca participa da transação. 3.1.3. Supported: O objeto participa da transação, se existir. 3.1.4. Required: Se existir o objeto participa da transação, caso contrário cria uma nova transação. 3.1.5. RequiredNew: O objeto sempre cria uma nova transação.

4. É necessário que exista sempre o tratamento de erro (Try...Catch). O método TransactionManager.SetComplete() é responsável pelo Commit da transação corrente, sem esse método o TM não poderá validar a transação efetuada. É importante que esse método fique após a execução da operação, para que o TM avalie se ocorreu ou não uma exceção (exception) e possa validar a operação efetuada. Já o método TransactionManager.SetAbort( é responsável pelo Rollback da transação corrente), este método deve ser chamado dentro do catch.

2.8. Integração com Workflow Para que uma classe de negócio possa ser integrada com o módulo de Workflow ela deve implementar

a interface Unitech.Workflow.IFluxoUtil, o que torna obrigatória a existência do método Transitar. Este método deve chamar o método Transitar da classe Unitech.Workflow.Util passando os dados da entidade que a classe de negócio representa dentro do Fluxo do Workflow.

Segue um exemplo de código do método transitar: 1. 2. 3. 4. 5. 6. 7. 8.

<TM.TransactionContext(Transaction.Required, Isolation:=Isolation.ReadCommitted)> _ Public Function Transitar(ByVal dsTrans As DataSet) As Int32 Implements Workflow.BS.IFluxoUtil.Transitar Dim dsPublicacao As DataSet Dim ds As DataSet Dim dt As DataTable Dim Retorno As Int32

Pág.:27

9. 10. 11. 12. 13. 14. 15. 16. 17. 18. 19. 20. 21. 22. 23. 24. 25. 26. 27. 28. 29. 30. 31.

Try ds = New DataSet dt = New DataTable dt.Columns.Add("IdenEntidadeFluxo", System.Type.GetType("System.Int32")) ds.Tables.Add(dt) ds.Tables(0).Rows.Add(dt.NewRow()) ds.Tables(0).Rows(0)("IdenEntidadeFluxo") = dsTrans.Tables(0).Rows(0)("EntidadeFluxo") 'Obtendo dados da entidade de negocio dsPublicacao = ObterPublicacaoDB().ObterPorEntidadeWKF(ds) 'Validacao das regras de negócio dsTrans = ValidaRegraNegocio(dsTrans, dsPublicacao) Retorno = Unitech.Workflow.Util.Transitar(dsTrans) TransactionManager.SetComplete() Return Retorno Catch ex As System.Exception TransactionManager.SetAbort() Throw ex End Try End Function

No trecho acima (linha 21), podemos verificar a chamada para um método de validação antes da

chamada da transição, este método serve para definir algumas regras de negócio da classe em relação ao fluxo, tal como o nível de importância daquela entidade em relação ao fluxo.

Existe um ponto importante na integração de uma classe de negócio com o Workflow que é o momento da inserção de um novo registro no Banco de Dados. A classe neste momento ainda não possui o seu identificador no fluxo correspondente cadastrado no módulo de Workflow. Para isto o método transitar da classe Unitech.Workflow.Util retorna o identificador da entidade criada no fluxo (linha 23). Isto ocorre quando o DataSet passado como parâmetro ao método transitar não possui o campo IdenEntidadeFluxo preenchido. A classe Unitech.Workflow.Util entende que se trata da criação de uma nova entidade no fluxo e devolve este Identificador. De posse do identificador pode-se efetuar então a inserção do registro, a partir deste ponto, qualquer transição de estados no workflow deverá informa o identificador da entidade no fluxo através do campo IdenEntidadeFluxo no parâmetro DataSet. Segue um exemplo do método Inserir de uma classe integrada ao Workflow: 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13.

14.

15.

16.

17.

18. 19. 20. 21.

22.

23. 24. 25. 26. 27.

<TM.TransactionContext(Transaction.Required, Isolation:=Isolation.ReadCommitted)> _ Public Function Inserir(ByVal dsPublicacao As DataSet) As Integer Dim RowsAffected As Int32 Try Validar(dsPublicacao.Tables(0).Rows(0), TipoOperacao.Inserir) Dim dsTrans As DataSet dsTrans = Unitech.Workflow.Util.TransistionStructure 'Regras para Transicoes Inicial e Normal dsTrans.Tables(0).Rows(0)("SiglaFluxo") = CTX_SIGLAFLUXO dsTrans.Tables(0).Rows(0)("EntidadeFluxo") = dsPublicacao.Tables(0).Rows(0)("IdenEntidadeFluxo") dsTrans.Tables(0).Rows(0)("EstadoFluxoDestino") = dsPublicacao.Tables(0).Rows(0)("IdenEstadoDestino") dsTrans.Tables(0).Rows(0)("UsuarioTransicao") = dsPublicacao.Tables(0).Rows(0)("IdenUsuarioTransicao") dsTrans.Tables(0).Rows(0)("NovoUsuarioResponsavel") = dsPublicacao.Tables(0).Rows(0)("IdenResponsavel") dsTrans.Tables(0).Rows(0)("GrupoInteresse") = dsPublicacao.Tables(0).Rows(0)("IdenGrupoInteresse") dsTrans.Tables(0).Rows(0)("XMLEntidade") = XMLEntidade(dsPublicacao) 'Validacao das regras de negócio dsTrans = ValidaRegraNegocio(dsTrans, dsPublicacao) dsPublicacao.Tables(0).Rows(0)("IdenEntidadeFluxo") = Unitech.Workflow.Util.Transitar(dsTrans) RowsAffected = ObterPublicacaoDB().Inserir(dsPublicacao) TransactionManager.SetComplete() Return RowsAffected

Pág.:28

28. 29. 30. 31. 32.

Catch ex As System.Exception TransactionManager.SetAbort() Throw ex End Try End Function

2.9. Tratamento de Erros

O tratamento de erros no Unifw.NET possui dois pontos principais: o assembly Unitech.Exception e a

Classe Unitech.Web.FWError. O desenvolvedor precisa definir no Web.config qual a tela que irá capturar e mostrar as mensagens de erro ao usuário (veja Web.config na seção Configuração do Ambiente). Este quadro deve herdar de Unitech.Web.FWError e então poderá utilizar a variável exception da sua classe ancestral.

O tratamento de erros em código é feito através dos blocos try...catch...finaly. Na cláusula Catch o desenvolvedor escolhe uma dentre as classes de Unitech.Exception e passa a mensagem do erro obtido através do método GetString em Dicionario (namespace Unitech.UNIFW.Dicionário.BS). As mensagens de erros devem estar cadastradas no módulo Dicionário em uma pasta específica (.../Erro/) para que possam ser exibidas corretamente. Segue um exemplo de tratamento de uma exceção numa classe de negócio: Private Sub Validar(ByVal CanalRow As DataRow, ByVal operacao As TipoOperacao) If (operacao = TipoOperacao.Excluir) Or (operacao = TipoOperacao.Alterar) Then If (CanalRow("Identificador") Is DBNull.Value) Then Throw New Unitech.Exception.EnvironmentException(Dicionario.GetSrtring("ErrIdentificadorNulo")) End If End If End Sub

Para tornar as mensagens de erros customizadas para os usuários utilize o recurso de mensagens dinâmicas. Veja o exemplo no tópico “Dicionário”.

Pág.:29

3. Implementando a camada de apresentação

3.1. Introdução A implementação da camada de apresentação de aplicações na plataforma ASP.NET traz uma grande

mudança em relação ao antigo ASP, a separação entre código e layout tornou-se mais intuitiva, visto que os arquivos .aspx/.ascx são destinados ao layout das páginas, deixando a execução para outros arquivos, os .aspx.xx/.ascx.xx onde xx são letras que representam a linguagem, ex: vb = Visua Basic, cs = C-Sharp, etc.

O framework .NET possui uma forma de execução das páginas com passos predefinidos onde o desenvolvedor pode interferir no comportamento e execução de eventos das páginas.

3.2. Projeto da Camada de Apresentação O projeto contêiner da camada de apresentação geralmente é o projeto da própria aplicação WEB.

Nesse projeto é criada uma estrutura de diretórios onde as classes serão agrupadas por módulos. (estrutura de diretório apresentada em URLs e arquivos) Essas classes são representadas pelos controles de usuários (arquivos ASCX). Deve se referenciar todos os componentes do Framework UniFw (Unitech.Unifw.*) assim como as referências para as dlls dos projetos de negócio (Unitech.Unifw.*.BS) e os de dados (Unitech.Unifw.*.DB). Além dessas deve se referenciar:

- System - System.Data - System.Drawing - System.Web - System.WebServices - System.XML

3.3. ASPX x ASCX

Na plataforma .NET os arquivos com extensão ASPX são as páginas propriamente ditas, e os ASCX são controles de usuários que podem ser carregados a partir de uma página (ASPX), ambos possuem layout (HTML) e código, mas o servidor IIS somente entenderá uma requisição a um ASPX. Uma página ASPX pode conter um ou mais controles ASCX, além de códigos HTML, o contrário não é possível.

O Unifw.NET trabalha sobre a seguinte estrutura de montagem de páginas: uma página ASPX contém um Controle ASCX principal (Template) e este contém outros controles ASCX (Quadros) que serão arrumados conforme o layout proposto por esse Template. Estes quadros, por sua vez, irão possuir os controles visuais de interação com o usuário. Para que fique mais claro veja a ilustração da seção “A Classe Unitech.Web.Template” mais adiante:

3.4. A Classe Unitech.Web.FWPage

Toda página ASPX deve herdar de FWPage para que possa utilizar os recursos de Segurança, Montagem automática de quadros e Auditoria do UNIFW. O UNIFW propõe que você desenvolva uma única página ASPX (Default.aspx por exemplo) contendo um controle do tipo PlaceHolder com id=”PagePH”, este controle será o container principal para seus templates, que serão, por sua vez, containers para seus quadros, tudo isso previamente cadastrado na Base de Dados. Note que o Controle PlaceHolder é obrigatório, e seu identificador tem que ser “PagePH”.

No carregamento da sua página que herda de FWPage, ocorre a Validação de Segurança, Auditoria e Carregamento do Template, nesta ordem.

Pág.:30

3.5. A Classe Unitech.Web.Template

Cada template no UNIFW é um UserControl (ASCX), ele tem a finalidade de formatar a disposição dos

quadros da tela. O processo ocorre da seguinte forma: cada controle adicionado ao seu template deve conter um Identificador que corresponda à sigla do quadro cadastrado, para que este possa ser carregado dentro do controle desejado. Exemplo: um template ascx contém uma table, esta pode conter varias células, cada uma com um Identificador que corresponderia ao quadro, ou seja, a célula do Identificador “TOPO” carregará o quadro cadastrado com sigla = “TOPO”, a célula “MENU” carregará o quadro cadastrado com sigla = “MENU”, e assim por diante.

Segue a ilustração:

Cada quadro do template deve herdar da classe Unitech.Web.Frame que será vista na próxima seção.

3.6. A Classe Unitech.Web.Frame

Tal como os Templates cada quadro no UNIFW é um UserControl (ASCX), mas com uma finalidade diferente. Um quadro (Frame) tem funções voltadas para os controles visuais que compõem a interface. A classe Frame também é responsável pela obtenção dos dados do Request.

A principal propriedade da classe Frame é o InnerDataSet, que é um DataSet para armazenamento dos dados obtidos por algum método ou passados a algum método de uma classe de negócio. Esse InnerDataSet pode ser utilizado em conjunto com os métodos SyncData e SyncForm.

O método SyncData preenche os campos do InnerDataSet com os dados da interface web, de maneira inversa o método SyncForm preenche os campos da interface web com os dados armazenados no InnerDataSet. Esses métodos necessitam que os campos na interface tenham o mesmo nome das colunas no InnerDataSet. Não é preciso passar parâmetros aos métodos e estes devem ser chamados dentro de um IF Not IsPostBack por questões de performance. Exemplo em VB.NET: Private Sub Page_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load If Not IsPostBack Then Dim BS As Unitech.UNIFW.Conteudo.BS.Publicacao BS = New Unitech.UNIFW.Conteudo.BS.Publicacao() InnerDataSet = BS.DataStructure() InnerDataSet.Tables(0).Rows(0).Item("Identificador") = CInt(Marcados(0)(0)) InnerDataSet = BS.ObterPorPKDetalhes(InnerDataSet) SyncForm()

End If End Sub

O trecho acima preenche os campos do formulário da página com os valores das colunas correspondentes contidas no InnerDataSet. Esses campos podem ser TextBoxes, Labels, CheckBoxes RadioButtons, ListBoxes ou DropDownLists.

TOPO

MENU

N EW S

CORPO

1.1.1.1.1 Template Normal.ascx

TOPO.ascx

MENU.ascx

NEWS.ascx

CORPO.ascx

Default.aspx (PlaceHolder PagePH)

Pág.:31

3.7. O processo de desenvolvimento de telas

O processo de desenvolvimento de telas para a aplicação WEB a ser desenvolvida, envolve diversas etapas que devem ser seguidas. O diagrama de fluxo abaixo mostra o processo básico de desenvolvimento:

3.7.1. Implementando uma tela com o Unifw 3.7.1.1 URLs e arquivos

Os arquivos de quadros e templates utilizados pela aplicação devem ser cadastrados no Unifw. Estes

arquivos devem ter extensão .ASCX, e serão carregados dentro do ASPX principal conforme já mencionado em seções anteriores. O Unifw propõe uma organização para as pastas e arquivos conforme a seguinte lista:

APLICACAO bin images css

Aplicação cadastrada?

Template cadastrado?

Tela cadastrada?

Inicio

Cad. Aplicação e Módulo

Cad. URL/Arquivo de Template e Quadros

Cad. de Template e Quadros

Cad. URL/Arquivos de quadros da tela

Cad. da Tela, seus quadros e ações

Implementar ASCX do quadro da tela

Implementar arquivo de template ASCX

Falhou no teste?

Fim

não

sim

não

sim

não

sim

não

sim

Pág.:32

templates modulos

nome_modulo quadros geral quadros xml

Onde:

• APLICACAO: diretório raiz da aplicação, onde estarão os arquivos .ASPX, o Global.asax ,o Web.config e o AssemblyInfo.

• bin : diretório padrão para as dlls geradas. • Images: diretório onde os arquivos de imagem serão colocados • Css : diretório onde os arquivos de estilo (Cascade Style Sheet) utilizados pelas páginas da

aplicação. • Templates: diretório onde serão colocados os arquivos ASCX de templates da aplicação. • Modulos: diretório raiz para os módulos. • Módulos/Nome_modulo: diretório do módulo • Módulos/Nome_modulo/Quadros: diretório onde serão colocados os arquivos ASCX de

quadros que compõem o módulo. • Geral/Quadros: diretório com quadros utilizados por todos os módulos da aplicação. • Xml: diretório onde serão colocados os arquivos XML de Menu.

3.7.1.2 Herança de Unitech.Web.Frame

Uma tela no Unifw sempre é formada por um ou mais quadros sobre um template cadastrado. Para que

ela funcione corretamente, seus quadros devem herdar de Unitech.Web.Frame como já mencionando anteriormente.

Um cuidado especial deve ser tomado com o PostBack de uma página, para que este não faça processamentos desnecessários, por exemplo SyncForm.

Segue um exemplo de código de um quadro herdando de Unitech.Web.Frame: Imports System.Data Imports Unitech.UNIFW.Seguranca.BS Imports Unitech.Web Public MustInherit Class Unifw_PublicacaoNoticiaBanner : Inherits Unitech.Web.Frame Private CacheObjectName As String Protected Marcados As System.Collections.ArrayList = New System.Collections.ArrayList() Public IdPublicacao As Object ‘---------------------------------------------------------------- ‘ A Declaração das variaveis HTML foi suprimida ‘ para melhor visualização. ‘---------------------------------------------------------------- #Region " Web Form Designer Generated Code " <System.Diagnostics.DebuggerStepThrough()> Private Sub InitializeComponent() End Sub Private Sub Page_Init(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Init InitializeComponent() FillItens(IdPublicacao, Marcados) Dim AplicacaoPublicacaoBS As Unitech.UNIFW.Conteudo.BS.AplicacaoPublicacao AplicacaoPublicacaoBS = New Unitech.UNIFW.Conteudo.BS.AplicacaoPublicacao() Dim AplicacaoPublicacaoDS As DataSet AplicacaoPublicacaoDS = AplicacaoPublicacaoBS.DataStructure AplicacaoPublicacaoDS.Tables(0).Rows(0)("IdenPublicacao") = CInt(Marcados(0)(0)) AplicacaoPublicacaoDS = AplicacaoPublicacaoBS.ObterPorPublicacao(AplicacaoPublicacaoDS) SetDataSource( AplicacaoPublicacaoDS)

Pág.:33

If Not IsPostBack Then AddColumns() End If End Sub #End Region Private Sub Page_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load FillItens(IdPublicacao, Marcados) AddColumns() BindGridAplicacaoPublicacao() Detalhes_Apresentar() If Not IsPostBack Then SyncForm() Unitech.Web.Util.BookMark.Marcar() End If End Sub Private Sub FillItens(ByVal Ident As Object, ByRef Lista As System.Collections.ArrayList) Try Lista = CType(Ident, System.Collections.ArrayList) Catch If (Ident.GetType().ToString() = "System.String") Then Dim Temp As ArrayList = New ArrayList() Temp.Add(Ident) Lista.Add(Temp) Else Lista.Add(Ident) End If End Try End Sub Private Sub AddColumns() With GridAplicacao .AddColumnPK("IdenPublicacao") .AddColumnPK("IdenAplicacao") End With End Sub Private Sub BindGridAplicacaoPublicacao() Dim StrSortField As String = GridAplicacao.SortExpression If ((StrSortField <> String.Empty) And (StrSortField <> Nothing)) Then InnerDataView.Sort = StrSortField If (Not GridAplicacao.IsSortedAscending) Then InnerDataView.Sort += " DESC" End If End If GridAplicacao.UniDataSource = InnerDataView GridAplicacao.VirtualItemCount = InnerDataView.Count GridAplicacao.DataBind() End Sub

Private Sub GridAplicacao_PageIndexChanged(ByVal Sender As System.Object, ByVal E As

System.Web.UI.WebControls.DataGridPageChangedEventArgs) Handles GridAplicacao.PageIndexChanged BindGridAplicacaoPublicacao() GridAplicacao.CurrentPageIndex = E.NewPageIndex GridAplicacao.DataBind() End Sub Private Sub Detalhes_Apresentar() Dim DS As DataSet Dim BS As Unitech.UNIFW.Conteudo.BS.Publicacao BS = New Unitech.UNIFW.Conteudo.BS.Publicacao() InnerDataSet = BS.DataStructure() If Marcados Is Nothing Then SyncData() Else InnerDataSet.Tables(0).Rows(0).Item("Identificador") = CInt(Marcados(0)(0)) End If InnerDataSet = BS.ObterPorPKDetalhes(InnerDataSet)

Pág.:34

InnerDataSet.Tables(0).Columns("Data").ExtendedProperties.Add("FormFormat", "d") End Sub Private Sub Redirecionar_Command(ByVal sender As System.Object, ByVal e As

System.Web.UI.WebControls.CommandEventArgs) Handles Bt_Editar.Command Unitech.Web.Redirector.GoTo(sender) End Sub End Class

Analisando o código acima, pode-se notar que se trata de uma página com um UniDataGrid chamado

de GridAplicacao, o qual possui eventos paginação, ordenação e marcação de itens para alteração ou exclusão. Este UniDataGrid listará as aplicações amarradas a uma determinada publicação recebida como parâmetro de uma tela anterior (variável IdPublicacao), este processo será explicado mais tarde.

Pode-se notar também a utilização de métodos como o SyncData e SyncForm, já vistos anteriormente. E por fim a utilização de novas classes: a classe Unitech.Web.Redirector, que fará o redirecionamento a

outra página, a depender do objeto (sender) que a chamou e a classe Unitech.Web.Util.Bookmark que será visto em uma seção posterior.

Esta página possui os comportamentos básicos de uma tela com um único UniDataGrid, e pode ser simplificada caso o desenvolvedor opte por herdar da classe Unitech.Web.Frames.SimpleGrid, que será vista a seguir. Implementando uma tela com mais de um DataGrid O procedimento geralmente realizado no desenvolvimento de uma tela com um UniDataGrid é o de obtê-lo e o atribui-lo para o InnerDataSet. Na chamada de um método Bind daquele UniDataGrid basta utilizar a propriedade UniDataSource direcionando para o InnerDataView (propriedade de Unitech.Web.Frames) e pronto a ligação entre aquele DataSet o UniDataGrid é feita.

Qual seria o procedimento para a utilização de mais um UniDataGrid? Lembrando que possuímos só um InnerDataSet. A resposta é a seguinte, para cada UniDataGrid será necessário criar uma propriedade na classe da página que será um DataView (System.Data.DataView), nesse DataView será armazenado a visualização dos datasets. Exemplo:

Protected DataView1 As DataView Protected DataView2 As DataView Protected DataView3 As DataView No exemplo acima é criado 3 propriedades as quais armazenarão as visualizações dos UniDataGrids. Cada DataView desse esta relacionado com um determinado DataGrid e seu respectivo DataSet. No MyBase.Init onde é carregado os dados é necessário fazer a geração dessas DataViews através do método setDefaultView()a qual irá carregar baseado em um dataset a DefaultView da tabela 0 nesse DataView. Abaixo segue a implementação desse método e um exemplo de como utiliza-lo. Private Sub setDefaultView(ByRef myDataView As DataView, ByVal myDataSet As DataSet) myDataView = myDataSet.Tables(0).DefaultView End Sub

Private Sub Page_Init(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles

MyBase.Init InitializeComponent() Dim DS As DataSet

Dim BS1 As Unitech.UNIFW.Seguranca.BS.Sequencia = New Unitech.UNIFW.Seguranca.BS.Sequencia() DS = FormatDisplaySequencia(BS1.ObterTodos(), BS1.GetType().Name)

SetDefaultView(DataView1, DS)

Dim BS2 As Unitech.UNIFW.Util.OrigemDados BS2 = New Unitech.UNIFW.Util.OrigemDados() Dim ds2 As DataSet = New DataSet() ds2 = BS2.DataStructure ds2.Tables(0).Rows(0)("Sigla") = "UNIFWTM"

DS = BS2.ObterPorSigla(ds2) SetDefaultView(DataView2, DS)

Dim BS3 As Unitech.UNIFW.Seguranca.BS.Classe BS3 = New Unitech.UNIFW.Seguranca.BS.Classe()

Pág.:35

DS = FormatDisplayClasse(BS3.ObterTodos(), BS3.GetType().Name) SetDefaultView(DataView3, DS) If Not IsPostBack Then AddColumns() End If

End Sub

Para realizar o DataBind de cada UniDataGrid sera necessário obter esse DataView. Abaixo segue outro exemplo apresentando o Bind de um dos Grids do exemplo anterior. Private Sub BindGridSequencia() UniDataGridSequencia.UniDataSource = DataView1 UniDataGridSequencia.VirtualItemCount = DataView1.Count UniDataGridSequencia.DataBind() End Sub Utilizando Cache se torna mais simples a administração desses DataSets, no tópico a seguir irá explicar como desenvolver uma página herdando de Frames implementando Cache. Utilização de Cache em Frames

É possível manter em cache o DataSet a ser manipulado pela página, obtendo assim melhor perfomance nas ações de paginação e ordenação de campos. No entanto, essa prática deve ser evitada pois variáveis de escopo de sessão (utilizadas no Cache) acaba comprometendo o desempenho da aplicação a medida que se aumenta o número de usuários que utilizam o sistema. A idéia é manter o dataset em cache para que o mesmo possa ser utilizado após um POSTBACK evitando assim outro acesso a base de dados. A lógica utilizada é a mesma empregada no código do tópico acima (Herança de Unitech.Web.Frames) com uma pequena diferença na implementação do MyBase.Init (implementado com o nome Page_Init). O codigo abaixo apresenta a maneira de implementar o cache.

Private Sub Page_Init(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Init InitializeComponent() FillItens(IdPublicacao, Marcados) Dim AplicacaoPublicacaoBS As Unitech.UNIFW.Conteudo.BS.AplicacaoPublicacao AplicacaoPublicacaoBS = New Unitech.UNIFW.Conteudo.BS.AplicacaoPublicacao() Dim AplicacaoPublicacaoDS As DataSet CacheObjectName = "DataGridCache" AplicacaoPublicacaoDS = AplicacaoPublicacaoBS.DataStructure AplicacaoPublicacaoDS.Tables(0).Rows(0)("IdenPublicacao") = CInt(Marcados(0)(0)) If Not IsPostBack Then AddColumns() AplicacaoPublicacaoDS = AplicacaoPublicacaoBS.ObterPorPublicacao(AplicacaoPublicacaoDS) UpdateCache(CacheObjectName, AplicacaoPublicacaoDS) End If End Sub

Como podemos ver no exemplo acima só será realizado acesso a base de dadosse a página não tiver sofrido um POSTBACK, ou seja, quando é chamada a página o método UpdateCache irá armazenar o dataset resultante do ObterPorPublicacao na sessão do usuário com o nome determinado na propriedade CacheObjectName. Após isso para a aplicação restaurar essa dataset basta a mesma realizar uma chamada para o método GetFromCache() passando o CacheObjectName como parâmetro. Abaixo segue um exemplo de como restaurar esse dataset.

Private Sub BindGridAplicacaoPublicacao() CacheObjectName = "AplicacaoPublicacao" GetFromCache(CacheObjectName) Dim StrSortField As String = GridAplicacao.SortExpression If ((StrSortField <> String.Empty) And (StrSortField <> Nothing)) Then InnerDataView.Sort = StrSortField If (Not GridAplicacao.IsSortedAscending) Then InnerDataView.Sort += " DESC" End If End If

Pág.:36

GridAplicacao.UniDataSource = InnerDataView GridAplicacao.VirtualItemCount = InnerDataView.Count GridAplicacao.DataBind()

End Sub

3.7.2. Telas Simples (SimpleGrid, SimpleForm e SimpleDetail)

3.7.2.1 SimpleGrid

Como visto anteriormente, um quadro contendo um único UniDataGrid pode ter o seu código simplificado, pois o Unifw possui a classe Unitech.Web.Frames.SimpleGrid que já faz boa parte do trabalho para o desenvolvedor, tal como cuidar das questões ligadas a ordenação e paginação. O Código acima, se herdado de SimpleGrid teria a seguinte aparência: Imports System.Data Imports Unitech.Web.WebControls Public MustInherit Class Unifw_Sequencia Inherits Unitech.Web.Frames.SimpleGrid Protected WithEvents LabelTituloModulo As Unitech.Web.WebControls.UniLabel Protected WithEvents LabelTitulo As Unitech.Web.WebControls.UniLabel Protected WithEvents LabelTexto As Unitech.Web.WebControls.UniLabel Private Sub Page_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load AddColunasPK() SimpleUniDataGrid.Titulo = Unitech.UNIFW.Dicionario.BS.Dicionario.GetString("SEQUENCIA.TituloGrid") If Not IsPostBack Then Unitech.Web.Util.BookMark.Marcar() End If End Sub Private Sub AddColunasPK() With SimpleUniDataGrid .AddColumnPK("Sigla") End With End Sub Private Sub Inicializacao(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.InitializeGrid Dim SequenciaBS As Unitech.UNIFW.Seguranca.BS.Sequencia = New Unitech.UNIFW.Seguranca.BS.Sequencia() SetDataSource(FormatDisplaySequencia(SequenciaBS.ObterTodos(), SequenciaBS.GetType().Name)) End Sub Private Function FormatDisplaySequencia(ByVal DS As DataSet, ByVal TableName As String) As DataSet DS.Tables(TableName).Columns("Descricao").Caption = "Descrição" DS.Tables(TableName).Columns("ProxIdentificador").Caption = "Proximo ID" FormatDisplaySequencia = DS End Function End Class

Note a grande redução de codificação e também uma alteração do Objeto que antes era GridAplicacao,

passou a ser SimpleUniDataGrid. Todos os outros métodos ficam implementados na classe ancestral Unitech.Web.Frames.SimpleGrid.

Existe um novo evento chamado InitializeGrid na classe Base que serve para preencher o DataGrid

através do método SetDataSource. O SetDataSource faz exatamente o preenchimento o SimpleUniDataGrid com os valores do DataSet passado como parâmetro. Obs: O UniDataGrid do HTML deve possuir o id = “SimpleUniDataGrid”, por esta razão não podemos ter mais de um DataGrid em uma página que herda de SimpleGrid, a não ser que o desenvolvedor implemente todos os outros métodos para o outro UniDataGrid da

Pág.:37

página, o que tornará a herança de SimpleGrid uma coisa sem nexo. O UniDataGrid será melhor explicado na seção de Componentes Visuais. Outro fator importante é que o SimpleUniDataGrid já é declarado na classe ancestral (SimpleGrid), portanto não pode haver outra declaração na sua classe, apague este código caso sua ferramenta de desenvolvimento gere esta declaração automaticamente em modo de design. Utilização de Cache em SimpleGrid

É possível manter em cache o DataSet a ser manipulado pelo SimpleGrid, obtendo assim melhor perfomance nas ações de paginação e ordenação de campos. No entanto essa prática não é aconselhada, pois utiliza variável de escopo de sessão a qual deve ser evitada o seu uso demasiado.

Fazer com que o SimpleGrid mantenha em cache seu dataset evitando assim acesso a banco de dados é muito simples, basta implementar o MyBase.InitializeGrid (em nosso exemplo acima sendo implementado através do nome Inicializacao) da seguinte maneira:

Private Sub Inicializacao(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.InitializeGrid Dim SequenciaBS As Unitech.UNIFW.Seguranca.BS.Sequencia = New Unitech.UNIFW.Seguranca.BS.Sequencia() CacheObjectName = "SimpleGridCache" If Not IsPostBack Then FillData(FormatDisplaySequencia(SequenciaBS.ObterTodos(), SequenciaBS.GetType().Name)) End If End Sub

O método FillData utilizado no exemplo acima armazena o dataset em cache (sessão) com o nome denominado pela propriedade CacheObjectName. Note que o CacheObjectName deve ficar fora do If Not IsPostBack pois a classe pai (SimpleGrid) necessita saber qual é o nome da variável de cache a ser recuperada. Nesse exemplo podemos verificar que o acesso a base de dados só será feito quando a página for carregada sem PostBack . É interessante ter o controle sobre os nomes das variáveis de cache para evitar sobrecarga no servidor é indica a utilização de uma variável padrão, tipo “SimpleGridCache”, em casos especiais como em chamadas de janelas POP-UP se faz necessário a utilização de outros nomes. 3.7.2.2 SimpleForm

Assim como o SimpleGrid, o Unifw provê a classe Unitech.Web.Frames.SimpleForm para telas de

formulários simples, esta classe possui recurso de SyncForm automático e uma melhor divisão dos eventos de apresentação, inserção, alteração e exclusão de registros. 3.7.2.3 SimpleDetail A Classe SimpleDetail, assim como as duas anteriores também simplifica o desenvolvimento de telas de detalhes simples (com SyncForm automático), porém o único evento existente é o de apresentação. Obs.: Lembrando que os campos devem ter os Identificadores iguais às colunas do InnerDataSet nas telas que herdam de SimpleForm e SimpleDetail.

3.8 Usando o BookMark

Por questões de segurança e performance o Unifw traz o conceito de bookmark de páginas. Para poder utilizar este recurso o desenvolvedor deverá utilizar métodos da classe Unitech.Web.Util.Bookmark.

Este recurso funciona como um empilhamento de páginas marcadas através dos métodos Unitech.Web.Util.Bookmark.Marcar(), ou Unitech.Web.Util.Bookmark.MarcarBloco(“NomeTela”) que devem ser chamados no Load da página desejada dentro de um IF Not IsPostBack.

Outra maneira de marcar uma tela é configurando a propriedade IsMark (propriedade de Unitech.Web.Frame) para True. Ou se quiser ainda marcar um bloco basta informar também o nome do mesmo na propriedade BookMarkBlockName.

Pág.:38

As páginas que são ditas folhas, ou seja, delas você não pode ir para mais nenhuma página a não ser

voltar para uma anterior, devem chamar justamente o método Unitech.Web.Util.Bookmark.Voltar ou Unitech.Web.Util.Bookmark.VoltarBloco(“NomeTela”).

Como isso funciona? Cada chamada ao método Marcar(), empilhará a Tela atual em um objeto Bookmark (esse

empilhamento é realizado no ínicio de execução da próxima pagina executada) e cada chamada ao método Voltar() desempilha a última Tela deste objeto. Já o método MarcarBloco(“NomeTela”) serve para ser usado em conjunto com o VoltarBloco(“NomeTela”), onde o desempilhamento será feito até o registro marcado como bloco na Pilha Bookmark, descartando as eventuais telas que estiverem acima desta na pilha. Segue uma ilustração do Empilhamento e desempilhamento de telas com o Bookmark: Marcação Simples Marcação em Bloco

A classe SimpleForm, já vista anteriormente, possui o recurso de Voltar já implementado nos botões confirmar e desistir. Caso o desenvolvedor não informe a tela pra qual estes botões devem apontar em suas devidas propriedades (que serão vistas na seção de Componentes Visuais), a classe redirecionará o quadro para a última página marcada chamando automaticamente o método Voltar().

3.9 Redirecionamento de Páginas Os componentes visuais UniButton, UniLinkButton e UniImageButton do Unifw possuem as propriedades Aplicação, Módulo e Tela de destino. Essas propriedades são usadas para o redirecionamento de uma tela a outra do sistema via chamada ao método Goto da classe Unitech.Web.Redirector, passando como parâmetro o controle que possui essas propriedades preenchidas. Exemplo:

Private Sub Redirecionar_Command(ByVal sender As System.Object, ByVal e As System.Web.UI.WebControls.CommandEventArgs) Handles Bt_Editar.Command

Unitech.Web.Redirector.GoTo(sender) End Sub End Class

Onde neste caso o sender possui uma instancia do UniImageButton Bt_Editar, a Classe Redirector tratará de chamar a nova tela conforme as propriedades mencionadas anteriormente deste UniImageButton.

3.10 Componentes Visuais O Unifw possui sua própria biblioteca de componentes visuais que estão reunidas no assembly Unitech.Web.WebControls. Esses componentes são subclasses das classes que compõem o assembly System.Web.UI.WebControls e das que compõem o assembly Microsoft.Web.UI.WebControls.

Tela E

Tela F

Tela D

Tela C

Tela B

Tela A

Tela E

Tela A

Tela B

Tela C

Tela D

MarcarBloco(“TelaD”)

VoltarBloco(“TelaD”)

Voltar() Marcar()

Pág.:39

Propriedades Comuns

A maioria dos componentes visuais apenas herdam as características de suas classes ancestrais, com pouco ou nenhum código extra. Alguns desses componentes possuem a propriedade DictionaryKey, que uma vez preenchida com uma chave existente no Dicionário, faz com que o componente busque o Texto atrelado a esta chave no Dicionário e o renderize de forma adequada, dentre estes componentes podemos citar: UniLabel, UniLinkButton, UniButton, etc.

As propriedades Aplicação, Módulo e Tela já explicadas na seção de Redirecionamento de Páginas existem nos componentes UniButton, UniLinkButton e UniImageButton

E, por fim, alguns componentes de entrada de dados (UniTextBox, UniDateBox, UniBusinessBox, UniNumberBox, UniCheckbox, UniDropDownList, etc) e o UniLabel, possuem a propriedade Message, esta propriedade serve basicamente para criar variáveis no request com os valores preenchidos ou selecionados dos componentes de Input ou Labels, por exemplo, caso o desenvolvedor preencha a propriedade Message de um UniLabel visible=false, o texto do Label irá como uma variável no redirecionamento da tela, exemplo: Default.aspx?ValorMessage=TextoLabel

Nas telas receptoras devem ser declarados objetos públicos com identificadores iguais a estas variáveis, a partir daí o Unifw tratará de preenchê-los conforme o valor passado pelo componente da tela chamadora.

UniValidators

Componentes validators são componentes que renderizam código JavaScript para proceder as validações de campos da Tela. Os componentes Validators do Unifw apenas herdam as características dos Validators do Framework .Net, são eles:

• UniRequiredFieldValidator: verifica se um determinado campo foi preenchido, caso contrário exibe a mensagem de erro.

• UniCompareValidator: faz comparações de valores entre 2 campos, ou com um determinado valor.

• UniRangeValidator: verifica se o valor de entrada pertence a uma região de valores predefinida. • UniRegularExpressionValidator: submete o valor de entrada a validação via uma expressão regular.

• UniCustomValidator: permite que o desenvolvedor crie seu Script de validação para os componentes da tela.

UniDataGrid

Este é um dos componentes visuais mais usados e mais importantes do Unifw, ele herda as

características do componente DataGrid do Framework .Net, além de implementar algumas outras funcionalidades, tais como Coluna de CheckBoxes nos itens com funcionalidades de marcar e desmarcar todos os itens ao mesmo tempo, TextBox paginador, e outros.

O UniDataGrid possui uma variável IdMessage que possui a mesma funcionalidade da variável Message dos Componentes Visuais de entrada de dados já mencionada anteriormente, o valor adicionado à variável será o da(s) coluna(s) identificada(s) como chave(s) primária(s) que teve seu checkbox marcado. Para adicionar uma coluna do uniDataGrid como chave primária, deve ser utilizado o o método AddColumnPK do UniDataGrid passando como parâmetro o nome da coluna desejada. Este recurso é utilizado e telas que possuem os botões editar, detalhes ou excluir para passagem do identificador. Quando são marcados mais de um checkbox a variável do requeste será preenchida com um array de valores da seguinte forma: Variável=valor1|valor2|valor3...

ScrollBar Horizontal

Através da propriedade ScrollBar é possível habilitar no UniDataGrid a exibição de barras de

rolagem. Essa propriedade vem setada como Desabilitada. Para habilitar o ScrollBar Horizontal será necessário definir a propriedade ScrollBar como

Horizontal. Vale ressaltar que os campos do datagrid devem ter seus tamanhos configurados para

Pág.:40

uma melhor exibição dos dados (isso através da ExtendedProperties denominada Height nas colunas do DataTable).

Definindo a propriedade ScrollBar como Auto o UniDataGrid irá exibir o ScrollBar (horizontal ou/e vertical) se necessário, ou seja, caso a tabela com os itens tenha tamanho vertical ou horizontal superior ao tamanho definido nas propriedades Width e/ou ItensTableHeight do UniDataGrid..

UniScrollMenu e UniExpandMenu

Esses dois componentes estão disponíveis no assembly Unitech.Web através do namespace Unitech.Web.WebControls. Eles são gerados dinamicamente a partir de um xml com a configuração do menu que deve ser informado o endereço relativo à aplicação Web na propriedade MenuData. Tal xml deve possui a seguinte estrutura (os valores dos atributos Id, Label e Url são somente ilustrativos): <MenuData> <MenuGroup> <MenuItem Id="Item1" Label="Item 1"> <MenuGroup> <MenuItem Id="Item1_1" Label="Item 1.1"> <MenuGroup> <MenuItem Label="Item 1.1.1" URL="Default.aspx?Aplicacao=APP&amp;Modulo=MOD&amp;Tela=TELA&amp;Acao=ACAO"/> </MenuGroup> </MenuItem> <MenuItem Id="Item1_2" Label="Item 1.2"> <MenuGroup> <MenuItem Label="Item 1.2.1" URL="http://www.unitech.com.br"/> <MenuItem Id="Item1_2_2" Label="Item 1.2.2"> <MenuGroup> <MenuItem Label="Item 1.2.2.1" URL="http://www.unitech.com.br"/> </MenuGroup> </MenuItem> </MenuGroup> </MenuItem> <MenuItem Label="Item 1.3" URL="http://www.unitech.com.br"/> </MenuGroup> </MenuItem> <MenuItem Label="Item 2" URL="http://www.unitech.com.br"/> </MenuGroup> </MenuData>

Após ler o xml com a configuração os menus são renderizados conforme figura

abaixo:

Menu fechado Menu expandido

UniExpandMenu UniScrollMenu

Pág.:41

É interessante configurar a propriedade CacheEnabled = true e IncludeScript = false para que o

componente ofereça melhor perfomance e torne o arquivo gerado mais leve, vale ressaltar que a propriedade IncludeScript só existe no UniScrollMenu. Quando a propriedade IncludeScript = false é importante configurar a propriedade ScriptFolderPath para o diretório o qual possui os arquivos de script do menu.

Caso seja necessário integrar o menu com a seugurança do UniFW, basta apenas setar para Ocultado (oculta o item caso não tenha permissão para o mesmo) ou Desabilitando (desabilita o item caso não tenha permissão para o mesmo) a propriedade AplicaSeguranca e verificar a propriedade AcaoDefault que é responsável por informar qual a Ação que será usada caso a URL não possua o item Acao.

Vale lembrar que para que exista tal integração o atributo URL tem que conter as conforme aprentado no item de menu com Label “Item 1.1.1” no exemplo da estrutura do xml acima. Caso não seja informado o item Aplicacao na URL o menu utiliza sigla da aplicacação em questão e caso não seja informado o item Acao, conforme dito anteriomente, o menu utiliza o valor que está setado na propriedade AcaoDefault.

UniTextBox, UniBusinessBox, UniDateBox e UniNumberBox

Esses componentes estão disponíveis no assembly Unitech.Web através do namespace Unitech.Web.WebControls e possuem algumas propriedades em comum que serão apresentadas em seguida:

• Message: é informado para essa propriedade o nome do atributo a ser adicionado ao objeto Message para comunicação entre páginas.

• AutoComplete: quando configurado para On ativará o recurso de auto-completar da digitação na caixa de texto (TextBox), enquanto, quando configurado para Off o recurso será desativado explicitamente. Quando configurado para None não existe interferência do componente deixando conforme a configuração do browser. Obs: Esse recurso de auto-completar é inerente ao browser Internet Explorer.

• TabOnEnter: esse recurso permite que, quando configurado para true, o enter seja substituído por tab no controle.

• Required: é responsável por tornar o campo requirido ativando um UniRequiredValidator quando o campo não tem informação. As propriedades abaixo só serão utilizadas caso está propriedade estiver configurada para true.

o RequiredCssClass: define o ccs para o validator. o RequiredErrorMessage: define qual é a mensagem de erro para o validator. o RequiredMsgPositionLeft: define qual é a posição absoluta em relação à esquerda que a

mensagem de erro irá aparecer, caso aconteça. Vale lembra que caso essa propriedade e a propriedade RequiredMsgPositionTop não sejam definidas a mensagem de erro irá aparecer ao lado do componente.

o RequiredMsgPositionTop: define qual é a posição absoluta em relação ao topo que a mensagem de erro irá aparecer, caso aconteça. Vale lembra que caso essa propriedade e a propriedade RequiredMsgPositionLeft não sejam definidas a mensagem de erro irá aparecer ao lado do componente.

o RequiredText: define qual é texto para o validator, caso seja ativado. Além dessas propriedades apresentadas acima, os componentes UniBusinessBox, UniDateBox e

UniNumberBox possuem propriedades especifificas que serão apresentadas em seguida. Vale ressaltar que esses três componentes necessitam que sejam informados se existe algum validator associado a ele, com esse intuito eles disponibilizam um método para associar o validator ao controle e outro para desassociar, que são respectivamente, addValidator e removeValidator.

UniBusinessBox O UniBusinessBox possui as seguintes propriedades adicionais, que são:

• EstiloPredefinido: essa propriedade define estilos que controlam os valores colados (somente no Internet Explorer) e digitados, formatam e em alguns casos fazem a validação. Os estilos são:

o CEP: seguindo o formato ##.###-###, onde # representa qualquer valor numérico, controla os valores informados e formata o valor no momento que o foco é perdido.

Pág.:42

o CNPJ: seguindo o formato ##.###.###/####-##, onde # representa qualquer valor numérico, controla os valores informados e, formata e valida o valor no momento que o foco é perdido.

o CPF: seguindo o formato ###.###.###-##, onde # representa qualquer valor numérico, controla os valores informados e, formata e valida o valor no momento que o foco é perdido.

o CPF/CNPJ: seguindo o formato ###.###.###-## ou ##.###.###/####-##, onde # representa qualquer valor numérico, controla os valores informados e, formata e valida o valor no momento que o foco é perdido.

o Inscrição Estadual (BA): seguindo o formato ###.###.###, onde # representa qualquer valor numérico, controla os valores informados e formata o valor no momento que o foco é perdido.

o Telefone: seguindo o formato ###-#### ou ####-####, onde # representa qualquer valor numérico, controla os valores informados e formata o valor no momento que o foco é perdido.

o Telefone com DDD: seguindo o formato (##)###-#### ou (##)####-####, onde # representa qualquer valor numérico, controla os valores informados e formata o valor no momento que o foco é perdido.

• Validador Cpf/Cnpj: essa categoria de propriedades só é utilizada caso o estilo escolhido seja CNPJ, CPF ou CPF/CNPJ, são elas:

o ValidatorCpfCnpjCssClass: define o ccs para o validator. o ValidatorCpfCnpjErrorMessage: define qual é a mensagem de erro para o validator. o ValidatorCpfCnpjMsgPositionLeft: define qual é a posição absoluta em relação à

esquerda que a mensagem de erro irá aparecer, caso aconteça. Vale lembra que caso essa propriedade e a propriedade ValidatorCpfCnpjMsgPositionTop não sejam definidas a mensagem de erro irá aparecer ao lado do componente.

o ValidatorCpfCnpjMsgPositionTop: define qual é a posição absoluta em relação ao topo que a mensagem de erro irá aparecer, caso aconteça. Vale lembra que caso essa propriedade e a propriedade ValidatorCpfCnpjMsgPositionLeft não sejam definidas a mensagem de erro irá aparecer ao lado do componente.

o ValidatorCpfCnpjText: define qual é texto para o validator, caso seja ativado.

UniDateBox O UniDateBox possui as seguintes propriedades adicionais, que são:

• EstiloPredefinido: essa propriedade define estilos que controlam os valores colados (somente no Internet Explorer) e digitados, formatam e em alguns casos fazem a validação. Os estilos são:

o Data (dd/mm/yyyy): seguindo o formato dd/mm/yyyy, onde dd representa o dia (01 a 31), mm representa o mês (01 a 12) e yyyy representa o ano (0001 a 9999), controla os valores informados e, formata e valida a data no momento que o foco é perdido.

o Dia/Mês (dd/mm): seguindo o formato ddmm, onde dd representa o dia (01 a 31) e mm representa o mês (01 a 12), controla os valores informados e, formata e valida a data no momento que o foco é perdido.

o Hora (hh:mm) 12H: seguindo o formato hh:mm AM ou hh:mm PM, onde hh representa hora (01 a 12) e mm representa o minuto (01 a 59), controla os valores informados e, formata e valida a data no momento que o foco é perdido.

o Hora (hh:mm) 24H: seguindo o formato hh:mm, onde hh representa hora (00 a 23) e mm representa o minuto (01 a 59), controla os valores informados e, formata e valida a data no momento que o foco é perdido.

o Hora (hh:mm:ss): seguindo o formato hh:mm:ss, onde hh representa hora (00 a 23), mm representa o minuto (01 a 59) e ss representa o segundo (01 a 59), controla os valores informados e, formata e valida a data no momento que o foco é perdido.

o Mês/Ano (mm/yyyy): seguindo o formato mm/yyyy, onde mm representa o mês (01 a 12) e yyyy representa o ano (0001 a 9999), controla os valores informados e, formata e valida a data no momento que o foco é perdido.

• TipoSeparador: essa propriedade só é utilizada quando os estilos Data (dd/mm/yyyy), Dia/Mês (dd/mm) e Mês/Ano (mm/yyyy) são seleciondos e define o separador de data que pode ser Barra (/), Traço (-) ou Ponto (.).

• Validador Data: essa categoria de propriedades é utilizada por todos os estilos, são elas:

Pág.:43

o ValidatorDataCssClass: define o ccs para o validator. o ValidatorDataErrorMessage: define qual é a mensagem de erro para o validator. o ValidatorDataMinimumValue: define qual é a data mínima suportada, que em

conjunto com a propriedade ValidatorDataMaximumValue define a faixa de datas válidas.

o ValidatorDataMaximumValue: define qual é a data máxima suportada, que em conjunto com a propriedade ValidatorDataMinimumValue define a faixa de datas válidas.

o ValidatorDataMsgPositionLeft: define qual é a posição absoluta em relação à esquerda que a mensagem de erro irá aparecer, caso aconteça. Vale lembra que caso essa propriedade e a propriedade ValidatorDataMsgPositionTop não sejam definidas a mensagem de erro irá aparecer ao lado do componente.

o ValidatorDataMsgPositionTop: define qual é a posição absoluta em relação ao topo que a mensagem de erro irá aparecer, caso aconteça. Vale lembra que caso essa propriedade e a propriedade ValidatorDataMsgPositionLeft não sejam definidas a mensagem de erro irá aparecer ao lado do componente.

o ValidatorDataText: define qual é texto para o validator, caso seja ativado.

UniNumberBox O UniNumberBox possui as seguintes propriedades adicionais, que são:

• EstiloPredefinido: essa propriedade define estilos que controlam os valores colados (somente no Internet Explorer) e digitados, formatam e em alguns casos fazem a validação. Os estilos são:

o Nenhum: seguindo o formato (####,###), onde # representa qualquer número e vírgula (,) representa o separador decimal, controla os valores informados e valida o valor no momento que o foco é perdido. Vale lembrar que esse estilo não controla a quantidade de casas decimais.

o Inteiro: seguindo o formato (#.###), onde # representa qualquer número e ponto (.) representa o separador de milhar, controla os valores informados e valida o valor no momento que o foco é perdido. Vale lembrar que esse estilo não permite digitar valores decimais.

o Real: seguindo o formato (#.###,##), onde # representa qualquer número, ponto (.) representa o separador de milhar e vírgula (,) representa o separador decimal, controla os valores informados e valida o valor no momento que o foco é perdido. Vale lembrar que a quantidade de casas decimais é definido pela propriedade QuantidadeCasasDecimais.

Obs: Vale ressaltar que a validação só é feita caso o validador de valor esteja ativo. • QuantidadeCasasDecimais: Define qual será a quantidade de casas decimais. Essa

propriedade só é utilizada caso o estilo selecionado seja Real. • TipoSeparadorDecimal: essa propriedade só é utilizada quando os estilos Real e Nenhum

são seleciondos e define o separador de decimal que pode ser Virgula (,), ou Ponto (.). • TipoSeparadorMilhar: essa propriedade só é utilizada quando os estilos Real e Inteiro são

seleciondos e define o separador de milhar que pode ser Virgula (,), ou Ponto (.). • Validador Valor: essa categoria de propriedades é utilizada por todos os estilos, são elas:

o ValidatorValorCssClass: define o ccs para o validator. o ValidatorValorErrorMessage: define qual é a mensagem de erro para o validator. o ValidatorValorMinimumValue: define qual é o valor mínimo suportado, que em

conjunto com a propriedade ValidatorValorMaximumValue define a faixa de valores válidos.

o ValidatorValorMaximumValue: define qual é o valor máximo suportado, que em conjunto com a propriedade ValidatorValorMinimumValue define a faixa de valores válidos.

o ValidatorValorMsgPositionLeft: define qual é a posição absoluta em relação à esquerda que a mensagem de erro irá aparecer, caso aconteça. Vale lembra que caso essa propriedade e a propriedade ValidatorValorMsgPositionTop não sejam definidas a mensagem de erro irá aparecer ao lado do componente.

o ValidatorValorMsgPositionTop: define qual é a posição absoluta em relação ao topo que a mensagem de erro irá aparecer, caso aconteça. Vale lembra que caso essa

Pág.:44

propriedade e a propriedade ValidatorValorMsgPositionLeft não sejam definidas a mensagem de erro irá aparecer ao lado do componente.

o ValidatorValorText: define qual é texto para o validator, caso seja ativado.

3.11. Dicionário É uma boa prática de desenvolvimento de aplicações, a flexibilização de obtenção das mensagens

exibidas e manipuladas pelos componentes envolvidos. Ou seja, deve ser possível a alteração de mensagens de erro, títulos de telas, nomes de campos e todos outros textos utilizados pelas aplicações sem a necessidade de recompilação de seus componentes. Para isso, o Unifw disponibiliza para os desenvolvedores uma biblioteca de Dicionário, existente no pacote Unitech.UNIFW.Dicionario, que possibilita a obtenção de mensagens textuais em tempo de execução, sendo que as mesmas são armazenadas em banco de dados, podendo assim ser alteradas sem a necessidade de recompilação da aplicação. Além disso, a biblioteca de Dicionário do Unifw é sensível ao idioma configurado. Ou seja, os textos das mensagens podem ser configurados em diversos idiomas e, de modo centralizado, as aplicações podem ter suas mensagens alteradas para qualquer idioma previamente cadastrado. Essa alteração é feita no arquivo Web.config através da tag de globalização.

O Unifw utiliza o conceito de cache sob demanda de páginas para montar sua infraestrutura de Dicionário. As mensagen e traduções cadastradas são reunidas em uma estrutura em memória e são recuperadas através da classe Dicionario (Namespace Unitech.UNIFW.Dicionario.BS). Por exemplo, se você quiser que o titulo do UniDataGrid do código anterior fosse dicionarizado com a chave: “TituloGrid” basta colocar a seguinte chamada em seu código:

SimpleUniDataGrid.Titulo = Dicionario.GetString(“TituloGrid”) Caso a classe Unitech.UNIFW.Dicionario.BS.Dicionario não encontre esta chave no banco de dados,

ele atribuirá ao título do grid a própria chave solicitada, no caso acima TituloGrid. A obtenção da chave do dicionário é case insensitive.

Mensagens Dinâmicas Um outro recurso importante é a obtenção de mensagens dinâmicas. As mensagens dinâmicas diferem

das convencionais por possuir tags em seu corpo que oferecem a facilidade da customização do texto em tempo de runtime.

A mensagem cadastrada no exemplo a seguir é do tipo dinâmica, pois a mesma contém uma tag que irá ser substituída em tempo de execução (tag =[NomeUsuario] ) . Exemplo: Seja Bem Vindo, =[NomeUsuario]

A manipulação dessas mensagens é realizado também através do método GetString da classe

Dicionario presente no namespace Unitech.UniFW.Dicionario.BS. Esse método possui as seguintes assinaturas que oferecem recursos para essa funcionalidade:

public static string GetString(string key, Hashtable itens) public static string GetString(string key, string [] chaves, string [] valores)

Ambos os métodos realizam a mesma função, a qual é de configurar a mensagem dinâmica a ser

obtida. Segue exemplos de como utilizar os 2(dois) métodos: A mensagem dinâmica cadastrada (Seja bem vindo, =[nomeusuario] ao sistema =[siglasistema]. ) com a sigla TESTE.MensagemDinamica pode ser configurada e acessada da seguinte maneira: Imports Unitech.UNIFW.Dicionario.BS Dim param As New Hashtable //Apesar da tag possuir ‘=[‘ e ‘]’ entre o nome da chave, isso se torna //transparente para o programador. O mesmo só precisa informar o nome da chave; param.Add("NomeUsuario", "João da Silva") param.Add("SiglaSistema", "UniFW") Dim msg As String = Dicionario.GetString("TESTE.MensagemDinamica", param)

Pág.:45

Uma segunda forma é através da outra sobrecarga desse método:

Dim msg As String = Dicionario.GetString("TESTE.MensagemDinamica", New String() {"nomeusuario", "siglasistema"}, New String() {"João da Silva", "UniFW"})

O resultado de ambas as formas é a seguinte string “Seja Bem Vindo, João da Silva ao sistema UniFW.”

3.12. Ajuda O módulo de ajuda é aplicado para todas as aplicações do UniFW. A ajuda de uma aplicação é formada

por Conteúdos e Tópicos de Ajuda organizados hierarquicamente.

3.12.1. Mensagens Dicionarizadas O módulo de ajuda é composto de mensagens dicionarizadas que estão organizadas hierarquicamente.

Todas as mensagens do módulo de ajuda estão no grupo de mensagem identificado pela sigla HELP. Quando é criado um conteúdo ajuda, é automaticamente criado um grupo de mensagem para a

aplicação identificado pela sigla APP_ mais a sigla da aplicação (Ex.: APP_UNIFW) e um grupo de mensagem para o conteúdo identificado por CONT_ mais o identificador do conteúdo criado (Ex.: CONT_110). No caso do conteúdo ajuda o titulo é dicionarizado, sendo a mensagem identificada pela sigla CTIT_ mais o identificador do conteúdo (Ex.: CTIT_110). Pode ser criado conteúdo ajuda dentro de um conteúdo de ajuda.

Quando é criado um tópico de ajuda é criado também um grupo de mensagem hierarquicamente inferior ao conteúdo pai do tópico. Este grupo é identificado pela sigla TOP_ mais o identificador do tópico (Ex.: TOP_111). Neste caso o título é dicionarizado, sendo a mensagem identificada pela sigla TTIT_ mais o identificador do conteúdo (Ex.: TTIT_111).

O texto das seções do tópico também é dicionarizado sendo que as suas mensagens estão no grupo do tópico e são identificadas pela sigla TSECTEXT_ mais o identificador do tópico de ajuda mais o identificador da seção tópico (Ex.: TSECTEXT_111_99)

3.12.2. Critério de seleção de tópicos sensíveis a contexto Os tópicos de ajuda quando sensiveis a contexto devem seguir uma ordem de prioridade para a escolha

do tópico que deve ser exibido para o usuário. A ordem de prioridade é a seguinte:

1. Tópicos que possuam grupo de trabalho do usuário e o papel que mais se aproxime de qualquer papel do usuário para aquele grupo;

2. Tópicos que possuam o papel mais próximo da lista de papeis do usuário; 3. Tópicos que possuam ação definida e que estejam de acordo com o da tela onde foi solicitado o help; 4. Qualquer tópico que atenda a tela solicitada.

Caso não exista um tópico de ajuda associado à tela será exibida uma tela informativa.

3.12.3. Criando apresentações para tópicos usando o XSL do Tipo de Tópico A apresentação e a estrutura do tópico são determinadas pelo tipo de tópico associado. A estrutura dos

tópicos é determinada pelas seções cadastradas num tipo de tópico, enquanto que a sua apresentação é gerada pelo XML do tópico (gerado dinamicamente, no momento da solicitação da ajuda) e o XSL cadastrado no tipo de tópico associado.

Para cadastrar um tipo de tópico, é necessário conhecer a estrutura do XML gerado pelos tópicos, pois é ele quem vai conter as informações contidas nas seções dos tópicos cadastrados, além de outras informações. O quadro seguinte mostra qual a estrutura de um XML de tópico, que pode ser obtido através do método ObterXML() da classe de negócio TopicoAjuda:

���������

������������������ ����������������������

������������������������� ������������������������������������� ������������

Pág.:46

�������� ��������������� �������

� ���������������������� �������������������

������������������������� ������������������������������������� �������������������� ��������������� �������

� ������������������������������

����������������������������������������������������������������������� �������������������������������������������������� ����������������������������������������������������������� ����������������������������������������������������������������������������� ������������

� ����������������������������������������������� �������������������������������������������

��������������������������������������������������� �������������������������������������������������� ����������������������������������������������������������� ����������������������������������������������������������������������������� ������������

� �������������������� ���������������������

� ������� Para cada seção que o tópico possuir, será incluído no XML do tópico a tag ‘secao’, contendo a sigla da

seção do tipo de tópico no qual a seção do tópico está associada, o título da seção (obtido do dicionário), a ordem e o texto definido para a seção. Da mesma forma, para cada tópico relacionado que o tópico possuir, deverá existir uma tag ‘topico_relacionado’, contendo o título do tópico de destino do tópico relacionado e o identificador do tópico de destino do tópico relacionado.

A partir da estrutura deste XML, podemos criar um XSL para definir a apresentação em browser dos

tópicos cadastrados. Um exemplo prático Vamos criar um XSL que utiliza o XML gerado pelos tópicos para criar apresentações na linguagem

XML. A seguir, é apresentado um XSL; veremos a sua apresentação na tela de ajuda para um tópico de exemplo cadastrado:

������������� ��! ���������� "#$%&&'(%� ������)��*��+����������)��� +���) ,,,�,-���� �((( .#/ ��������� �������)0��� +���) ,,,������+�����1� ����������� ��! �������)��������+��� +�� ������)������������+� ������ ������)���������1�%����%���������2*��2��34567�74��,)��������88�� ��)���������+���������+�������������������+���%�9���25������%�*��2���������2���� +��:��+������2� ����������������+���%�9���2������2���������2��%���+�2� ����������������70��� �����������������;����2��*��+���2�+����2 ��� �, ���,����2 ������� +����������1��*�����������2!2�����������2!2�������������1��1������2!2�,���+�2�!!<2�����������2!2�����������2!2��� � ������������� ��1+�� ����)���%��������� ����������� � �� ���� ����� � ���)���*%��������������� ����� ��� � ���)���*%��������������� ������������������� ����������������� ����������� ��1���

Pág.:47

����� 1��*����� +���������)���������1�%����%���������2*��2��34567�74� �,)��������88�� ��)������� ��)�������������)������������+� ����� ��� ������������� ��1�+� ����)���%��������� ���������� � �� ���� ����� ������������� ���1�* ����)���%��������� ����� � �� ���� ����� ��)�������������)������������+� ����������������� ������������������� ��1�+� ���������)���������1�%����%���������2*��2���������34567�74���+���� �6�����7����7��������=>"?@AB����7C=67A�������70��5����A"�����������88���� ��)����������)���%��������� ������������������������������� � ���������)���������1�%����%���������2*��2���������34567�74A"����7��������88���� ��)����������)���%��������� ���������������������� � ������)���������1�%����%���������2*��2� �� ��)������� ����)���%��������� ���������������������� � ������)���������1�%����%���������2*��2���34567�74� ��88�� ��)����������� ���� ����� ��)����������� ��)��*��+����

Cadastrando um tópico com 3 seções e 1 tópico relacionado que utiliza o tipo de tópico com XSL

definido acima, devemos obter a seguinte apresentação visual:

3.12.4. Inserindo referências para tópicos relacionados nos textos das seções do tópico

Na seção anterior, foi mostrado um XSL que permite que os tópicos relacionados sejam listados na tela

de ajuda de um tópico. Seria interessante que o usuário que cadastra o tópico pudesse ter a possibilidade de inserir estes links no meio do texto de uma seção do tópico, por exemplo, sem ter que recorrer ao XSL Será demostrado aqui como o programador pode permitir que isto aconteça. Para isto será necessário:

1. Criar um XSL que inclua na apresentação do tópico, um script de submissão de página,

2. Criar um pagebean que receba a requisição de página do usuário e redirecione para a tela que exibe a ajuda do tópico.

Um tópico relacionado, quando cadastrado, permite especificar uma referência para o tópico de destino

da relação. Através desta referência é possível criar links dentro do texto das seções do tópico, para o tópico de destino do tópico relacionado. Podemos então exibir a tela de ajuda com links dentro das seções que apontam para os tópicos relacionados do tópico.

Pág.:48

Isto pode ser implementado criando um link HTML dentro do texto da seção do tópico:

<a href=”javascript:redirecionar(‘nome_da_referência’)”> Clique aqui </a> A função redirecionar submete a página atual juntamente com o nome da referência e o identificador do

tópico no qual a ajuda foi solicitada. Com posse destes dados, é possível identificar o tópico de destino da referência, já que a entidade RelacaoTopicoAjuda possui um tópico de origem e uma referencia. Uma vez identificado o tópico de destino, é so redirecionar para a tela de ajuda do tópico, passando os parâmetros ‘IdentTopico’ e ‘IdentAplicacao’ , os identificadores do tópico de destino do tópico relacionado, da seguinte forma:

Default.Aspx?Aplicacao=UNIFW&Modulo=AJUDA&Tela=TelaAjudaCorpo&IdentTopico=302&IdentAplic

acao=1

Pág.:49

4. Log e Tratamento de Erros

Está disponível uma nova forma de tratamento de erros no Unifw.Net, através da qual é possível definir

se os erros deverão ser gravados em log e configurar como estes serão exibidos na tela. Além disso, este recurso facilita a identificação do local onde o erro realmente ocorreu por meio do empilhamento de exceções.

Segundo a forma de tratamento, os erros são diferenciados em duas categorias: (i) erros de negócio,

que consistem em todos erros originados de validações de negócio, como por exemplo, validações de campos obrigatórios ou tamanhos inválidos, e (ii) erros de ambiente, que são causados por falhas no código, como a tentativa de utilizar objetos não instanciados ou comandos SQL mal formados. Os erros de ambiente não são apresentados na tela na sua forma original, sendo encapsulados em um erro genérico definido para o projeto no Web.Config.

Todas as classes filhas, direta ou indiretamente, de UniComponent, podem utilizar o método TrataErro,

que tem como argumentos a exception capturada e a mensagem do novo erro (obtido através da sigla do erro pelo método GetString em Dicionario) a ser gerado caso necessário. Isto permite que, caso o erro capturado seja de ambiente, uma nova exception seja levantada com a mensagem especificada, permitindo que seja facilmente identificado o real local do erro. O exemplo abaixo demonstra a utilização do tratamento de erros em classes de negócio e dados.

Public Class FuncaoCalculo Inherits Fabrica.GEPRO.Classes.Component.GEPROComponent Public Function ObterTodos() As DataSet Try .... .... Catch ex As System.Exception TrataErro(ex, Dicionario.GetString("ErrObterTodos")) End Try End Function End Class

Todas as classes filhas, direta ou indiretamente, da classe Frame, tais como SimpleForm, SimpleGrid e

SimpleDetail, têm disponível o método TrataErro, que, conforme configurado no Web.Config, gravará o erro em log e o exibirá na tela. Caso, em alguma tela específica, não se deseje utilizar as configurações definidas no Web.Config, pode-se utilizar as sobrecargas do método TrataErro para isso. O exemplo abaixo demostra a utilização do tratamento de erros em telas web.

Public MustInherit Class TipoIndicador Inherits Unitech.Web.Frames.SimpleGrid Private Sub Page_Load(...) Handles MyBase.Load Dim LobjTipoIndicador As Fabrica.GEPRO.Classes.TipoIndicador Try .... .... Catch ex As System.Exception TrataErro(ex) Finally 'Libera o objeto LobjTipoIndicador = Nothing End Try End Sub End Class

Pág.:50

O Unifw.Net já possui em sua tabela de configuração (que será detalhada no capítulo 5), itens de

configuração padrão para o tratamento de erro, que são:

• TipoExibiçãoErroNegocio -> Alert • TipoExibiçãoErroAmbiente -> PaginaErro • ErroAmbientePadrao -> ErrFalhaExecucaoAmbiente • TipoLogErro -> Todos

A seguir, são descritas as chaves de configuração que deverão existir no Web.Config, caso deseje uma

configuração diferente da padrão: <add key="TipoExibicaoErroNegocio" value="Alert"/>

<add key="TipoExibicaoErroAmbiente" value="Painel"/>

<add key="ErroAmbientePadrao" value="ErrAmbiente"/>

A chave "ErroAmbientePadrao" deve conter a sigla do erro padrão que será apresentado na tela no caso de algum erro de ambiente. O valor desta chave será procurado no dicionário de erros do Unifw.

As chaves "TipoExibicaoErroAmbiente" e "TipoExibicaoErroNegocio" especificam a forma como as

duas categorias de erros serão exibidas, sendo possíveis os seguintes valores:

• "Painel”: Exibe o erro em um painel presente na tela. Este painel deve se chamar "pnlDescricaoErro" e deve conter um label chamado “lblDescricaoErro”. Isto permite que exista qualquer layout dentro do painel.

• "Alert": Exibe um Alert javascript com a mensagem de erro • "PaginaDeErro": Redireciona para a tela de erro default do ambiente • "Nenhum": Não exibe o erro, escondendo que ocorreu

<add key="TipoLogErro" value="Todos"/>

A chave "TipoLogErro" define a abrangência do log de erros realizado no Event Viewer, permitindo as seguintes valores:

• "Ambiente": Realiza o log somente de erros de ambiente • "Negocio": Realiza o log somente de erros de negócio • "Todos": Realiza o log tanto de erros de ambiente quanto de negócio • "Nenhum": Não realiza log de erros

Caso os projetos que utilizem o tratamento de erros desejem modificar a forma como o mesmo é realizado, basta estender a classe UniComponent e sobrescrever os métodos referentes ao tratamento de erros. Por exemplo, caso o projeto tenha novas exceptions de negócio, basta sobrescrever o método CarregaBIExceptions, adicionando as novas exceptions desejadas.

Além disso, nestes casos é necessário adicionar duas novas chaves ao Web.Config, que indicam qual

classe é responsável por definir quais são os erro de negócio. Neste caso, deve-se preencher estas chaves com os valores referentes à nova classe Component específica do projeto. <add key="AssemblyNameComponent" value="Fabrica.GEPRO.Classes"/>

<add key="ClassNameComponent" value="Fabrica.GEPRO.Classes.Component.GEPROComponent"/>

Obs.: Vale ressaltar que a forma antiga de tratamento de erro no UNIFW continua funcionando,

esta nova forma proposta apenas acrescentará mais poder ao seu tratamento de erro.

Pág.:51

5. Configuração do Ambiente/Componentes

5.1. WebConfig

O Unifw necessita definir algumas configurações para que seu ambiente possa disponibilizar recursos de Login, Página de Erro, Serviços, entre outros. Segue um exemplo de configuração de WebConfig comentado: <?xml version="1.0" encoding="utf-8"?> <configuration> <system.web> <!-- Compilation indica se é permitido fazer debug na aplicação em questão --> <compilation defaultLanguage="vb" debug="false"></compilation> <!-- Alterações do UNIFW em system.web --> <!-- O modo de autenticação é mudado para Forms para permitir --> <!-- que o ambiente .NET descubra automaticamente que o usuário --> <!-- não está "logado". LoginUrl aponta para a tela de login --> <!-- o ASPX da tela de login não pode ser o mesmo utilizado pelas --> <!-- outras telas do sistema. --> <authentication mode="Forms"> <forms loginUrl="Login.aspx?Modulo=GERAL&amp;Tela=LOGIN" name=".AUTHUNIFW.NET" timeout="20" path="/"/> </authentication> <!-- Authorization indica quais páginas precisam de autorização --> <!-- para acesso. "deny users=?" indica que todas as páginas --> <!-- necessitam de autorização. --> <authorization> <deny users="?"/> </authorization> <!-- Indica a página de erro. O ASPX deve ser diferente do que --> <!-- o ASPX utilizado pelas outras páginas da aplicação --> <customErrors defaultRedirect="Erros.aspx?Modulo=GERAL&amp;Tela=ERRO" mode="On" /> <trace enabled="true" requestLimit="1000" pageOutput="false" traceMode="SortByTime" localOnly="true"/> <sessionState mode="InProc" stateConnectionString="tcpip=127.0.0.1:42424" sqlConnectionString="data source=127.0.0.1;user id=sa;password=" cookieless="false" timeout="20"/> <globalization requestEncoding="utf-8" responseEncoding="utf-8" culture="pt-BR" uiCulture="pt-BR"/> </system.web> <location path="Erros.aspx"> <system.web> <authorization> <allow users="*"/> </authorization> <customErrors mode="Off"/> </system.web> </location> <location path="Login.aspx"> <system.web> <authorization> <allow users="*"/> </authorization> <customErrors mode="On"/> </system.web> </location> <appSettings> <!--(Chave Obrigatória no AppSettings)--> <!--Sigla da Aplicacao que contém a tela default.--> <add key="Aplicacao" value="sigla_aplicacao"/> <!--(Chave Obrigatória no AppSettings)--> <!--Sigla do módulo que contém a tela default.--> <add key="Modulo" value="sigla_modulo"/> <!--(Chave Obrigatória no AppSettings)--> <!--Sigla da tela default.-->

Pág.:52

<add key="Tela" value="sigla_tela"/> <!--(Chave Obrigatória no AppSettings)--> <!--Sigla do módulo que contém a tela de Login.--> <add key="ModuloLogin" value="sigla_modulo_tela_login"/> <!--(Chave Obrigatória no AppSettings)--> <!--Sigla da Tela de Login.--> <add key="TelaLogin" value="sigla_tela_login"/> <!--(Chave Obrigatória no AppSettings)--> <!--Sigla do módulo que contém a tela de Erro.--> <add key="ModuloErro" value="sigla_modulo_tela_erro"/> <!--(Chave Obrigatória no AppSettings)--> <!--Sigla da Tela de Erro.--> <add key="TelaErro" value="sigla_tela_erro"/> <!--(Chave Obrigatória no AppSettings)--> <!--Tempo limite de execução de qualquer comando de acesso a dados.--> <add key="CommandTimeOut" value="30"/> <!--(Chave Obrigatória no AppSettings)--> <!--Assembly que contém a classe responsável por obter os valores de configuração do framework e da aplicação.--> <add key="ConfiguracaoAssembly" value="Unitech.UNIFW.Util"/> <!--(Chave Obrigatória no AppSettings)--> <!--Classe responsável por obter os valores de configuração do framework e da aplicação.--> <add key="ConfiguracaoClassName" value="Unitech.UNIFW.Util.Configuracao"/> <!--(Chave Obrigatória no AppSettings)--> <!--Assembly que contém a classe factory responsável pela instância do objeto de acesso a dados do módulo de Util.--> <add key="DataFactoryUtilAssembly" value="Unitech.UNIFW.Util"/> <!--(Chave Obrigatória no AppSettings)--> <!--Classe factory responsável pela instância do objeto de acesso a dados do módulo de Util.--> <add key="DataFactoryUtilClassName" value="Unitech.UNIFW.Util.SQLServer.DataFactorySQLServer"/> <!--(Chave Obrigatória no AppSettings)--> <!--Assembly que contém a classe responsável por gerenciar todo acesso a dados da base de infra-estrutura, como por exemplo conexão, consulta e alteração.--> <add key="DataBaseOrigemDadosAssembly" value="Unitech.Data"/> <!--(Chave Obrigatória no AppSettings)--> <!--Classe responsável por gerenciar todo acesso a dados da base de infra-estrutura, como por exemplo conexão, consulta e alteração.--> <add key="DataBaseOrigemDadosClassName" value="Unitech.Data.SQLDataBaseTM"/> <!--(Chave Obrigatória no AppSettings)--> <!--String de conexão com o banco de infra-estrutura.--> <add key="ConnectionStringOrigemDados" value="server=SERVIDOR_BANCO;uid=USUARIO;pwd=SENHA;database=BANCO"/> </appSettings> </configuration>

O Unifw utiliza-se de dois meios para obtenção das suas configurações principais. O primeiro é a tabela Config, que possui registros com configurações que serão usadas por todas as aplicações, ou seja, nesta tabela estão os valores padrões. Já o segundo é o Web.config e/ou Unitech.Service.exe.config, que possuem configurações que são especificas da aplicação em questão. Conforme apresentado no exemplo acima, existem algumas chaves que são obrigatórias no Web.config e/ou Unitech.Service.exe.config, abaixo são listadas as chaves que são obrigatórias e precisão ter seu valor alterado:

• Aplicacao: Sigla da Aplicação. • Modulo: Sigla do Módulo que contém a tela inicial. • Tela: Sigla da Tela inicial. • ModuloLogin: Sigla do Módulo que contém a tela de Login. • TelaLogin: Sigla da Tela de Login. • ModuloErro: Sigla do Módulo que contém a tela de Erro. • TelaErro: Sigla da tela de Erro. • ConnectinoStringOrigemDados: String de conexão com o banco de dados de infra-estrutura.

Pág.:53

É importante lembrar, que caso o valor genérico defindo na tabela Config não atenda as necessidades

da aplicação, pode-se alterar esse valor acrescentando a chave no Web.config e/ou Unitech.Service.exe.config e o valor desejado.

Com o intuito de simplificar o acesso as configurações da aplicação foi criado a classe Unitech.Util.Configuracao que possui os seguintes métodos:

• Obter(string): Obtém o valor do parâmetro de configuração passado. A ordem de busca é a

apresentada logo abaixo, sendo que só passa para o próximo ítem caso a sigla não tenha sido achada:

1. Procura a sigla no arquivo de configuração da aplicação em questão (arquivo .config). 2. Procura na tabela Config.

• Obter(string, bool): Obtém o valor do parâmetro de configuração passado. O parâmetro boleano indica se a sigla tem que ser encontrada no arquivo de configuração da aplicação em questão (arquivo .config), caso seja verdadeiro e não encontre uma exceção é gerada. A ordem de busca é a apresentada logo abaixo, sendo que só passa para o próximo ítem caso a sigla não tenha sido achada:

1. Procura a sigla no arquivo de configuração da aplicação em questão (arquivo .config). 2. Procura na tabela Config.

• ObterConnectionString(): Obtém a string de conexão do banco de dados de infra-estrutura. Esse método foi criado com intuito de flexibilizar o local e/ou a forma de busca da ConnectionString. Caso a aplicação não queira utilizar a forma e local padrão de busca da connectionString (web.config), basta criar uma classe de configuração que herde de Unitech.UNIFW.Útil.Configuração, sobrescrever este método e informar no web.config nas chaves ConfiguracaoAssembly e ConfiguracaoClassName, respectivamente, o AssemblyName e o ClassName da nova da classe de configuração.

5.2. Página inicial

A página inicial pode ser uma simples página HTML ou um ASCX, que será carregado inicialmente. Esta Tela como todas as outras também deve estar cadastrada no Unifw.

5.3. Página de autenticação (login)

A página de autenticação possui algumas observações: Ela deve ser um ASPX carregando um ou mais quadros ASCX, assim como a página Default.aspx. e herdar normalmente de FWPage. Já o quadro principal (com os campos de Domínio, Usuário e Senha e com o Botão login) deverá herdar de Unitech.Web.Frames.Login. Segue exemplo de um quadro de login: Public MustInherit Class TelaLogin : Inherits Unitech.Web.Frames.Login Protected WithEvents DomReq As Unitech.Web.WebControls.UniRequiredFieldValidator Protected WithEvents LoginReq As Unitech.Web.WebControls.UniRequiredFieldValidator Protected WithEvents SenhaReq As Unitech.Web.WebControls.UniRequiredFieldValidator Private Sub Page_Load(ByVal sender As Object, ByVal E As EventArgs) Handles MyBase.Load If Not IsPostBack Then Unitech.Web.Util.BookMark.Marcar() Unitech.Web.Util.BookMark.PreencherPilha() End If End Sub End Class

Pág.:54

6. Tópicos Avançados

6.1. Envio de Emails

Através da classe Mail (NamesSpace Unitech.Web.Util) é possível enviar emails de forma bastante simples, não necessitando realizar configurações referentes ao servidor SMTP e email do remissor. Abaixo segue um exemplo da utilização desse componente. Imports Unitech.UNIFW.Dicionario.BS Dim msg As Unitech.Web.Util.Mail = New Unitech.Web.Util.Mail() strTitulo = Dicionario.GetString("DICADESENHA.TituloEmail") strMsg = Dicionario.GetString("DICADESENHA.Email") msg.EmailFormat = Mail.MailFormat.Html msg.Send(“[email protected]”, “titulo email”, “corpo email”)

No exemplo acima o método Send é o responsável pelo envio do email, nele é preciso informar o email do destinatário, título do email e o texto do email. As configurações de servidor SMTP e email do remetente estão na tabela Config ou no arquivo de configuração da aplicação em questão (arquivo .config) com as chaves: ServerSMTP EmailUsuarioGerenciador

6.2. Informações sobre o usuário autenticado Muitas vezes é necessário obter alguma informação sobre o usuário logado na aplicação. Para isso temos a classe User (NamesSpace Unitech.Web) o qual oferece as seguintes propriedades: GetDomain() - obtem a sigla do domíno do usuário autenticado. GetLogin() – obtem o login do usuário autenticado. GetUserID() – obtem o ID do usuário autenticado.

6.3. Ciclo de vida de uma Página ASP.NET A programação de páginas ASPX/ASCX requer atenção ao seu ciclo de vida e à ordem dos eventos disparados. Toda requisição a uma página provoca vários eventos no Servidor. Cada evento deste pode ser capturado pelo desenvolvedor de forma a executar códigos próprios. São eles (na ordem): Initialize: Fase de inicialização da página ou controle ( OnInit() ). Load View State: Aqui a propriedade ViewState do controle é populada. A informação de ViewState vem de uma variável oculta do controle, usada para persistir o estado através das idas e vindas ao servidor. Ela poderá ser modificada através do método LoadViewState. Isto permite ao ASP.NET gerenciar o estado do seu controle sobre carregamentos da página para que cada controle não seja redefinido para seu estado padrão toda vez que a página for enviada. Process PostBack Data: Processa os dados enviados ao servidor no posting do formulário. Caso um desses dados resulte em uma requisição de alteração da ViewState, eles serão processados através do método LoadPostData().

Pág.:55

Load: Aqui o método CreateChildControls() é chamado para inicializar os ServerControls existentes. O estado é restaurado e os controles de formulários renderizam os dados no lado cliente. O Desenvolvedor pode modificar a fase de carga da página tratando o evento Load com o método OnLoad() Send PostBack Change Modifications: Caso tenha existido alguma mudança entre o estado corrente e o estado anterior, eventos de modificação são disparados através do método RaisePostDataChangedEvent(). Handle PostBack Events: Aqui o evento client-side que causou o postback é tratado. PreRender: Esta é a fase justamente antes da página ser renderizada no browser. Esta é a última chance do desenvolvedor de modificar a saída antes da rederização usando o método OnPreRender(). Save State: No início do ciclo de vida, o estado persistido foi carregado de uma variável oculta. Agora o estado é gravado de volta na variável oculta, persistido como um objeto string, o que irá completar a volta ao lado cliente. O desenvolvedor poderá sobrescreve-lo usando o método SaveViewState(). Render: Aqui é onde a saída da página que será enviada de volta ao browser cliente é gerada. O desenvoplvedor pode sobrescreve-lo usando o método Rrender(). CreateChildControls() será chamado, caso necessário, para criar e inicializar server controls na árvore de controles. Dispose: Esta é a última fase do ciclo de vida. Ela dá ao desenvolvedor a última oportunidade para qualquer limpeza final e liberação de referências a quaisquer recursos, tais como conexões ao banco de dados. Pode ser modificada através do método Dispose().

6.4. Utilização do GAC O Framework.NET possui um repositório de assemblies chamado de Global Assembly Cache (GAC), que armazena os assembles em suas respectivas versões e cultures. De posse dessas informações o framework consegue ativar o assembly corretamente. Para instalar um assembly no GAC, deve ser utilizada uma ferramenta chamada gacutil em linha de comando, com a seguinte sintaxe: gacutil /i caminho/nome_do_assembly.dll É uma boa prática manter as DLLs compartilhadas instaladas no GAC, mas isto requer atenção, especificamente em tempo de desenvolvimento das suas aplicações, pois uma vez que a sua aplicação vá ao GAC buscar uma DLL, ela buscará todas as outras Dlls que esta referência no próprio GAC, caso não sejam encontradas um erro de referência não encontrada ocorrerá. Solução: se um assembly foi instalado no GAC, os demais assemblies aos quais esse faz referência deverão ser instalados também.

6.5. Inspetores WEB O Unifw.NET disponibiliza atualmente três tipos de inspetores conforme segue:

1. Inspetor de segurança: responsável por verificar se o usuário está autorizado a utilizar uma determinada funcionalidade.

2. Inspetor de workflow: responsável por fazer a autorização de operações realizadas sobre entidades de fluxo.

3. Inspetor dinâmico: possibilita que seja carregado mais de um inspetor.

Atualmente, a configuração padrão utiliza o Inspetor dinâmico que carrega os outros dois inspetores o de Segurança e o de Workflow. Caso o desenvolvedor queira criar seu próprio inspetor é necessário que o seu inspetor implemente a interface Unitech.Web.Interfaces.IInspector. e conseqüentemente implemente o método Validate(). Após criado o inspetor, o desenvolvedor precisa alterar as configurações no Web.config. A alteração da configuração de inspetoria segue a seguinte lógica:

• Caso o desenvolvedor queria que o Unifw carregue apenas um inspetor, é necessário que acrescente as seguintes tags no web.config, conforme o exemplo abaixo:

<!—Assembly que contém a classe de Inspetoria --> <add key="InspectorAssembly" value="assembly_name_inspetor"/> <!—A classe de Inspetoria que será carregada pelo Unifw -->

Pág.:56

<add key="InspectorClassName" value="class_name_inspetor"/>

• Caso o desenvolvedor queira que o Unifw carregue mais de um inspetor, é necessário que

acrescente as seguintes tags no web.config, conforme o exemplo abaixo:

<!—Assembly que contém a classe de Inspetoria --> <add key="InspectorAssembly" value="assembly_name_inspetor_dinamico"/> <!—A classe de Inspetoria que será carregada pelo Unifw --> <add key="InspectorClassName" value="class_name_inspetor_dinamico"/> <!—Assembly que contém a classe de Inspetoria --> <add key="DynamicInspectorAssembly_1" value="assembly_name_inspetor1"/> <!—A classe de Inspetoria que será carregada pelo Unifw --> <add key="DynamicInspectorClassName_1" value="class_name_inspetor1"/> <!—Assembly que contém a classe de Inspetoria --> <add key="DynamicInspectorAssembly_2" value="assembly_name_inspetor2"/> <!—A classe de Inspetoria que será carregada pelo Unifw --> <add key="DynamicInspectorClassName_2" value="class_name_inspetor2"/>

Pode-se ver no exemplo acima que o Unifw permite a criação de mais de um Inspetor. O Unifw.Net buscará o inspetor no Web.config ou na tabela Config e executará o método validate no evento OnLoad de cada página.

6.6. Autenticadores O UniFW conta com o conceito de autenticadores, a fim de permitir que a autenticação do usuário fique mais flexível. È possível, por exemplo, autenticar um usuário em outro banco de dados que não seja o do UniFW, ou em um Active Directory, desde que se desenvolva um autenticador próprio para isso. É importante notar que ao se configurar um novo autenticador, este substituirá o autenticador atual do UniFW. Exemplo de implementação de um autenticador: public class SecurityAuthenticator : IAuthenticator { public void Authenticate(string Dominio, string Usuario, string Senha) { if (Dominio == null) { throw new DominioInvalidoException(ErrDominioInvalido); } if (Usuario == null) { throw new LoginInvalidoException(ErrUsuarioInvalido); } // Faz a autenticação dos dados Unitech.UNIFW.Seguranca.BS.Usuario usuario = new Unitech.UNIFW.Seguranca.BS.Usuario(); int IdenUsuario = usuario.Login(Dominio, Usuario, Senha, int.Parse( Unitech.Util.Configuracao.Obter( "PasswordExpire" ) )); // Verifica o resultado da autenticação switch (IdenUsuario) { case -1: // Usuário não existe throw new UsuarioNaoAutenticadoException(ErrNaoLogou); case -2: // Primeiro Login throw new UsuarioNaoAutenticadoException(ErrPrimeiroLogin); case -3: // A senha expirou throw new UsuarioNaoAutenticadoException(ErrSenhaExpirada); default: // Logou com sucesso User.UpdateUserInfo(Dominio, Usuario); break; } } } Analisando o código anterior, temos uma implementação da interface IAuthenticator que obrigará a classe a implementar o método: void Authenticate(string Domino, string Usuário, string Senha). Este método fica responsável por validar os dados que lhes foram passados da forma que quiser e em caso de sucesso chamar o método Unitech.Web.User.UpdateUserInfo(string domínio, string login). Em caso de falha na autenticação deverá ser levantada uma Exception com a mensagem desejada.

Pág.:57

Depois de implementado, esse autenticador deverá ser configurado no UniFW para que possa entrar em ação. Para isso basta criar/alterar as seguintes chaves no arquivo Web.config: <add key="AutenticadorAssembly" value=""/> <add key="AutenticadorClassName" value=""/> Obs.: O autenticador só fucionará se a tela de login da aplicação herdar da classe Unitech.Web.Frames.Login.

6.7. Serviços O Unifw.Net possui o recurso de agendamento de execução de serviços feitos por terceiros. Para isso o desenvolvedor precisa criar seu serviço herdando de Unitech.Service.ServiceBase, e sobrescrever o método Executar(). O Agendador de serviços do Unifw.Net (Unitech.ServiceManager) é um componente que roda como um serviço do Windows (Window Service). De minuto em minuto o ServiceManager checa a existência de Serviços para execução e ativa suas respectivas threads. Para que o ServiceManager possa carregar seu serviço este deverá ser instalado no GAC e cadastrado no módulo de serviços do Unifw, configurando-se sua primeira execução, seu intervalo, tipo do intervalo (minuto, hora, dia, ...), etc. Segue a Implementação do serviço de alarme do módulo Workflow: using System; using System.Data; namespace Unitech.Workflow.Servicos { public class Alarme : Unitech.Service.ServiceBase { public override void Executar(){ Unitech.UNIFW.Workflow.BS.Alarme AlarmeBS = new Unitech.UNIFW.Workflow.BS.Alarme(); try{ AlarmeBS.RegistraNotificacao(); }catch(System.Exception e){ Unitech.Util.Tracer.Write(TracerMessageCategory.Error,"Uniteh.Wokflow","O Serviço de Alarme não conseguiu registrar as notificações pendentes! "+e.Message ); } } } }

6.7.1. Agendamento de Automático de Relatórios Essa funcionalidade é indicada nos casos em que o relatório a ser gerado possui um volume muito grande de registros a serem processados naquele determinado momento. Essa funcionalidade tem o papel de encaminhar em outro momento um email com aquele relatório. Esse relatório poderá ser tanto um arquivo binário o qual o mesmo será anexado em um email, como poderá ser uma página HTML(modo texto). A classe responsável por esse serviço é a Unitech.UNIFW.Relatorio.Servico.EnvioRelatorioPendente do assembly Unitech.UNIFW.Relatório a qual deve estar registrada nos serviços da aplicação de administração do UniFW. O agendamento é realizado pela classe Unitech.UNIFW.Relatorio.AgendamentoRelatorio a qual irá incluir um registro de agendamento na fila de relatórios pendentes para que o serviço de Relatórios Pendentes efetue a entrega. O método AgendarRelatorio é o responsável pelo agendamento.

��������������������������� ��������� �������� ��� � ���������� ������������ ����� ��������� ����������������� ��� � ����������� ���������� ����� �������� ������������� � ����� �������� ���������� ������ �������� ��������� ������ ������ �

Pág.:58

Parâmetros:

URL ���� Endereço do relatório a ser enviado. Parametros ���� DataSet com os parâmetros a serem passados para o relatório. Esses parâmetros serão colocados em uma variável de sessão. IdenUsuario ���� Identificador do usuário que requisitou o relatório. Data ���� Data e hora em que se deve ser enviado o relatório. NomeSessao ���� Nome da variável de sessão que será criada com os parâmetros. UrlAutenticacao ���� Endereço da URL de autenticação no sistema a qual será gerado o relatório. Essa URL aponta para a tela de LoginRelatorio cadastrada nessa aplicação. Se a mesma não for informada será utilizada a tela de LoginRelatorio da aplicação do UniFW.NET. TituloEmail ���� Título do email do relatório pendente. CorpoEmail ���� Corpo do email do relatório pendente.

Existe uma outra sobrecarga do método AgendarRelatorio a qual não utiliza dos parâmetros UrlAutenticacao, TituloEmail e CorpoEmail. Nesse caso o serviço autentica-se na tela de LoginRelatorio do UniFW.NET e envia o email com o título “Relatório Pendente” e corpo “Segue em anexo o relatório pendente.”, isso se o relatório for um arquivo binário, no caso de ser um página (modo texto) a própria será enviada. Exemplo: Dim datahoraEnvio As DateTime = "01/01/2004 10:00:00" Dim objRelatorio As AgendamentoRelatorio = New AgendamentoRelatorio objRelatorio.AgendarRelatorio("http://localhost/Unitech.UNIFW1500/default.aspx?tela=USUARIO&modulo=SEGUR", dsVarSessao, 8, datahoraEnvio, "varSessao") Nos casos de envio de arquivo binário o parâmetro URL poderá ser modificado para fornecer ao serviço de envio de relatórios o nome do arquivo em anexo a ser enviado. Esse parâmetro deve ser passado por meio de querystring denominada NomeArquivo. Exemplo: objRelatorio.AgendarRelatorio("http://localhost/Unitech.UNIFW1500/default.aspx?tela=USUARIO&modulo=SEGUR&NomeArquivo=meurelatorio", dsVarSessao, 8, datahoraEnvio, "varSessao") Desenvolvimento da Tela para Autenticação do Serviço Relatório O serviço EnvioRelatorioPendente só conseguirá enviar um relatório que exija login requerido ou acesso requirido se a tela de autenticação for informada. Essa tela de autenticação deve pertencer à aplicação do relatório e a mesma deve ser especificada no momento da realização do agendamento, conforme já visto no tópico acima. Essa tela de autenticação será responsável pela validação do acesso do serviço (através do usuário unifw_emissor_relatorio), login do usuário que solicitou o relatório, carga dos parâmetros do relatório em sessão e por fim o redirecionamento para o mesmo. Para facilitação dessa implementação foi criada uma tela pré-fabricada, a LoginRelatorio pertecente ao namespace Unitech.Relatorio.Frames e ao assembly Unitech.Relatorio. A utilização da mesma é realizada através da herança, não se faz necessário mais nenhuma outra programação. Exemplo: Public Class Unifw_LoginRelatorio Inherits Unitech.UNIFW.Relatorio.Frames.LoginRelatorio ... End Class

Pág.:59

6.7.2. Configuração do Serviço RelatorioPendentes Primeiramente a classe Unitech.UNIFW.Relatorio.Servico.EnvioRelatorioPendente do assembly Unitech.UNIFW.Relatório deve estar registrada como serviço do UniFW. No arquivo de configuração do Unitech.Service.exe (Unitech.Service.exe.config) deve existe a TAG SiteAplicacao com o diretório da aplicação do UniFW.NET. Exemplo: <add key="SiteAplicacao" value="http://localhost/Unitech.UNIFW1500" /> A aplicação de administração do UniFW deve possuir o usuário unifw_emissor_relatorio no domínio unifw o qual será o responsável pelo envio do relatórios pendentes. Essa configuração fornece o caminho default de autenticação do serviço de envio de relatórios, podendo ser modificada para cada relatório específico. (ver tópico 8.6.1)

6.8. Tracer O Framework .Net possui recursos de tracer log durante a execução de páginas ASPX. Para ativar tal recurso, é necessário alterar os atributos enable e pageoutput da tag trace do WebConfig para o valor “true”. Quando esta tag está ativa, alem de escrever mensagens na seção de trace da página o Unifw.NET também escreverá algumas mensagens no eventlog do servidor da aplicação. Este recurso é útil para debug de serviços, já que estes não possuem uma camada de interação com o usuário em casos de ocorrências de exceções durante a execução. Note que ativar o recurso de trace, implicará num maior tempo para carregamento das páginas, devido ao processamento extra, necessário para a geração das mensagens.

6.9. Add-Ins do Visual Studio .NET Os add-ins têm por objetivo customizar a ferramenta de trabalho, o próprio Visual Studio, de modo a suprir de maneira eficaz e eficiente as necessidades do usuário. Através do desenvolvimento dos add-ins é possível realizar tarefas, outrora complicadas e que exigiam tempo, de maneira ágil e simples. Essa primeira versão de lançamento tem por enfoque principal, automatizar algumas tarefas realizadas pelos programadores da fabrica de software .Net. Foram acopladas ao Visual Studio as seguintes funcionalidades: cadastro de urls, tradução de mensagens e navegação rápida no UniFW. Cada uma dessas funcionalidades será descrita e ilustrada em detalhes nas subseções abaixo.

6.9.1. Configuração Antes de iniciar a descrição das funcionalidades, faz-se necessária a explicação do processo de configuração do add-in. São utilizados 2 arquivos para armazenar as configurações. Ambos estão localizados no diretório onde se encontra a IDE do Visual Studio (por padrão C:\Program Files\Microsoft Visual Studio .NET 2003\Common7\IDE). Um dos arquivos é o arquivo de configuração do VS (devenv.exe.config), no qual incluímos algumas tags que são essenciais para o funcionamento da aplicação. Exemplo: <configuration> <startup>

<supportedRuntime version="v1.1.4322"/> <requiredRuntime version="v1.1.4322"/>

</startup> <runtime> <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1"> <probing privatePath="PublicAssemblies;PrivateAssemblies"/> <qualifyAssembly partialName="System.Web" fullName="System.Web, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, Custom=null"/> <qualifyAssembly partialName="System" fullName="System, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089, Custom=null"/>

Pág.:60

<qualifyAssembly partialName="CustomMarshalers" fullName="CustomMarshalers, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"/> <qualifyAssembly partialName="CustomMarshalers, Version=1.0.5000.0" fullName="CustomMarshalers, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"/> <qualifyAssembly partialName="CustomMarshalers, Version=1.0.5000.0, PublicKeyToken=b03f5f7f11d50a3a" fullName="CustomMarshalers, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"/> <dependentAssembly> <assemblyIdentity name="Microsoft.VisualStudio" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" /> <bindingRedirect oldVersion="1.0.3300.0" newVersion="1.0.5000.0"/>

</dependentAssembly> <dependentAssembly> <assemblyIdentity name="CrystalDecisions.VSShell" publicKeyToken="692fbea5521e1304" culture="neutral" /> <bindingRedirect oldVersion="9.1.3300.0" newVersion="9.1.5000.0"/>

</dependentAssembly> </assemblyBinding> </runtime> <system.net> <settings>

<ipv6 enabled="true" /> </settings> </system.net> <appSettings> <add key="CommandTimeOut" value="99"/> <add key="ConfiguracaoAssembly" value="Unitech.UNIFW.Util"/> <add key="ConfiguracaoClassName" value="Unitech.UNIFW.Util.Configuracao"/>

<add key="DataFactoryUtilAssembly" value="Unitech.UNIFW.Util"/> <add key="DataFactoryUtilClassName" value="Unitech.UNIFW.Util.DAO.DataFactorySQLServer"/>

<add key="DataBaseOrigemDadosAssembly" value="Unitech.Data"/> <add key="DataBaseOrigemDadosClassName" value="Unitech.Data.SQLDataBaseTM" /> <add key="ConnectionStringOrigemDados" value="server=SEDEFRWNET02\unifwdb;uid=sa;pwd=unifw;database=bd_unifw16_lauro" /> </appSettings> </configuration>

Note que houve a inclusão da seção “appSettings” no arquivo acima. O outro arquivo de configuração existente tem o nome de unifw_addin.config.xml. Neste arquivo estão contidas informações de uso constante e padrão pelo add-in, tais quais: aplicação, idioma, país e url UnifW. Possui a seguinte estrutura: <?xml version="1.0" standalone="yes"?> <dsUniFWAddIn xmlns="http://tempuri.org/dsUniFWAddIn.xsd"> <xs:schema id="dsUniFWAddIn" targetNamespace="http://tempuri.org/dsUniFWAddIn.xsd" xmlns:mstns="http://tempuri.org/dsUniFWAddIn.xsd" xmlns="http://tempuri.org/dsUniFWAddIn.xsd" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata" attributeFormDefault="qualified" elementFormDefault="qualified"> <xs:element name="dsUniFWAddIn" msdata:IsDataSet="true"> <xs:complexType> <xs:choice maxOccurs="unbounded"> <xs:element name="Config"> <xs:complexType> <xs:sequence> <xs:element name="IdenAplicacao" type="xs:int" minOccurs="0" /> <xs:element name="IdenIdioma" type="xs:int" minOccurs="0" /> <xs:element name="IdenPais" type="xs:int" minOccurs="0" /> <xs:element name="UrlUniFW" type="xs:string" minOccurs="0" /> </xs:sequence> </xs:complexType> </xs:element> </xs:choice> </xs:complexType> </xs:element> </xs:schema> <Config> <IdenAplicacao>1</IdenAplicacao> <IdenIdioma>1</IdenIdioma>

Pág.:61

<IdenPais>1</IdenPais> <UrlUniFW>http://localhost/unitech.unifw</UrlUniFW> </Config> </dsUniFWAddIn> Esses arquivos são gerados pela janela de configuração ilustrada abaixo: Através da tela acima e suas respectivas guias é possível realizar alterações de configuração. Ao salvar as alterações, a mudança será refletida nos arquivos mencionados anteriormente. Para o correto funcionamento do add-in, além dessas configurações, é obrigatória a presença das Dlls do UniFW no diretório local onde se encontra instalado o IDE do Visual Studio .NET (por padrão C:\Program Files\Microsoft Visual Studio .NET 2003\Common7\IDE).

2.4.1. Cadastro de Urls O cadastro de urls pode ser feito de duas maneiras: cadastro individual e cadastro de uma estrutura de diretório que possua algum arquivo .ascx incluso na mesma. Exemplo de Cadastro Individual:

Após o clique na url que se deseja cadastrar, uma tela semelhante a tela acima é exibida. Deve-se clicar no botão de seleção de caminho Url, onde será especificado o local onde a url em questão deve ser cadastrada. A descrição da Url é opcional, embora recomendável.

O cadastro por diretório é realizado de maneira semelhante:

Após o clique no diretório que se deseja cadastrar, uma tela semelhante a tela acima é exibida. Um array de objetos contendo toda a estrutura de diretórios e seus respectivos arquivos .ascx é passado como parâmetro. Deve-se clicar no botão de seleção de caminho Url, para que seja especificado o local onde esta estrutura de diretórios deve ser criada e suas recpetivias urls cadastradas. A descrição da Url nesse tipo de cadastro não é possível. No momento que o cadastro está ocorrendo, o caminho da url e seu respectivo nome, são

Pág.:62

dinamicamente atualizados da tela. Uma barra de progresso indica como está sendo o desenvolvimento da operação.

6.9.2. Tradução de mensagens Essa funcionalidade permite que mensagens sejam cadastradas e traduzidas no UniFW de um modo prático e fácil. Inicialmente, esta funcionalidade pode ser acessada de duas maneiras diferentes: Através do menu do UniFW.NET e através da seleção de algum texto numa página de código (*.vb, *.cs, etc). Acesso via Menu: Quando o acesso é feito via Menu UniFW.NET, a tela de tradução de mensagens apresenta a seguinte disposição:

O grupo Mensagem vem automaticamente preenchido com o valor “Label”, pois foi avaliado que nesta situação,este grupo é o mais propicio a ser escolhido como local de armazenamento. Os campos “Sigla” e “Descrição” são obrigatórios. O campo “Texto Mensagem” é opcional, já que o usuário tem a opção de cadastrar a mensagem sem necesariamente ter que traduzi-la imediatamente. Há também a possibilidade de se acessar uma mensagem previamente existente e fazer quaisquer alterações desejadas. Como citado anteriormente, há uma outra forma de executar a tradução de mensagens. Ela se dá por meio da seleção de algum trecho de código na tela. Exemplo:

Quando esta opção é invocada, é feita uma validação que visa verificar a existência da mesagem selecionada. Em caso positivo, todas as informações referentes a esta mensagem são recuperadas e exibidas ao usuário. Em caso negativo, a tela comparta-se de modo semelhante à execução via menu. Porém o “Grupo

Pág.:63

Mensagem” padrão é “Erros”, e os campos “Sigla” e “Descrição” são preenchidos com o valor do texto selecionado.

6.9.3. Navegação rápida no UniFW

Essa funcionalidade tem por objetivo facilitar o acesso ao UniFW.NET. As telas que apresentam uma maior taxa de requisição foram agrupadas dentro de um submenu chamado de “Navegar”. Ao clique de um dos ítens do submenu, um browser é aberto dentro do Visual Studio e a respectiva Url do ítem é solicitada. Exemplo:

Pág.:64

7. Preparação do Ambiente de Desenvolvimento do UNIFW.NET

7.1. Softwares Básicos e Ambiente 1. MS Windows 2000

1.1. Último Service Pack (atualmente é o 3.0) 2. MS Visual Studio .Net

2.1. Último Service Pack (atualmente é o 2.0) 2.2. iewebcontrols.msi

3. MS SQL Server 2000 Client 4. MS Visual Source 6.0a

7.2. Passos para preparação do ambiente 1. Configuração do usuário do Visual Source Safe e realizar o ‘GET LAST VERSION’. O diretório

padrão para as pastas de desenvolvimento 1.1. pasta UNIFW o work folder é ‘C:\PROJETOS\UNIFW\’ 1.2. pasta APLICAÇÃO\UNIFW o work folder é ‘C:\INETPUB\WWWROOT\UNITECH.UNIFW\’ 1.3. pasta CHAVE o work folder é ‘C:\CHAVE\’

2. Cria um atalho para a solution ‘FullReferenciaPorProjeto’ a qual estará no diretório

‘C:\PROJETOS\UNIFW\SOLUTION\’.

3. Deve se compilar a solução ‘FullReferenciaPorProjeto’. Deve se configurar no VS que todos os projetos devem ser compilados no modo DEBUG.

3.1. Primeiro deve compilar todos o componentes. 3.2. Compilar a aplicação UNIFW.NET

4. Criar a pasta virtual ‘/Unitech.UNIFW’ para o diretório ‘C:\INETPUB\WWWROOT\UNITECH.UNIFW’.

Lembre-se de clicar no botão CREATE APPLICATION.

5. Colocar no PATH (em system) do Windows os seguintes diretórios: ‘C:\WINNT\Microsoft.NET\Framework\<version>;C:\Program Files\Microsoft Visual Studio .NET\FrameworkSDK\Bin’. O aplicativo ‘al.exe’ responsável pela geração de Dlls (funcionalidade do modulo de dicionário).

6. Alterar o arquivo ‘machine.config’ do diretório

‘C:\WINNT\Microsoft.NET\Framework\<version>\CONFIG’ (sendo que <version> é o nº de versão do ASP.NET). Alterar a propriedade ‘Username’ da TAG ‘Processmodel’ de ‘Machine’ para ‘SYSTEM’. Através dessa configuração possibilita que o ASP.NET execute certas ações as quais o usuário ‘Machine’ não possui as devidas permissões. (ação tipo executar o aplicativo ‘al.exe’)

7. Teste se a aplicação esta funcionando corretamente, abrindo o browser em

‘http://localhost/Unitech.UNIFW/’

Pág.:65

8. F.A.Q.

1. Mensagem ‘Unitech.Web.WebControls or one of it's refereces not found’

Verificar a pasta bin da Aplicação que deve conter as classes Unitech.Web*.dll

2. UniTreeView não renderiza corretamente Verificar a versão do browser se é IE5.5 ou superior.

3. Serviço assíncrono não ativa.

- Verificar se o serviço está ativo no cadastro, sua data e horário de Início. - Verificar se a dll do Serviço está no Gac

4. O Cadastro das funções das telas foi feito, bem como as permissões para papéis e grupos de trabalha foram dadas, mas o inspetor de segurança não funciona. Verificar na tabela Config ou no web.config se existe alguma configuração para algum inspetor especifico ou para o inspetor dinâmico. Se utilizar um inspetor específico verificar se as tags InspectorAssembly e InspectorClassName estão, respectivamente, com os valores Unitech.Web e Unitech.Web.Security.SecurityInspector. Se utilizar o inspetor dinâmico verificar o seguinte:

• Se as tags InspectorAssembly e InspectorClassName estão, respectivamente, com os valores Unitech.Web e Unitech.Web.DynamicInspector. • Se existe em umas das tags DynamicInspectorAssembly_X e DynamicInspectorClassName_X, respectivamente, os valores Unitech.Web e Unitech.Web.Security.SecurityInspector. Onde X é o número seqüencial.

5. O Cadastro das permissões de estado e transição foi feito, mas o Inspetor de Workflow não

funciona. Verificar na tabela Config ou no web.config se existe alguma configuração para algum inspetor especifico ou para o inspetor dinâmico. Se utilizar um inspetor específico verificar se as tags InspectorAssembly e InspectorClassName estão, respectivamente, com os valores Unitech.Web e Unitech.Web.Security.WorkflowInspector.

Se utilizar o inspetor dinâmico verificar o seguinte: • Se as tags InspectorAssembly e InspectorClassName estão, respectivamente, com os valores

Unitech.Web e Unitech.Web.DynamicInspector. • Se existe em umas das tags DynamicInspectorAssembly_X e

DynamicInspectorClassName_X, respectivamente, os valores Unitech.Web e Unitech.Web.Security.WorkflowInspector.

Onde X é o número seqüencial.

6. A coluna com os valores da chave primária do DataGrid não esta sendo exibida. Defina o atributo ShowsPK = True, desta forma a chave primária é exibida.

7. Como faço para pegar um DataSet() em cache e utiliza-lo em uma SimpleGrid? Preencha a propriedade cacheObjectName na inicialização do DataGrid no método desejado chame o getFromCache(), esse método preencherá o InnerDataSet com conteúdo do DataSet mantido em cachê.

8. Como que se redireciona de uma página para outra?

No método OnClick() do objeto que fez a chamada do redirecionamento, faça a seguinte chamada: Unitech.Web.Redirector.GoTo(sender)

9. Como faço para realizar o LOGOUT do usuário do sistema? O LOGOUT é feito através da seguinte chamada: Unitech.Web.User.LogOut();

Pág.:66

10. A auditoria não esta funcionando. Não esta gerando um registro em OperacaoAuditoria. O que

pode ser?

a) Verificar na tabela Config ou no web.config se existe alguma configuração para auditoria. Caso existaverificar se as tags AuditorAssembly e AuditorClassName estão, respectivamente, com os valores Unitech.Web e Unitech.Web.Security.SecurityAudit.

b) Confira se no Global.asax.vb da aplicação WEB possui a chamada pelo método Fill da classe Context (namespace Unitech.Web.Util) no evento Application_BeginRequest. Esse método é responsável pela auditoria em POSTBACK.

Sub Application_BeginRequest(ByVal sender As Object, ByVal e As EventArgs) Unitech.Web.Util.Context.Fill()

End Sub

c) Examine se a trilha foi criada para o domínio a ser auditado. O usuário logado no UniFW.NET

criará trilhas somente para o seu domínio.

d) Confira se a trilha possui escopo e alvo.

e) Verifique se a tela a ser auditada possui pelo menos uma ação vinculada a uma função a ser auditada (referente ao escopo).

f) É válido ressaltar que o processo de auditoria começa pela verificação da querystring solicitada,

avaliando os parâmetros APLICACAO, MODULO, TELA e ACAO. Dessa forma, o UniFW.NET estará criando a Operação Auditoria quando for verificado:

1. Que a combinação de tais parâmetros representa um escopo (a ação da tela corresponde a uma função a ser auditada) de uma trilha

2. E o usuário que estiver realizando a solicitação da tela seja o alvo (pertinentes a um papel e grupo de trabalho a ser auditado) da trilha mencionada no item anterior.

11. A minha aplicação não está realizando a auditoria em POSTBACK. O que pode ser? Para realização da auditoria em postbacks se faz necessário a presença da chamada Unitech.Web.Util.Context.Fill() no evento Application_BeginRequest da classe Global (presente no arquivo Global.asax.vb no dirétorio raiz da aplicação WEB) . Esse método é responsável pela atualização no CallContext(váriavel de escopo de processo) da atual operação de auditoria.

12. Qual o procedimento diante dos erros “Object reference not found”, “specified cast is not

valid’ ? Finalize o processo ‘aspnet_wp.exe’, caso o mesmo não possa ser finalizado entre no DOS e execute o ‘iisreset.exe’.

13. Ao executar pela 1º vez uma aplicação WEB após o mesma ser atualizada, surge o erro

“especified cast is not valid’ Versões incompatíveis entre as Dlls do GAC e do diretório BIN.

14. Como definir o timeout padrão de execução de comandos de acesso a base de dados? Se o acesso a base de dados for executado através de classes IDATABASE do UniFW, a configuração do timeout padrão é feita através do parâmetro “CommandTimeOut” que define em segundos este tempo. Este parâmetro se localiza no arquivo de configuração AppSettings(ex.: web.config”).

15. Ao executar pela 1º vez uma aplicação WEB, surge o erro “Object reference not set to an instance of an object.”. Verifique se as Dlls Unitech.UNIFW.Util e Unitech.Data.SQLSequence estão no diretório BIN ou no GAC.

Pág.:67

16. O UniDualList não está realizando a transferência de itens de um ListBox para outro, ao invés

disso o mesmo está realizando POSTBACK 1º No controle que irá utilizar o UniDualList deverá ter dois HtmlInputHidden com os seguintes nomes

[ID_DO_DUALIST]RightListBoxValues e [ID_DO_DUALIST]LeftListBoxValues, sendo que [ID_DO_DUALIST] é o nome do identificador do controle UniDualListBox. A não existência desses HtmlInputHidden ocasionará o problema no funcionamento do componente.

2º Os controles HtmlInputHidden devem possuir os values dos itens dos ListBoxes do UniDualList, sendo que o [ID_DO_DUALIST]RightListBoxValues deve ter os valores do ListBox da Direita e o [ID_DO_DUALIST]LeftListBoxValues da esquerda. O inputhidden terá no final em seu VALUE uma string contendo os values dos itens do listbox (obedecendo à ordem) delimitado por virgula. A falta dessa configuração provocará irregulariedades no funcionamento do DualList.

Observação: - Não será possível utilizar o UniDualList com itens no ListBox que não possuam

chaves (value). É válido informar que cada item de ambos os ListBoxes devem possuir chaves(value) distintas, pois a mesma é utilizada pelo componente para identificação dos itens.

Pág.:68

9. Bibliografia

MSDN. Microsoft. Disponível em <http://www.msdn.microsoft.com/net/>. Acessada em 20 de Setembro de 2002.

Liberty, Jesse. Programing C#. Ed. O’Reilly Thai, Thuan e Lam, Hoang Q., .Net framework Essentials. Ed. O’Reilly Gamma, Erich. Design Patterns: Elements of Reusable Object-Oriented Software