Microsoft .NET
Application Blocks
2003 / 2004
980304 André Coutinho
Departamento de Engenharia Informática
Setembro 2004
Orientador ISEP: Paulo Sousa
Microsoft .NET – Application Blocks
Agradecimentos
Muito obrigado ao meu orientador o Engº. Paulo Sousa, pela ajuda na realização
deste relatório.
I
Microsoft .NET – Application Blocks
Índice
Agradecimentos .....................................................................................................I
Índice ....................................................................................................................II
Índice de figuras..................................................................................................VI
Índice de Tabelas ...............................................................................................VII
Glossário .......................................................................................................... VIII
1. Introdução ......................................................................................................... 1
1.1. O que são os application blocks? ................................................................... 1
1.1.1. Código redundante ...................................................................................... 1
1.1.2. Encapsulamento .......................................................................................... 1
1.2. Para que servem? ........................................................................................... 1
1.3. Benefícios de usar os application blocks ....................................................... 2
1.4. Estrutura do Relatório.................................................................................... 2
2. Data Access Application Block ........................................................................ 3
2.1. Introdução ...................................................................................................... 3
2.2. Classes principais do DAAB ......................................................................... 4
2.2.1. Classe SqlHelper......................................................................................... 4
2.2.1.1. Os métodos da classe SqlHelper .............................................................. 5
2.2.1.2. Detalhes de implementação ..................................................................... 7
2.2.1.3. Opções para passagem de parâmetros...................................................... 7
2.2.1.4. Funções Privadas ..................................................................................... 8
2.2.2. Classe SqlHelperParameterCache............................................................... 9
2.2.2.1. Os métodos da classe SqlHelperParameterCache.................................. 10
2.2.2.2. Detalhes de implementação ................................................................... 10
2.2.3. Usando o DAAB para executar comandos SQL....................................... 10
2.2.4. Usando o DAAB para executar Stored Procedures.................................. 11
3. Logging Application Block ............................................................................ 13
3.1. Introdução .................................................................................................... 13
3.1.1. Enterprise Instrumentation Framework .................................................... 13
3.2. Logging........................................................................................................ 14
3.2.1. Formatação da informação dos eventos.................................................... 15
3.2.2. Configuração dos níveis de log................................................................. 17
3.2.3. EnterpriseInstrumentation.config.............................................................. 19
4. Exception Management Application Block .................................................... 21
4.1. Introdução .................................................................................................... 21
4.2. Classes do EMAB ........................................................................................ 22
4.2.1. Classe BaseApplicationException ............................................................ 22
4.2.2. Classe ExceptionManagerSectionHandler................................................ 23
4.2.3. Classe ExceptionManager......................................................................... 23
4.2.4. Classe ExceptionManagerInstaller ........................................................... 24
4.2.5. Classe Default Publisher........................................................................... 24
4.2.6. A interface IExceptionPublisher............................................................... 24
4.2.6.1. Métodos da interface IExceptionPublisher ............................................ 24
4.2.7. A interface IExceptionXmlPublisher........................................................ 25
4.2.7.1. Métodos de IExceptionXmlPublisher.................................................... 26
5. Configuration Management Application Block.............................................. 28
5.1. Introdução .................................................................................................... 28
5.2. Elementos constituintes do CMAB.............................................................. 28
5.3. Objectivos .................................................................................................... 30
II
Microsoft .NET – Application Blocks
5.4. Vantagens..................................................................................................... 30
5.5. Porquê a criação do CMAB ......................................................................... 32
5.6. Criação de um CSP de leitura ...................................................................... 33
5.7. Criação de um CSP de leitura/escrita .......................................................... 33
5.8. Criação de um DPP...................................................................................... 33
6. Updater Application Block ............................................................................. 35
6.1. Introdução .................................................................................................... 35
6.2. Arquitectura do UAB................................................................................... 36
6.2.1. Classes do UAB ........................................................................................ 40
6.2.1.1. Classe ServerApplicationInfo ................................................................ 40
6.2.1.1.1. Objectivos ........................................................................................... 40
6.2.2. Os ficheiros manifest ................................................................................ 41
7. Caching Application Block............................................................................. 42
7.1. Introdução .................................................................................................... 42
7.2. Funcionamento............................................................................................. 42
7.3. O que são os Service Agents........................................................................ 42
7.4. A interface IServiceAgent............................................................................ 43
7.4.1. Métodos da interface IServiceAgent......................................................... 43
7.5. O método PersistCallback............................................................................ 43
7.6. Término de um Service Agent ..................................................................... 43
7.7. Usando o CAB com outros application blocks ............................................ 43
7.8. Componentes primários do CAB................................................................. 44
7.8.1. Classe CacheManager............................................................................... 44
7.8.1.1. Métodos da classe CacheManager ......................................................... 44
7.8.1.2. Propriedades da classe CacheManager .................................................. 45
7.8.2.A classe CacheService ............................................................................... 45
7.8.2.1. Métodos da classe CacheService ........................................................... 45
7.8.3. A interface ICacheStorage ........................................................................ 46
7.8.3.1. Métodos da interface ICacheStorage ..................................................... 47
7.8.3.2. Propriedades da interface ICacheStorage .............................................. 47
7.9. Ficheiros de Configuração ........................................................................... 47
7.10. Protecção de dados..................................................................................... 49
7.10.1. A interface IDataProtection .................................................................... 49
7.10.1.1. Métodos do interface IDataProtection ................................................. 49
7.11. Expiração ................................................................................................... 50
7.11.1. Classe AbsoluteTime .............................................................................. 50
7.11.1.1. Construtores da classe AbsoluteTime.................................................. 50
7.11.1.2. Métodos da classe AbsoluteTime ........................................................ 50
7.11.2. Classe ExtendedFormatTime .................................................................. 50
7.11.3. Classe FileDependency........................................................................... 51
7.11.3.1. Construtores da classe FileDependency .............................................. 51
7.11.3.2. Métodos da classe FileDependency..................................................... 51
7.11.3.3. Eventos da classe FileDependency ...................................................... 51
7.11.4. Classe SlidingTime ................................................................................. 51
7.11.4.1. Métodos da classe SlidingTime ........................................................... 52
7.11.4.2. Eventos da classe SlindingTime .......................................................... 52
7.12. Exploração ................................................................................................. 53
7.12.1. A interface IScavengingAlgorithm ......................................................... 53
7.12.1.1. Métodos do interface IScavengingAlgorithm...................................... 53
7.13. Armazenamento ......................................................................................... 54
III
Microsoft .NET – Application Blocks
7.13.1. Como escolher uma das opções de armazenamento ............................... 54
7.13.2. Classe MemoryMappedFileStream......................................................... 54
7.13.2.1. Construtores da classe MemoryMappedFileStream ............................ 55
7.13.2.2. Métodos da classe MemoryMappedFileStream................................... 55
7.13.2.3. Propriedades da classe MemoryMappedFileStream............................ 56
8. Aggregation Application Block ...................................................................... 57
8.1. Introdução .................................................................................................... 57
8.2. Funcionamento............................................................................................. 57
8.3. Usando o AAB com outros Application Blocks .......................................... 57
8.4. Design do AAB............................................................................................ 58
8.5. Classe AggregationRequest ......................................................................... 59
8.5.1. Construtor da classe AggregationRequest ................................................ 59
8.5.2. Métodos da classe AggregationRequest ................................................... 59
8.6. A estrutura AggregatedResult...................................................................... 59
8.6.1. Propriedades da estrutura AggregatedResult ............................................ 59
8.7. Ficheiro de configuração.............................................................................. 60
9.1. Introdução .................................................................................................... 64
9.2. Funcionamento............................................................................................. 64
9.3. Utilização do AIAB com outros application blocks .................................... 64
9.4. Arquitectura do AIAB ................................................................................. 65
9.4.1. O subsistema Request ............................................................................... 65
9.4.1.1. Classe AsyncRequestBacth.................................................................... 66
9.4.1.1.1. Construtor da classe AsyncRequestBatch........................................... 66
9.4.1.1.2. Métodos da classe AsyncRequestBatch.............................................. 66
9.4.1.1.3. Propriedades da classe AsyncRequestBatch....................................... 66
9.4.2. O subsistema Dispatcher........................................................................... 67
9.4.2.1. Classe AsyncROHServices.................................................................... 68
9.4.2.1.1. Construtor da classe AsyncROHService ............................................ 68
9.4.2.1.2. Métodos da classe AsyncROHService ............................................... 68
9.4.2.2. Classe AsyncDispatcher ........................................................................ 68
9.4.2.2.1. Propriedades da classe AsyncDispatcher............................................ 68
9.4.2.3. Classe Processor .................................................................................... 69
9.4.2.3.1. Métodos da classe Processor............................................................... 69
9.4.2.4. Classe ServiceAgentReqDetails ............................................................ 69
9.4.2.4.1. Construtor público da classe ServiceAgentReqDetails ...................... 69
9.4.2.4.2. Métodos da classe ServiceAgentReqDetails....................................... 69
9.4.2.4.3. Propriedades da classe ServiceAgentReqDetails................................ 70
9.4.2.5. Classe ResultManager............................................................................ 70
9.4.2.5.1. Métodos da classe ResultManager...................................................... 70
9.4.3. O subsistema Monitor............................................................................... 71
9.4.3.1. Classe RecoveryMonitor........................................................................ 72
9.4.3.1.1. Construtor da classe RecoveryMonitor............................................... 72
9.4.3.1.2. Métodos da classe RecoveryMonitor.................................................. 72
9.4.3.2. Classe GarbageCollection...................................................................... 72
9.4.3.2.1. Construtor da classe GarbageCollection............................................. 72
9.4.3.2.2. Métodos da classe GarbageCollection ................................................ 72
9.4.4. Design da base de dados ........................................................................... 72
9.4.5. Ficheiros de configuração ......................................................................... 73
10. User Interface Process Application Block .................................................... 77
10.1. Introdução .................................................................................................. 77
IV
Microsoft .NET – Application Blocks
10.2. Descrição da solução.................................................................................. 77
10.3. Classes Factory .......................................................................................... 78
10.3.1. Classe GenericFactory ............................................................................ 79
10.3.1.1. Métodos da classe GenericFactory ...................................................... 79
10.3.2. Classe ControllerFactory ........................................................................ 79
10.3.2.1. Métodos da classe ControllerFactory .................................................. 79
10.3.3. Classe StatePersistenceFactory............................................................... 79
11. Conclusão...................................................................................................... 80
12. Bibliografia ................................................................................................... 82
V
Microsoft .NET – Application Blocks
Índice de figuras
Figura 1: Arquitectura do DAAB ......................................................................... 4
Figura 2: A arquitectura EIF ............................................................................... 14
Figura 3: Arquitectura do Logging Application Block....................................... 15
Figura 4: Como funciona o EMAB..................................................................... 21
Figura 5: A arquitectura do EMAB .................................................................... 22
Figura 6: Relação entre os elementos do CMAB (arquitectura)......................... 28
Figura 7: Mantendo aplicações actualizada com o UAB.................................... 35
Figura 8: Arquitectura do UAB .......................................................................... 36
Figura 9: Mapeamento do ficheiro de configuração do updater da aplicação
(application updater) .......................................................................................... 38
Figura 10: Arquitectura de validação do lado do cliente .................................... 38
Figura 11: Arquitectura de validação do lado do servidor.................................. 39
Figura 12: Arquitectura de post processing do UAB ......................................... 40
Figura 13: Mapeamento da classe ServerApplicationInfo num ficheiro
manifest ............................................................................................................... 41
Figura 14: Arquitectura do AAB ........................................................................ 58
Figura 15: Arquitectura do AIAB ....................................................................... 65
Figura 16: Base de dados usada pelo AIAB ....................................................... 73
Figura 17: Funcionamento do Controller ........................................................... 78
VI
Microsoft .NET – Application Blocks
Índice de Tabelas
Tabela 1: As diferentes assemblies do CAB....................................................... 44
VII
Microsoft .NET – Application Blocks
Glossário
AAB - Aggregation Application Block.
AIAB - Asynchronous Invocation Information Application Block.
BITS - Background Intelligent Transfer Service.
CAB - Caching Application Block.
CMAB – Configuration Management Application Block.
CSP – Configuration Section Provider.
DAAB – Data Access Application Block.
DPAPI – Data Protection API.
DPP – Data Protection Provider.
EIF – Enterprise Instrumentation Framework.
EMAB – Exception Management Application Block.
FSP – Foreign Service Provider.
LAB – Logging Application Block.
MAC – Message Authentication Code.
MMF – Memory-mapped file
MVC – Model View Controller.
RAD – Rapid Application Development.
UAB – Updater Application Block.
UIPAB – User Interface Process Application Block.
WMI – Windows Management Instrumentation.
XML – Extensible Markup Language.
XSLT – Extensible Stylesheet Language.
VIII
Microsoft .NET – Application Blocks
1. Introdução
1.1. O que são os application blocks?
A Microsoft disponibiliza application building blocks para o Framework .NET,
que encapsulam certas áreas chave, facilitando a construção de aplicações ao
fornecerem implementações out of the box de serviços comuns tais como acesso
a dados, configuração e tratamento de excepções.
Os application building blocks promovem o desenvolvimento de aplicações mais
rápido e mais correcto, fazendo uso de boas práticas de programação.
A seguir são apresentados os principais motivos que levaram à criação dos .NET
application blocks.
1.1.1. Código redundante
A redundância de código é um problema grave que afecta a dimensão, eficiência,
manutenção e correcção de erros de uma aplicação.
Determinar a redundância é útil para reduzir a programação “copy/paste” que se
acumulou num projecto.
Os problemas gerados por este tipo de atitude ao programar, são os seguintes:
•
•
•
•
•
•
•
Um qualquer erro num determinado algoritmo terá de ser corrigido em
todas as aplicações em que foi introduzido.
Tornar o programa mais genérico.
Alertar o programador que está a inventar algo já existente.
Descobrir cópias.
Falta de encapsulamento, isto torna a manutenção e extensão bastante
complexas.
Durante a manutenção de programas é frequente termos de reescrever
código, para o tornar mais claro, mais genérico, mais eficiente e menos
redundante.
A reescrita é perigosa, pois pode não preservar a semântica do código
original (introduz bugs).
1.1.2. Encapsulamento
A falta de encapsulamento também é um problema, que afecta a manutenção e
extensão da aplicação, e aumenta a sua complexidade. Sem encapsulamento, as
informações são globais e podem ser acedidas directamente, criando confusão
sobre quem definiu o quê e quando. A ideia subjacente ao encapsulamento é
proteger a informação (código, dados), por trás de uma barreira, para evitar a
utilização indevida de determinado objecto ou classe que possa corromper a
informação a proteger.
1.2. Para que servem?
Os application blocks encapsulam uma optimização das boas práticas e técnicas
de programação para trabalhar no Framework .NET, como já foi dito. São
reutilizáveis, e permitem reduzir grande parte do código redundante (aquele
André Coutinho
1
Microsoft .NET – Application Blocks
código reescrito cada vez que queremos implementar uma determinada
funcionalidade). Considerando, por exemplo, uma aplicação que requer acesso a
uma base de dados, verifica-se que se usa repetidamente muitos blocos de
código. Um application block encapsula o código mais utilizado, fornecendo
portanto uma forma simples de reutilizar código eficientemente.
Outra vantagem dos application blocks consiste na camada que formam sobre o
Framework .NET. Usando os application blocks é possível reter os métodos
mais expostos/usados dos application blocks e internamente lidar com as
mudanças na Framework .NET. A aplicação fica protegida das mudanças que
poderão ocorrer nas bibliotecas .NET, e assim, aumentar a capacidade da
manutenção.
1.3. Benefícios de usar os application blocks
Sem dúvida que o maior benefício de usar os application blocks é a capacidade
que estes têm de tornar o desenvolvimento mais rápido e modular de programas.
Uma vez que muito do código está encapsulado, isto vai permitir mais
concentração na “business logic” da aplicação.
1.4. Estrutura do Relatório
Este relatório está estruturado de acordo com o tema que levou à sua realização,
os application blocks .NET da Microsoft, ou seja, existe um capítulo por
application block (um block, um capítulo). Além destes, foram também
incluídos um capítulo de introdução, conclusão e bibliografia.
Tendo sido estudados nove application blocks, cada capítulo dedicado a um
determinado application block começa por fazer um pequena introdução e
seguidamente são descritas as suas principais classes, métodos e interfaces, com
exemplos, bem como detalhes de implementação nos casos em que isto se
justificou.
Anteriormente à descrição das classes, métodos e interfaces, apresentam-se
ainda os objectivos da criação de cada application block, bem como as suas
vantagens. São ilustrados também, alguns casos de utilização.
André Coutinho
2
Microsoft .NET – Application Blocks
2. Data Access Application Block
2.1. Introdução
O Data Access Application Block é um componente disponível para a
Framework .NET, que contém código de acesso a dados, optimizado, e que
facilita a execução de Stored Procedures e comandos SQL, sobre uma base de
dados Microsoft SQL Server. A sua implementação é centrada à volta da classe
SqlHelper (responsável pelo encapsular das tarefas mais comuns de acesso e
gestão de dados) que possui métodos estáticos para os serviços mais comuns de
acesso a dados (ex., efectuar um select para obter um DataSet). O facto destes
métodos serem estáticos significa que podem ser chamados sem existir uma
instância da classe. Por exemplo, o método ExecuteReader() (classe
SqlHelper)
pode
ser
chamado
usando
simplesmente
SqlHelper.ExecuteReader, não é necessário instanciar um objecto da classe
SqlHelper.
Estes métodos estáticos do DAAB (como daqui em diante será referido) podem
ser utilizados para devolver objectos do tipo SqlDataReader, DataSet e
XmlReader contendo a informação desejada. É ainda possível especificar
parâmetros para os Stored Procedures, e a classe está preparada para lidar com
transacções.
Especificamente o DAAB ajuda a:
• Executar Stored Procedures e comandos de texto SQL, mais facilmente.
• Especificar detalhes dos parâmetros.
• Retornar objectos do tipo SqlDataReader, Dataset, XmlReader, ou valores
isolados.
• Usar tabelas e campos strong typed.
• Suportar caching de parâmetros, quando necessários.
• Permitir a adição de novas tabelas, através da passagem de Datasets préexistentes.
• Actualizar um DataSet, com comandos de update especificados pelo
utilizador.
• Criar objectos SqlCommand.
• Permitir que DataRows sejam passados como parâmetros.
A versão analisada neste capítulo é a versão 2 deste application block.
Relativamente ao anterior foram acrescentadas as seguintes funcionalidades:
• Suporte para strongly typed Datasets com o método FillDataSet.
• Suporte à realização de updates sobre um Dataset, para a base de dados.
• Métodos helper adicionais com suporte para parâmetros do tipo DataRow.
André Coutinho
3
Microsoft .NET – Application Blocks
Os principais elementos do DAAB estão ilustrados na Figura 1.
Figura 1: Arquitectura do DAAB
2.2. Classes principais do DAAB
2.2.1. Classe SqlHelper
A classe SqlHelper é o componente central do DAAB. Fornece métodos que
permitem implementar soluções de acesso a dados para bases de dados SQL
Server.
Os principais objectivos desta classe são:
• Encapsular os métodos mais comuns de acesso a dados, minimizando o
código customizado a usar.
• Permitir que as aplicações cliente executem updates a bases de dados, ou que
recebam valores, objectos SqlDataReader, objectos DataSet, ou objectos
XmlReader, usando um conjunto consistente de métodos.
• Permitir que as aplicações cliente executem comandos SQL ou Stored
Procedures, usando o mesmo método.
André Coutinho
4
Microsoft .NET – Application Blocks
•
•
•
•
•
•
A especificação por parte das aplicações cliente da string de conexão ou o
objecto SqlConnection para determinar a origem dos dados.
Permitir que a aplicação cliente especifique parâmetros se necessário, que
serão passados como um array de objectos SqlParameter, ou ainda,
permitir a passagem de parâmetros para Stored Procedures.
Especificar uma transacção ADO.NET, por parte dos clientes, e poder
introduzir um comando na transacção.
Possibilitar o preenchimento de um DataSet.
Possibilitar a persistência do update feito a um DataSet para uma base de
dados física.
Suportar DataSets strong type.
2.2.1.1. Os métodos da classe SqlHelper
Para satisfazer os objectivos da classe SqlHelper, esta classe possui vários
métodos com overload, para cada tarefa de acesso a dados. Estes métodos
fornecem múltiplas implementações de uma mesma função (overload), de modo
a aumentar a flexibilidade em termos de informação sobre a conexão, parâmetros
e transacções.
A seguir apresentam-se os métodos constituintes desta classe, juntamente com
um dos seus overloads, para cada um dos métodos. Uma vez que cada método
tem vários overloads, decidiu-se apresentar apenas um overload de cada um.
Os métodos da classe SqlHelper são então os seguintes:
•
ExecuteNonQuery.
Este método é usado para executar comandos que não
devolvem valores ou linhas de uma tabela. É geralmente utilizado para
executar updates de bases de dados, mas também para devolver parâmetros
de saída de Stored Procedures.
public static int ExecuteNonQuery(
string connectionString,
CommandType commandType,
string commandText)
•
ExecuteReader.
Método utilizado para devolver objectos SqlDataReader
contendo o resultado devolvido por um comando SQL executado.
private static SqlDataReader ExecuteReader(
SqlConnection connection,
SqlTransaction transaction,
CommandType commandType,
string commandText,
SqlParameter[] commandParameters,
SqlConnectionOwnership connOwnership)
•
ExecuteDataSet.
Este método retorna um objecto DataSet contendo o
resultado da execução de um comando.
public static DataSet ExecuteDataset(
string connectionString,
CommandType commandType,
string commandText)
André Coutinho
5
Microsoft .NET – Application Blocks
•
ExecuteScalar. Retorna apenas um valor. Este valor é sempre a primeira
coluna, da primeira linha devolvida pela execução do comando SQL.
public static object ExecuteScalar(
string connectionString,
CommandType commandType,
string commandText)
•
ExecuteXmlReader.
Devolve um fragmento XML, de um inquérito FOR
XML.
public static XmlReader ExecuteXmlReader(
SqlConnection connection,
CommandType commandType,
string commandText)
•
FillDataSet. Método similar ao ExecuteDataSet, mas que em vez de
devolver um novo objecto DataSet, adiciona informação ao DataSet
existente.
public static void FillDataset(
string connectionString,
CommandType commandType,
string commandText,
DataSet dataSet,
string[] tableNames)
•
UpdateDataSet.
Propaga as mudanças efectuadas num DataSet, para a base
de dados física.
public static void UpdateDataset(
SqlCommand insertCommand,
SqlCommand deleteCommand,
SqlCommand updateCommand,
DataSet dataSet,
string tableName)
•
CreateCommand.
Este método permite especificar os argumentos para o
comando a ser usado pelo UpdateDataSet.
public static SqlCommand CreateCommand(
SqlConnection connection,
string spName,
params string[] sourceColumns)
•
ExecuteNonQueryTypedParams.
É similar ao ExecuteNonQuery, no entanto
os parâmetros de saída obtidos vêm de um DataRow.
public static int ExecuteNonQueryTypedParams(
String connectionString,
String spName,
DataRow dataRow)
André Coutinho
6
Microsoft .NET – Application Blocks
•
ExecuteDataSetTypedParams.
Este método é idêntico ao ExecuteDataset,
mas os parâmetros de saída obtidos vêm de um DataRow.
public static DataSet ExecuteDatasetTypedParams(
string connectionString,
String spName,
DataRow dataRow)
•
ExecuteReaderTypedParams. Idêntico ao método ExecuteReader, com a
excepção dos parâmetros obtidos vêm de um DataRow.
public static SqlDataReader ExecuteReaderTypedParams(
String connectionString,
String spName,
DataRow dataRow)
•
ExecuteScalarTypedParams.
Este método é idêntico ao ExecuteScalar,
mas os parâmetros de saída obtidos vêm de um DataRow.
public static object ExecuteScalarTypedParams(
String connectionString,
String spName,
DataRow dataRow)
•
ExecuteXmlReaderTypedParams.
Este
ExecuteXmlReader, mas os parâmetros
DataRow.
método
é
idêntico
ao
de saída obtidos vêm de um
public static XmlReader ExecuteXmlReaderTypedParams(
SqlConnection connection,
String spName,
DataRow dataRow)
2.2.1.2. Detalhes de implementação
A classe SqlHelper foi desenhada para encapsular as funcionalidades de acesso
a dados, através de uma série de métodos estáticos. Como não foi criada para ser
herdada ou instanciada, esta classe é declarada como não herdável com um
construtor privado.
Cada um dos métodos implementados consiste num conjunto de overloads
consistente. Isto providencia um padrão bem definido para execução de
comandos usando esta classe, enquanto dá aos programadores a flexibilidade
para escolherem a forma de acesso aos dados. Os overloads de cada método
suportam diferentes argumentos, de modo a ser possível decidir como é passada
a informação sobre parâmetros, conexão e transacções.
2.2.1.3. Opções para passagem de parâmetros
Uma das principais opções aquando da chamada de um método da classe
SqlHelper é como fazer a passagem de parâmetros para o comando a executar.
As opções são:
• Usar um overload que não aceite parâmetros para o comando.
André Coutinho
7
Microsoft .NET – Application Blocks
•
•
•
Esta opção é útil quando, por exemplo, há necessidade de executar um
Stored Procedure que não leva qualquer parâmetro.
Usar
um
overload
que
aceite
objectos
SqlParameter
(commandParameters).
Este overload que aceita objectos SqlParameter, também aceita um array
dos mesmos objectos. Este array é marcado com a palavra chave
ParamArray. Isto significa que existem duas abordagens a estes overloads. É
possível passar um array contendo os parâmetros para o comando, ou então
passar objectos SqlParameter individualmente para cada parâmetro do
comando.
Usar um overload para StoredProcedures que aceitem uma lista de valores de
parâmetros (parameterValues).
Internamente, estes parameterValues são atribuídos a um array de objectos
SqlParameter usando a função AssignParameter.
Embeber parâmetros num DataRow e chamar um dos métodos
*TypedParams, como por exemplo, o ExecuteNonQueryTypedParams.
2.2.1.4. Funções Privadas
Além dos métodos públicos, a classe SqlHelper inclui funções privadas, usadas
para gerir parâmetros e preparar comandos para execução. Independentemente
da implementação de determinado método usada, todos os comandos são
executados usando um objecto SqlCommand.
Antes deste objecto ser executado, quaisquer parâmetros devem ser adicionados
à sua colecção de objectos Parameter. As propriedades Connection,
CommandType, CommandText, e Translation também devem ser definidas
correctamente. O principal objectivo destas funções é fornecer uma forma
consistente de execução de comandos sobre uma base de dados SQL Server,
independentemente da implementação do método usada.
Os métodos privados são:
AttachParameters. Os clientes podem passar a esta função um array de
objectos SqlParameter, com os parâmetros associados ao comando a executar.
Antes de um objecto SqlCommand ser usado para executar o comando, cada
parâmetro do array deve ser adicionado à colecção de objectos Parameters do
objecto SqlCommad.
AssignParameter. Esta função é utilizada quando um Stored Procedure é
chamado, usando uma lista de parâmetros separados por vírgulas (Param1,
Param2, ...Paramn). A função executa um ciclo sobre um array de objectos
SqlParameters, contendo os parâmetros para o Stored Procedure e atribui o
valor correspondente a partir do array de parâmetros passados pela aplicação
cliente. Depois destes parâmetros estarem atribuídos, o array de objectos
SqlParameters pode ser passado à função para ser adicionado ao objecto
SqlCommand.
Existe um overload desta função que recebe um DataRow como argumento.
André Coutinho
8
Microsoft .NET – Application Blocks
PrepareCommand.
Esta função serve para definir as propriedades do objecto
SqlCommand usado para executar o Stored Procedure ou comando especificado
pela aplicação cliente. A função PrepareCommand faz a conexão à base de dados
e atribui as propriedades Connection e CommandType, verificando também se
alguma transacção foi especificada, e define a propriedade Transaction, no
caso de ter sido.
Finalmente define a propriedade CommandText e executa o comando.
ExecuteReader. O ExecuteReader
permitir que o DataReader seja aberto
usa um método interno privado, para
com o CommandBehavior apropriado para
gerir o tempo de vida da conexão foi passado pelo cliente ou criado pela classe
SqlHelper a partir de uma string de conexão. Um enum privado é usado para
definir a origem do objecto de conexão.
FillDataSet.
Os overloads públicos do método FillDataSet são
implementados por uma chamada a um overload interno e privado do mesmo
método.
2.2.2. Classe SqlHelperParameterCache
A classe SqlHelperParameterCache providencia funcionalidades para o
armazenamento (caching), e retorno de parâmetros utilizados pelos comandos e
Stored Procedures executados pelas aplicações.
É comum as aplicações executarem um determinado comando por diversas
vezes. A vantagem que esta classe traz, é que torna desnecessária a recriação dos
parâmetros usados por um qualquer comando, para cada execução do mesmo.
Existem dois problemas na gestão de parâmetros que a classe
SqlHelperParameterCache resolve. Estes problemas são:
• Os parâmetros que um Stored Procedure necessite, podem ter de ser
identificados dinamicamente.
• O armazenamento e recuperação de parâmetros para posteriores execuções.
Não só é benéfico descobrir parâmetros em run time (ou seja dinamicamente),
porque permite simplificar em muito o código, como também é importante
armazenar os parâmetros usados.
Abaixo são descritos os objectivos da classe:
• Os parâmetros devem ser descobertos e mapeados pela sua posição, em run
time, com o mínimo de impacto possível na performance da aplicação.
• Deverá ser possível para o utilizador armazenar e recuperar arrays de
objectos SqlParameter.
• Quando é recuperado um array de objectos SqlParameter, as mudanças
feitas aos parâmetros desse array não deverão afectar os valores em cache.
• Os utilizadores deverão conseguir recuperar dinamicamente um array de
parâmetros para um determinado Stored Procedure. Os parâmetros neste
array deverão ter o nome correcto, bem como o tipo de dados, tamanho e
direcção.
André Coutinho
9
Microsoft .NET – Application Blocks
2.2.2.1. Os métodos da classe SqlHelperParameterCache
Esta classe do DAAB tem três métodos (públicos) que podem ser utilizados para
gerir parâmetros.
Estes métodos são os seguintes:
•
CacheParameterSet.
SqlParameter.
Usado para armazenar um array de objectos
public static void CacheParameterSet(
string connectionString,
string commandText,
params SqlParameter[] commandParameters)
•
GetCachedParameterSet.
Método utilizado para recuperar uma cópia de
um array de parâmetros anteriormente armazenado.
public static SqlParameter[] GetCachedParameterSet(
string connectionString,
string commandText)
•
GetSpParameterSet.
Este método pode ser usado para recuperar os
parâmetros apropriados para a execução de um determinado Stored
Procedure, questionando a base de dados uma vez e guardando os resultados
para futuros inquéritos à base de dados.
public static SqlParameter[] GetSpParameterSet(
string connectionString,
string spName)
2.2.2.2. Detalhes de implementação
Os arrays de parâmetros são armazenados numa tabela de hash privada.
Internamente os parâmetros recuperados da cache são copiados para que a
aplicação cliente possa mudar os valores dos parâmetros, sem afectar os valores
já guardados. A função privada CloneParameter, é usada para fazer isto.
Um array de objectos SqlParameter pode ser guardado em cache usando o
método CacheParameterSet. Este método cria uma chave, concatenando a
string de conexão e o comando SQL passado para o método. O método
GetSpParameterSet, que possui dois overloads, permite recuperar os
parâmetros para um Stored Procedure específico a partir da cache. Se os
parâmetros não estão em cache, serão recuperados a partir da base de dados,
usando uma função privada, DiscoverSpParameterSet, que por sua vez usa o
método DeriveParameter da classe CommandBuilder do ADO.NET, para
determinar quais os parâmetros adequados para o Stored Procedure em questão.
2.2.3. Usando o DAAB para executar comandos SQL
Para ilustrar as vantagens do uso do DAAB, abaixo está um exemplo do código
necessário para criar um objecto SqlDataReader ligado a um objecto DataGrid
sem usar o DAAB. Geralmente, para devolver um DataReader é necessário
André Coutinho
10
Microsoft .NET – Application Blocks
estabelecer uma conexão à base de dados, criar um comando SQL e executá-lo
sobre a base de dados. O objecto SqlDataReader resultante pode então ser
ligado ao objecto DataGrid:
//create the connection string
and sql to be executed
string strConnTxt =
"Server=(local);Database=Northwind;Integrated Security=True;";
string strSql = "select * from products where categoryid = 1";
//create and open the connection object
SqlConnection objConn = new SqlConnection(strConnTxt);
objConn.Open();
//Create the command object
SqlCommand objCmd = new SqlCommand(strSql, objConn);
objCmd.CommandType = CommandType.Text;
//databind the datagrid by calling the ExecuteReader() method
DataGrid1.DataSource = objCmd.ExecuteReader();
DataGrid1.DataBind();
//close the connection
objConn.Close();
Agora vejamos o mesmo exemplo, mas usando o método ExecuteReader da
classe SqlHelper:
//create the connection string and sql to be executed
string strSql = "select * from products where categoryid = 1";
string strConnTxt =
"Server=(local);Database=Northwind;Integrated Security=True;";
DataGrid4.DataSource = SqlHelper.ExecuteReader(strConnTxt,
CommandType.Text, strSql);
DataGrid4.DataBind();
Como se pode ver há consideravelmente menos código do que no exemplo
anterior. Para executar um comando SQL e obter um SqlDataReader, o método
ExecuteReader() requer apenas a string usada para estabelecer a conexão, o
tipo de comando a executar e o comando SQL que se quer executar.
2.2.4. Usando o DAAB para executar Stored Procedures
O método ExecuteReader tem vários overloads, permitindo executar Stored
Procedures e transacções. A seguir está um exemplo deste método para a
execução de um Stored Procedure:
DataGrid5.DataSource = SqlHelper.ExecuteReader(
strConnTxt,
CommandType.StoredProcedure,
"getProductsByCategory",
new SqlParameter(
André Coutinho
11
Microsoft .NET – Application Blocks
"@CategoryID", 1)
);
DataGrid5.DataBind()
Para executar um Stored Procedure e devolver um objecto SqlDataReader,
chama-se outra variante do método ExecuteReader(). Para chamar um Stored
Procedure, em vez de passar um comando SQL, passa-se o nome do Stored
Procedure e um objecto SqlParameter.
Veja-se mais uma vantagem em usar o DAAB. Neste exemplo, é devolvido um
DataSet contendo o resultado da execução de um Stored Procedure
(getProductsByCategory) que usa apenas um parâmetro (CategoryID).
Começa-se por ver novamente o código necessário para fazer isto sem usar o
DAAB.
// Open a connection to Northwind
SqlConnection objConn = new
SqlConnection("Server=(local);Database=Northwind;Integrated
Security=True;");
objConn.Open();
//Create the stored procedure command object
SqlCommand objCmd = new SqlCommand("getProductsByCategory",
objConn);
objCmd.CommandType = CommandType.StoredProcedure;
//create the parameter object for the stored procedure parameter
objCmd.Parameters.Add("@CategoryID", SqlDbType.Int);
objCmd.Parameters["@CategoryID"].Value = 1;
//create our DataAdapter and DataSet objects
SqlDataAdapter objDA = new SqlDataAdapter(objCmd);
DataSet objDS = new DataSet("Category_Results");
//fill the dataset
objDA.Fill(objDS);
//databind the datagrid
DataGrid1.DataSource = objDS;
DataGrid1.DataBind();
//close connection
objConn.Close();
A seguir apresenta-se o código necessário para fazer o mesmo mas utilizando o
método ExecuteDataSet da classe SqlHelper:
string strConn = "Server=(local);Database=Northwind;Integrated
Security=True;";
DataSet objDS = SqlHelper.ExecuteDataset(strConn,
CommandType.StoredProcedure,
"getProductsByCategory", new
SqlParameter("@CategoryID", 1) );
DataGrid2.DataSource = objDS;
DataGrid2.DataBind();
O código foi reduzido de 12 para 4 linhas, como se pode ver.
André Coutinho
12
Microsoft .NET – Application Blocks
Usar o DAAB vai aumentar a rapidez com que uma aplicação é desenvolvida,
porque encapsula o código necessário para executar Stored Procedures,
comandos SQL, especificar parâmetros e devolver objectos SqlDataReader,
DataSet e XmlReader. O facto de reduzir o código a escrever, leva a que
apareçam menos erros, também.
3. Logging Application Block
3.1. Introdução
3.1.1. Enterprise Instrumentation Framework
O Logging Application Block depende do Microsoft Enterprise Instrumentation
Framework (EIF) para funcionar; assim, é portanto muito importante,
compreender o EIF antes de passar ao Logging Application Block.
O EIF permite simplificar o desenvolvimento de aplicações instrumentadas.
Fornece gestão de eventos e serviços de tracing e diagnóstico para aplicações.
Para exemplificar como o EIF simplifica o logging, considere-se o aparecimento
de um evento numa aplicação. Esta acção usando o EIF requer apenas uma linha
de código, como se pode verificar abaixo:
EventSource.Application.Raise(adminMessageEvent);
O EIF permite que os programadores façam uma instrumentação consistente das
aplicações e expõe o funcionamento interno de uma aplicação, permitindo
monitorizar e diagnosticar falhas nas aplicações, por exemplo. Também é
possível configurar de que forma a informação publicada pelo EIF, será
encaminhada para os diferentes logs existentes.
As seguintes funcionalidades são fornecidas pelo EIF:
•
•
•
•
Um modelo unificado de programação.
Um esquema de eventos Windows Management Instrumentation (WMI),
estruturado que promove o trabalho em conjunto das equipas de
desenvolvimento, teste e operações, para o suporte à aplicação.
Uma camada de configuração scriptable, que permite configurar como os
eventos surgem numa aplicação e como são registados em log.
Suporte para eventos e logging, usando WMI, Windows Event Log, e
Windows Event Tracing.
A figura seguinte mostra a arquitectura EIF:
André Coutinho
13
Microsoft .NET – Application Blocks
Figura 2: A arquitectura EIF
A arquitectura EIF consiste de cinco elementos principais:
• Event schema. O EIF fornece o esquema dos eventos que podem surgir
numa aplicação. Este Event schema também descreve os dados que cada
tipo de evento pode conter.
• Event sources. Qualquer aplicação que interaja com o EIF vai necessitar
de um ou mais objectos para lançar/gerar os eventos. Estes objectos são
conhecidos como Event Sources.
• Instrumentation API. O EIF tem um API unificado que providencia
informação sobre a instrumentação das tecnologias existentes. Os
eventos que vão surgindo na aplicação são passados ao Instrumentation
API do EIF, que depois trata dos pormenores da comunicação com o
resto da arquitectura EIF. Isto vai permitir a modificação de como os
eventos são reportados sem alterar a aplicação que os gerou.
• Event sinks. O EIF possui três repositórios de eventos, o WMI, o
Windows Event Log, e o Windows Trace Log. Estes repositórios
recebem os eventos gerados pela aplicação e garantem a persistência
destes no log apropriado.
• XML Configuration file. O EIF usa um ficheiro XML para configurar
como os eventos são encaminhados para o Event sink correcto. Estes
ficheiros XML podem ser usados para configurar o registo de eventos e
da sua proveniência, além de configurar qual o Event sink que os vai
receber.
3.2. Logging
O Logging application block fornece então, uma extensão à arquitectura EIF,
facilitando a implementação dos cenários mais comuns de logging. Estes
cenários são:
André Coutinho
14
Microsoft .NET – Application Blocks
•
•
•
•
•
•
•
•
•
Formatação da informação dos eventos.
Configuração dos níveis de log.
Logging assíncrono.
Logging de confiança (reliable logging).
Logging centralizado.
Tracing para serviços Web.
Informação sobre os eventos publicados.
Metering/Medição para serviços Web.
Usar o publisher da arquitectura EIF para o EMAB.
Abaixo está a arquitectura do Logging Application Block, onde se vê como este
application block extende o EIF.
Figura 3: Arquitectura do Logging Application Block
Seguidamente encontram-se exemplos de alguns dos cenários mais
significativos de logging já apresentados.
3.2.1. Formatação da informação dos eventos
O exemplo seguinte ilustra a formatação da informação de eventos.
É possível ver duas formas de formatar estas informações.
Na primeira especifica-se o Xslt (Extensible Stylesheet Language
Transformations) utilizado na formatação, como parâmetro para o sink usado.
Na segunda forma é também especificado o Xslt usado, mas como propriedade
do evento a ser publicado.
Em ambos os casos é importante referir que o parâmetro enableFormatting
do ficheiro EnterpriseInstrumentation.config, terá de estar a true.
André Coutinho
15
Microsoft .NET – Application Blocks
Nos exemplos abaixo é usado o Windows Event Log para armazenar o evento
formatado.
using System;
using System.IO;
using Microsoft.EnterpriseInstrumentation;
using Microsoft.ApplicationBlocks.Logging.Schema;
namespace
Microsoft.ApplicationBlocks.Logging.Samples.Formatting
{
public class FormattingSample
{
private String formatterName;
/// <summary>
/// Default constructor.
/// </summary>
public FormattingSample()
{
formatterName = "eventSpecifiedXslt";
}
/// <summary>
/// Method responsible for publishing event by
specifying the
/// Xslt on the event as a property.
/// </summary>
public void FormatWithEventXsltSpecified()
{
AuditMessageEvent publishedEvent = new
AuditMessageEvent();
publishedEvent.FormatterName = formatterName;
publishedEvent.EventPublishLogLevel = (int)
LogLevel.Always;
EventSource.Application.Raise(publishedEvent);
}
/// <summary>
/// Method responsible for publishing the event
information
/// with the formatting done using the Xslt specified
on the
/// event sink.
/// </summary>
public void FormatWithSinkXsltSpecified()
{
AuditMessageEvent publishedEvent = new
AuditMessageEvent();
publishedEvent.EventPublishLogLevel = (int)
LogLevel.Always;
EventSource.Application.Raise(publishedEvent);
}
///
///
///
///
///
André Coutinho
<summary>
The main entry point for the sample.
</summary>
<param name="args">
Arguments passed to the sample in this case
16
Microsoft .NET – Application Blocks
/// there are no arguments.
/// </param>
public static void Main(string[] args)
{
FormattingSample sample = new
FormattingSample();
sample.FormatWithEventXsltSpecified();
sample.FormatWithSinkXsltSpecified();
}
}
}
3.2.2. Configuração dos níveis de log
Este exemplo ilustra como os níveis de log podem ser configurados para
conrolar os eventos que são publicados, e os que não são.
Há três conceitos importantes a descrever, de modo a compreender como os
vários níveis de log podem ser usados.
Este conceitos são os seguintes:
• EventPublishLogLevel. Este propriedade (no evento a publicar)
indica o nível de log a partir do qual o evento pode ser publicado.
• ApplicationLogLevel. Esta propriedade (no evento a publicar)
permite saber qual o nível de log para o qual a aplicação está
configurada. Isto é obtido a partir do Application config ou do Web
config.
• Supported Log Levels. Os vários níveis de log possíveis:
o Logging Level: None (nenhum).
Descrição: Nenhum tipo de logging é feito neste nível.
Valor (inteiro) associado: 0.
o Logging Level: Always (sempre).
Descrição: Este é o nível de logging por defeito para todos os
eventos em que o logging level não foi especificado.
Eventos de auditoria (audit) ou de metering, podem especificar
o uso deste nível.
Valor (inteiro) associado: 1.
o Logging Level: Error (erro).
Descrição: Neste nível todos os erros e excepções da aplicação
são armazenados em log.
Valor (inteiro) associado: 2.
o Logging Level: Warning (aviso).
Descrição: Este nível pode ser utilizado para troubleshooting,
para identificação de problemas de funcionamento na aplicação.
Valor (inteiro) associado: 3.
o Logging Level: Informational (informativo).
Descrição: As mensagens que fornecem informação adicional
sobre o fluxo de controlo são armazenadas em log como
informação adicional que poderá ser útil. Isto poder ser
utilizado no arranque do sistema, por exemplo, apenas para
André Coutinho
17
Microsoft .NET – Application Blocks
mostrar informação possivelmente útil para confirmar que o
sistema arrancou com as configurações correctas.
Valor (inteiro) associado: 4.
o Logging Level: Debug.
Descrição: Neste nível todas as mensagens são armazenados em
log. Este nível só deve ser utilizado para o debugging de
aplicações.
Valor (inteiro) associado: 5.
Se a condição applicationLogLevel>=eventPublishLogLevel for satisfeita
então o evento será publicado, caso contrário isso não ocorrerá.
using System;
using Microsoft.ApplicationBlocks.Logging.Schema;
using Microsoft.EnterpriseInstrumentation;
namespace Microsoft.ApplicationBlocks.Logging.Samples
{
class LogLevelSample
{
/// <summary>
/// Default constructor.
/// </summary>
public LogLevelSample()
{
}
/// <summary>
/// Method responsible for Publishing Events.
/// </summary>
public void PublishEvents()
{
// This event has the Event Publish Log Level
set at
// Always and the Application Log Level is set
at
// Error. In this case the event will be
published.
AdminMessageEvent adminMessageEvent = new
AdminMessageEvent();
adminMessageEvent.Message = "Admin Message
Event to be published.";
adminMessageEvent.EventPublishLogLevel =
(int)LogLevel.Always;
EventSource.Application.Raise(adminMessageEvent
);
// This event has the Event Publish Log Level
set at
// Informational and the Application Log Level
is set at
// Error. In this case the event will not be
published
André Coutinho
18
Microsoft .NET – Application Blocks
// as the event publish log level is higher
that application
// log level.
// You can change the application log level
parameter to
//
"informational" and this event will be
published.
AuditOperationEvent auditOperationEvent = new
AuditOperationEvent();
auditOperationEvent.Operation = "ApproveOrder";
auditOperationEvent.Reason = "The user is
authorized to approve order.";
auditOperationEvent.EventPublishLogLevel =
(int)LogLevel.Informational;
EventSource.Application.Raise(auditOperationEve
nt);
// This event has the Event Publish Log Level
set at
// Error and the Application Log Level is set
at
// Error. In this case the event will be
published as
// the log levels match.
ErrorMessageEvent errorMessageEvent = new
ErrorMessageEvent();
errorMessageEvent.Severity = 2;
errorMessageEvent.Message =
"ErrorMessageEvent";
errorMessageEvent.EventPublishLogLevel =
(int)LogLevel.Error;
EventSource.Application.Raise(errorMessageEvent
);
}
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main(string[] args)
{
LogLevelSample sample = new LogLevelSample();
sample.PublishEvents();
}
}
}
3.2.3. EnterpriseInstrumentation.config
A seguir apresenta-se um pequeno excerto do ficheiro de configuração
EnterpriseInstrumentation.config, onde é possível ver o parâmetro
enableFormatting a true, usado na formatação da informação dos eventos.
<eventSink name="logSink" description="Outputs events to the
Windows Event Log."
type="Microsoft.ApplicationBlocks.Logging.EventSinks.LogEventSi
nk, Microsoft.ApplicationBlocks.Logging.EventSinks,
André Coutinho
19
Microsoft .NET – Application Blocks
Version=1.0.0.0, Culture=neutral,
PublicKeyToken=3010be203f86630a">
<parameter name="entryTypeFieldName"
value="EventLogEntryTypeID" />
<parameter name="defaultEntryType" value="Information" />
<parameter name="enableFormatting" value="false" />
<parameter name="machineName" value="." />
<parameter name="formatterName" value="logSinkXslt" />
</eventSink>
André Coutinho
20
Microsoft .NET – Application Blocks
4. Exception Management Application Block
4.1. Introdução
O Exception Management Application Block (EMAB) é um componente
disponível para a Framework .NET e fornece uma extensão simples mas flexível
para as excepções de logging. É possível também, a criação de componentes
customizados para tratamento das excepções de logging.
Este application block pode ser usado como mais um building block numa
aplicação .NET. Utilizá-lo ajuda a reduzir a quantidade de código a escrever,
testar e manter para o tratamento de erros. Como resultado a aplicação ficará
mais robusta e mais facilmente depurável.
Especificamente o EMAB ajuda a:
• Gerir excepções de forma eficiente e consistente.
• Isolar o código que gere as excepções do resto do código.
• Gerir as excepções de log com um mínimo de código.
Este application block ainda:
• Garante que os detalhes das excepções são capturados com um grupo de
informação, consistente, sobre o contexto. Esta consistência é fornecida
por uma classe que assegura que todas as excepções fornecem apenas um
nível mínimo de informação contextual. É possível criar classes
customizadas apartir desta.
• É flexível porque permite configurar as suas funcionalidades através de
um simples ficheiro de configuração .NET XML.
• Suporta um mecanismo extensível de lançamento de excepções.
A Figura seguinte mostra o funcionamento do EMAB.
Figura 4: Como funciona o EMAB
André Coutinho
21
Microsoft .NET – Application Blocks
4.2. Classes do EMAB
Neste sub capítulo são apresentadas as classes e interfaces mais importantes,
deste application block.
A Figura seguinte ilustra como estão organizados estes componentes dentro do
EMAB.
Figura 5: A arquitectura do EMAB
4.2.1. Classe BaseApplicationException
O primeiro passo para implementar uma gestão de excepções consistente, está
em assegurar que a informação sobre o contexto é capturada para cada excepção
que surge numa determinada aplicação. Para facilitar esta tarefa existe a classe
BaseApplicationException.
Esta classe é a base para garantir que as excepções apenas fornecem o nível
mínimo de informação contextual. É possível criar classes customizadas apartir
desta.
Existem dois problemas principais que esta classe resolve. Estes problemas são:
• As excepções devem automaticamente capturar a informação mais
importante sobre o ambiente.
• Deverá existir uma estrutura lógica para a hierarquia de excepções de
uma determinada aplicação.
Os objectivos da classe BaseApplicationException são:
• Ser uma classe base para a gestão de excepções, a partir da qual todas as
classes de excepção da aplicação deverão derivar.
• Conter apenas informação pertinente para todas as excepções de uma
aplicação.
André Coutinho
22
Microsoft .NET – Application Blocks
•
•
Implementar as funcionalidades base de captura de informação
contextual, que serão herdadas pelas classes customizadas.
Deve ser possível aceder à classe remotamente.
Os métodos mais importantes desta classe são os seguintes:
• GetObjectData. Preenche um objecto SerializationInfo com os
dados da excepção necessários para a serialization.
public override void GetObjectData(
SerializationInfo info,
StreamingContext context);
•
InitializeEnvironmentInformation.
Função de inicialização que
reune informação de forma segura.
private void InitializeEnvironmentInformation()
4.2.2. Classe ExceptionManagerSectionHandler
Esta classe é utilizada para devolver os parâmetros de gestão de excepções, do
ficheiro de configuração da aplicação.
4.2.3. Classe ExceptionManager
Para gerir o logging e o tratamento de excepções, consistemente, o EMAB inclui
esta classe.
A classe ExceptionManager foi criada para solucionar as seguintes questões:
• Os programadores necessitam de uma forma mais fácil para gerir
excepções imprevistas, com um mínimo de código.
• A solução deve ser flexível de modo a que permita modificações “on the
fly”, sem ser preciso recodificar, recompilar ou parar a aplicação.
• A solução deve ser extensível.
• A solução deve gerir as excepções que possam ocorrer durante o
processo de publicação de uma excepção.
Os objectivos da classe ExceptionManager são:
• O componente deve necessitar de um mínimo de código criado pelo
programador para se integrar numa aplicação.
• O comportamento deve ser baseado em parâmetros de configuração que
possam ser modificados sem recodificação, recompilação, e no caso de
aplicações ASP.NET, sem recomeçar a aplicação.
• As excepções internas lançadas por custom publishers devem ser
capturadas e registadas em log.
• Providenciar uma implementação própria dos objectos XmlSerializer.
Os métodos mais importantes desta classe são os seguintes:
• Publish. Publica uma excepção.
• SerizalizeToXml. Passa um objecto Exception para XML.
André Coutinho
23
Microsoft .NET – Application Blocks
4.2.4. Classe ExceptionManagerInstaller
Esta classe é usada quando o EMAB é instalado e cria os dois Event Sources
usados pelo publisher por defeito quando é necessário escrever no Windows
Event Log.
4.2.5. Classe Default Publisher
Esta classe implementa a interface IExceptionPublisher e fornece
funcionalidades de escrita para o registo de detalhes de excepções no Windows
Event Log. Na ausência de classes customizadas, baseadas nesta, é esta classe a
usada por defeito.
É possível configurar o publisher por defeito, criando um elemento <publisher>
no ficheiro de configuração. Isto permite definir qual o Event Source e o nome
do log a usar.
A seguir são apresentadas as interfaces IExceptionPublisher e
IExceptionXmlPublisher.
4.2.6. A interface IExceptionPublisher
Esta interface possui um único método, chamado Publish (apresentado
anteriormente), que permite que os publishers recebam detalhes sobre as
excepções a publicar (publishing).
public interface IExceptionPublisher
4.2.6.1. Métodos da interface IExceptionPublisher
•
Publish.
Fornece detalhes sobre as excepções relativas às excepções a
serem publicadas.
void Publish(
Exception exception,
NameValueCollection additionalInfo,
NameValueCollection configSettings);
O exemplo seguinte mostra uma implementação, simples, desta interface.
using
using
using
using
using
System;
Microsoft.ApplicationBlocks.ExceptionManagement;
System.Text;
System.IO;
System.Collections.Specialized;
namespace CustomExceptionPublishers
{
public class CustomPublisher : IExceptionPublisher
{
private string m_LogName = @"C:\TestExceptionLog.txt";
void IExceptionPublisher.Publish( Exception exception,
NameValueCollection additionalInfo,
NameValueCollection configSettings)
André Coutinho
24
Microsoft .NET – Application Blocks
{
// Load Config values if they are provided.
if (configSettings != null)
{
if (configSettings["fileName"] != null &&
configSettings["fileName"].Length > 0)
m_LogName = configSettings["fileName"];
}
// Create StringBuilder to maintain publishing information.
StringBuilder strInfo = new StringBuilder();
// Record the contents of the additionalInfo collection.
if (additionalInfo != null)
{
// Record General information.
strInfo.AppendFormat("------- Exception Log Entry ------ {0}", Environment.NewLine);
strInfo.AppendFormat("{0}General Information{0}",
Environment.NewLine);
strInfo.AppendFormat("{0}Additional Info:",
Environment.NewLine);
foreach (string i in additionalInfo)
{
strInfo.AppendFormat("{0}{1}: {2}",
Environment.NewLine, i,
additionalInfo.Get(i));
}
}
// Append the exception text
if (exception != null)
{
strInfo.AppendFormat("{0}Exception Information {1}",
Environment.NewLine, exception.Message.ToString());
}
else
{
strInfo.AppendFormat("{0}{0}No Exception.{0}",
Environment.NewLine);
}
// Write the entry to the event log.
FileStream fs =
File.Open(m_LogName,FileMode.Append,FileAccess.Write);
StreamWriter sw = new StreamWriter(fs);
sw.Write(strInfo.ToString());
sw.Close();
fs.Close();
}
}
}
4.2.7. A interface IExceptionXmlPublisher
André Coutinho
25
Microsoft .NET – Application Blocks
A interface IExceptionXmlPublisher tal como o IExceptionPublisher
também só tem um método Publish, neste caso para receber documentos XML
contendo os detalhes das excepções.
public interface IExceptionXmlPublisher
4.2.7.1. Métodos de IExceptionXmlPublisher
•
Publish.
Fornece documentos XML que contêm os detalhes das
excepções a serem publicadas.
void Publish(
XmlDocument exceptionInfo,
NameValueCollection configSettings);
O exemplo seguinte mostra uma possível implementação desta interface.
using
using
using
using
using
using
System;
Microsoft.ApplicationBlocks.ExceptionManagement;
System.Xml;
System.Text;
System.IO;
System.Collections.Specialized;
namespace CustomXMLExceptionPublishers
{
public class CustomXMLPublisher : IExceptionXmlPublisher
{
void IExceptionXmlPublisher.Publish(XmlDocument
ExceptionInfo,
NameValueCollection
ConfigSettings)
{
string filename = @"C:\TestExceptionLog.xml";
if (ConfigSettings != null)
{
if (ConfigSettings["fileName"] != null &&
ConfigSettings["fileName"].Length > 0)
{
filename = ConfigSettings["fileName"];
}
}
XmlDocument logDoc = new XmlDocument();
if (File.Exists(filename) == false)
// create the log file
{
FileStream f = File.Open(filename, FileMode.Create,
FileAccess.Write);
StreamWriter sw = new StreamWriter(f);
sw.Write("<?xml
version='1.0'?><ExceptionLog><ExceptionLog>");
sw.Close();
f.Close();
}
// Add this exception to the existing XML document
logDoc.Load(filename);
André Coutinho
26
Microsoft .NET – Application Blocks
XmlNode xNode =
logDoc.ImportNode(ExceptionInfo.DocumentElement, true);
logDoc.DocumentElement.AppendChild(xNode);
File.Delete(filename);
logDoc.Save(filename);
}
}
}
André Coutinho
27
Microsoft .NET – Application Blocks
5. Configuration Management Application Block
5.1. Introdução
Todas as aplicações requerem que de alguma forma se configure a informação
que adquirem, gerem e armazenam. Onde e como armazenar a informação de
configuração de uma aplicação, sempre foi um problema para os programadores.
As soluções mais comuns são:
• Ficheiros de configuração XML ou .ini (windows)
• Os registos do window
• Base de dados (por exemplo Microsoft SQL Server)
Cada uma destas alternativas tem pontos fracos e pontos fortes, nenhuma
solução é perfeita para um determinada situação.
Mesmo numa determinada aplicação, poderá ser preciso adoptar mais do que
uma forma de configuração da informação que a aplicação armazena. A
necessidade de uma aplicação correr em ambientes diferentes também poderá
fazer com que seja preciso implementar múltiplas soluções de configuração.
Outros factores são a capacidade de escrever (não só de ler) dados de
configuração, de segurança e integridade, e o impacto na performance da
aplicação que a solução de configuração provoca.
O Configuration Management application block (CMAB) atende a estes factores
e proporciona uma solução simples e flexível para a configuração de dados e
aplicações.
5.2. Elementos constituintes do CMAB
A Figura que se encontra abaixo mostra a estrutura do CMAB, a relação entre os
elementos chaves que serão descritos brevemente e os pontos de interacção com
entidades externas.
Figura 6: Relação entre os elementos do CMAB (arquitectura)
André Coutinho
28
Microsoft .NET – Application Blocks
Os elementos chave ou principais do CMAB são seis:
• Configuration sections. Uma configuration section é a principal unidade
de dados processadas pelo CMAB. Representa um bloco de dados de
configuração que é lido ou escrito numa única operação. O CMAB
identifica cada uma destas secções usando um nome. É necessário
declarar cada configuration section usada pela aplicação, nos parâmetros
de configuração do CMAB. A declaração de um configuration section
define qual CSH (Configuration Section Handler), CSP (Configuration
Section Providers) e DPP (Data Protection Provider), o CMAB usará
quando ler ou escrever essa mesma configuration section, e especifica se
o caching está activado para esse configuration section.
• A classe ConfigurationManager. Esta classe é o elemento central do
CMAB, e a única classe necessária para aceder a configuration sections.
A classe ConfigurationManager encapsula a complexidade associada
com a escrita/leitura de dados de configuração, e é responsável por:
o Fazer o parsing do ficheiro de configuração da aplicação e
instanciar as CSPs e DPPs para suportar cada configuration
section declarada.
o Fornecer a interface através da qual o código da aplicação vai ler
e escrever dados da configuration section.
o Gerir o fluxo interno de dados entre a aplicação e o CSP,
incluindo a instanciação do CSH correcto.
o Estabelecimento e gestão dos serviços de caching.
• Serviços de caching de dados. O CMAB providencia caching de dados
baseado em memória, para reduzir o overhead associado às leituras
repetidas de dados de configuração do sítio onde estão armazenados,
especialmente se estão distribuídos numa rede. Se o caching for activado
para uma configuration section, sempre que a classe
ConfigurationManager precisar de ler a configuration section, tentará
primeiro verificar se a configuration section está em cache.
• Configuration Section Handlers (CSH). Há dois tipos de CSH. CSH de
leitura e CSH de leitura/escrita. A CSH de leitura implementa a interface
IConfigurationSectionHandler e transforma um nó XmlNode na sua
estrutura correcta. A CSH de leitura/escrita implementa o interface
IConfigurationSectionHandlerWriter
(que
extende
o
IConfigurationSectionHandler) e transforma os dados em ambas as
direcções.
• Configuration Storage Provider (CSP). Um CSP é usado pelo CMAB
para ler/escrever dados de configuração da aplicação de/para um
armazém de dados específico, por exemplo, Microsoft SQL Server, ou
ficheiros XML. Existem dois tipos de CSP. Um só de leitura e outro de
leitura/escrita.
O
primeiro
implementa
a
interface
IConfigurationStorageReader e só é capaz de ler uma configuration
section apartir do armazém de dados. O segundo implementa a interface
IConfigurationStorageWriter
(que
extende
a
IConfigurationStorageReader) e pode ler e escrever configuration
sections.
André Coutinho
29
Microsoft .NET – Application Blocks
•
Data Protection Provider (DPP). Um DPP fornece serviços de
encriptação e MAC (Message Authentication Code), que podem ser
usados para melhorar a segurança e integridade das configuration
sections guardadas. Se se configurar um CSP para usar um DPP, o CSP
chama o DPP para fazer a encriptação e assinar os dados antes de os
armazenar e desencripta os dados antes de os passar para a aplicação. O
DPP implementa a interface IDataProtection.
5.3. Objectivos
Os pontos seguintes são os objectivos do CMAB:
• O CMAB deve fornecer um interface standard para a leitura e escrita de
dados de configuração, fácil de usar e independente do armazenamento
físico dos dados.
• Este application block tem que permitir que os programadores trabalhem
com dados de configuração usando a estrutura de dados mais
apropriadas.
• Deve ser fácilmente configurável usando ficheiros de configuração
standard do .NET.
• O CMAB deve suportar caching opcional dos dados de configuração
independentemente do armazenamento dos dados e ser transparente para
a aplicação que está a usar o CMAB.
• Suportar encriptação opcional dos dados de configuração da aplicação
para melhorar a segurança dos dados. O uso de encriptação deve ser
controlado pelos parâmetros de configuração, independentemente do
armazenamento dos dados, e ser transparente para a aplicação que está a
usar o CMAB.
• Suportar a assinatura opcional dos dados de configuração para melhorar
a integridade dos dados. O uso das assinaturas deve ser controlado pelos
parâmetros de configuração, e ser transparente para a aplicação que está
a usar o CMAB.
• O CMAB deve fornecer funcionalidades que suportem a maioria das
situações de dados de configuração. Isto inclui suporte dos pares
nome/valor, caching de dados baseado em memória, os armazéns de
dados mais comuns,e protecção de dados.
• Deve também ser extensível, permitindo aos programadores, adicionar
suporte a diferentes armazéns de dados, diferentes métodos de
encriptação e algoritmos de assinaturas de dados.
5.4. Vantagens
O CMAB traz as seguintes vantagens:
Simplicidade
O CMAB apresenta uma interface simples e consistente que suporta a leitura e
escrita de informação de configuração para a aplicação. Usando o CMAB é
muito simples devolver por exemplo a string de conexão à base de dados, que
temos configurada, ou ainda escrever uma nova configuração.
André Coutinho
30
Microsoft .NET – Application Blocks
string conString =
(string)ConfigurationManager.Items["connection_string
"];
Escrever configurações é também muito fácil, como se vê abaixo.
ConfigurationManager.Items["connection_string"] =
"Some String";
Um modelos de dados flexível
O uso dos pares nome/valor é uma metodologia comum para armazenar dados
de configuração. No entanto o CMAB não usa este método. É possível com este
application block ler/escrever parâmetros de configuração, ou grupos de
elementos de configuração chamados configuration sections.
O CMAB é também extensível e pode suportar dados de configuração de
qualquer tipo, fazendo uso de um CSH (Configuration Section Handler)
customizado. Esta flexibilidade permite escolher qual a melhor representação
para os dados de configuração, e também usar os métodos standard do CMAB
para armazenar estes dados.
Independência do local de armazenamento
No CMAB a capacidade de ler/escrever dados de configuração é transparente
em relação à forma como estes estão armazenados fisicamente.
Um CSP (Configuration Storage Provider) implementa as funcionalidades
necessárias para aceder ao meio físico de armazenamento, e o mapeamento entre
as configuration sections e o CSP é definido no ficheiro de configuração da
aplicação.
Uma vez que usando o CMAB estão a ser utilizados interfaces standard para ler
e escrever dados de configuração independentemente do local e forma de
armazenamento usados, é possível mudar o local destes dados de configuração
sem alterar do código já escrito.
O CMAB inclui também CSPs que suportam armazenamento de dados de
configuração em ficheiros XML (incluindo os ficheiros .config standard do
.NET), Windows Registry e SQL Server.
É possível extender o CMAB com CSPs customizados para suportar outros tipos
de armazenamento de dados.
Integridade e segurança dos dados
Os dados de configuração de uma aplicação incluem muitas vezes informações
sensíveis, tais como strings de conexão e localizações de serviços.
O CMAB providencia serviços de protecção de dados sob a forma de um DPP
(Data Protection Provider) para minimizar os acessos não autorizados a dados de
configuração sensíveis. Um DPP fornece o MAC (Message Authentication
Code) e funcionalidades de encriptação através de um interface bem definido
que pode ser configurado para uso conjunto com um CSP.
Este application block fornece duas implementações do DPP. Ambas geram,
MACs SHA1 e encriptam os dados usando o algoritmo de encriptação 3-DES. A
principal diferença entre as duas implementações, é que uma usa DPAPI
André Coutinho
31
Microsoft .NET – Application Blocks
(Windows Data Protection API) para simplificar a gestão de chaves, enquanto
que a outra requer que a gestão das chaves encriptadas seja feita usando classes
para o efeito.
É possível extender o CMAB com implementações customizadas do DPP para
suportar outros MACs e modos de encriptação.
Performance
O impacto causado pelo acesso a dados de configuração, na performance da
aplicação, depende do local onde os dados estão armazenados e do método de
acesso. Para assegurar que a descida de performance é mínima, o CMAB tem
uma opção que permite usar serviços de caching baseados em memória que
podem ser activados para qualquer CSP. O serviço de caching suporta
parâmetros de Time-to-live para os dados em cache e quando indicado pelo CSP
suporta também a capacidade de refrescar os dados em cache, se estes foram
alterados.
Extensibilidade
O CMAB é extensível. As suas interfaces permitem desenvolver CSPs, DPPs e
CSHs customizados. Como foi dito anteriormente também é possível mudar a
forma ou tipo de armazenamento físico dos dados de configuração, sendo isto
transparente para o CMAB, bastando para tal alterar os ficheiros de configuração
da aplicação.
5.5. Porquê a criação do CMAB
O uso de ficheiros de configuração .NET apenas fornece acesso de leitura aos
dados de configuração armazenados em ficheiros XML, o que em muitas
aplicações é muito restritivo.
Muitas vezes os programadores têm de implantar soluções específicas para o
armazenamento de dados de configuração, para cada aplicação. Uma vez que
são consideradas secundárias, estas soluções são implementadas com alguma
negligência, e funcionalidades como a segurança e integridade dos dados são
deixadas para segundo plano. Além disto, estas soluções criam dependências
entre a aplicação e o armazenamento dos dados, afectando a instalação da
aplicação.
O código seguinte exemplifica como guardar a configuration section por defeito.
Hashtable configData;
// Write the default configuration section (must be Hashtablebased)
ConfigurationManager.Write(configData);
O exemplo abaixo mostra como se podem ler e escrever items
individualmente na Configuration Section por defeito.
// Write a data item to the default configuration section
ConfigurationManager.Items["Size"] = "large";
// Read a data item from the default configuration section
André Coutinho
32
Microsoft .NET – Application Blocks
string size = (string)ConfigurationManager.Items["Size"];
5.6. Criação de um CSP de leitura
Para um CSP (Configuration Storage Provider) de leitura, deve ser criada uma
classe que implemente a interface IConfigurationStorageReader, como se vê
abaixo.
[ComVisible(false)]
public interface IConfigurationStorageReader
{
void Init( string sectionName, ListDictionary
configStorageParameters, IDataProtection dataProtection );
XmlNode Read();
event ConfigurationChanged ConfigChanges;
bool Initialized{ get; }
}
5.7. Criação de um CSP de leitura/escrita
Se houver necessidade de usar este application block para fazer administração,
será necessário criar um CSP customizado. Se já existir um CSP só de leitura
(ver exemplo anterior), a forma mais fácil de criar a versão de leitura/escrita será
criar uma segunda classe que acrescente estas funcionalidades às de leitura.
Todas as implementações de CSPs fornecidas com o CMAB possuem as
funcionalidades
de
leitura/escrita.
A
interface
usada
é
a
IConfigurationStorageWriter
que
extende
a
IConfigurationStorageReader.
[ComVisible(false)]
public interface IConfigurationStorageWriter :
IConfigurationStorageReader
{
void Write( XmlNode value );
}
5.8. Criação de um DPP
Existem duas abordagens para a implementação de um DPP. É possível
inicializar e instanciar tudo com o método Init. Isto significa não só a criação
dos objectos para encriptação e hashing, como também a obtenção das várias
chave e armazenamento das mesmas. Esta abordagem não é segura, uma vez que
as chaves (secretas) estão na memória durante o tempo de vida do CMAB.
A outra abordagem passa pela retenção dos detalhes do que será criado e onde
obter a chaves. No entanto, a obtenção das chaves e instanciação de objectos
criptográficos é feita de cada vez que um dos métodos Encrypt, Decrypt ou
ComputeHash, são chamados. Esta abordagem é mais segura mas diminui a
performance.
O CMAB tem implementações destas duas abordagens, a partir das quais é
possível criar implementações customizadas, conforme as necessidades.
André Coutinho
33
Microsoft .NET – Application Blocks
[ComVisible(false)]
public interface IDataProtection : IDisposable
{
void Init( ListDictionary dataProtectionParameters );
byte[] Encrypt( byte[] plainText );
byte[] Decrypt( byte[] cipherText );
byte[] ComputeHash( byte[] plainText );
}
André Coutinho
34
Microsoft .NET – Application Blocks
6. Updater Application Block
6.1. Introdução
Em organizações de média a grande dimensão, é comum necessitar das
actualizações da última versão de uma determinada aplicação, quer seja dos seus
executáveis, ou bibliotecas, quer seja de outros ficheiros (ex., configuração).
Idealmente, os administradores da rede preferem instalar os ficheiros de update
de uma aplicação apenas uma vez, para um servidor central, e seguidamente ter
os ficheiros replicados automaticamente para cada desktop existente na rede.
O UAB é um componente disponível para a Framework .NET que fornece uma
solução do tipo “pull model” que automaticamente faz o download dos updates
de determinada aplicação a partir de um sítio centralizado.
Este application block foi desenhado para organizações que necessitam de
aplicações que combinem as funcionalidades dos Windows Forms, com a
flexibilidade e facilidade de gestão das aplicações Web, e que não possuam as
infraestruturas necessárias à implementação de uma solução do tipo “push
model”, como o MS Systems Management Server. Usando o UAB para fazer o
download de updates para as aplicações, é possível ultrapassar a limitação
imposta pelos downloads de updates para as aplicações baseadas em Windows
Forms. Para além disso, utilizando o UAB também se mantém o controlo e
segurança sobre o processo de update da aplicação.
Figura 7: Mantendo aplicações actualizada com o UAB
O UAB é um componente .NET usado para detectar, validar, e fazer download
de updates para aplicações instaladas num sítio centralizado. Fazendo uso do
UAB, é possível manter aplicações actualizadas com o mínimo (ou até mesmo
sem) intervenção do utilizador. Ainda é possível extender o uso do UAB e criar
classes customizadas para fazer download e validar ficheiros, para executar
André Coutinho
35
Microsoft .NET – Application Blocks
tarefas de configuração após instalação, e também para controlar o processo de
update.
Especificamente, o UAB permite:
• Implementar uma solução de update do tipo “pull” para aplicações .NET.
• Usar técnicas de validação criptográfica para verificar a autenticidade dos
updates das aplicações, antes de estes serem aplicados.
• Executar tarefas de configuração pós-instalação, sem intervenção do
utilizador.
• Escrever aplicações que fazem update automaticamente.
6.2. Arquitectura do UAB
Figura 8: Arquitectura do UAB
A Figura acima mostra a arquitectura do UAB:
1. Geração de um ficheiro de manifest descrevendo os updates disponíveis
para cada aplicação
2. Uma aplicação controller é usada para começar e parar o update da
aplicação
3. O updater da aplicação inicia periodicamente o processo de update.
4. O updater da aplicação carrega o validator apropriado e valida os
ficheiros descarregados
5. Se um post processor foi especificado no ficheiro manifest, o updater da
aplicação carrega-o e executa-o
Nos parágrafos seguintes, explica-se um pouco mais detalhe cada um dos passos
anteriores.
André Coutinho
36
Microsoft .NET – Application Blocks
1 – No servidor, usando a aplicação Manifest Utility, gera-se um ficheiro
manifest para o update de cada aplicação. Faz uma lista de todos os ficheiros
incluídos no update, uma assinatura de validade para cada ficheiro (incluindo-se
a si próprio) e opcionalmente um post processor para execução no cliente para
depois do download e validação dos ficheiros.
2 – uma aplicação controller é usada para começar e parar o update da
aplicação. O ficheiro de configuração da aplicação associado ao controller é
utilizado para determinar três parâmetros fundamentais de configuração para o
processo de update:
• As aplicações a serem actualizadas, incluindo o local do ficheiro de
configuração e o ficheiro de manifest a ser usado para determinar a
última versão da aplicação no cliente e no servidor.
Existem três fontes de informação indispensáveis ao updater de uma
aplicação:
o O ficheiro de configuração do updater da aplicação. É um
ficheiro que contém informação sobre o intervalo de polling, o
local de log, downloader e validator a serem usados pelo updater,
também inclui detalhes sobre a aplicação a ser actualizada. Para
cada aplicação o ficheiro inclui parâmetros para o cliente e para o
servidor.
o Ficheiros de configuração do cliente. Estes ficheiros incluem
informação necessária para identificar a versão correntemente
instalada e o local do executável a ser lançado quando um
utilizador lança o application launcher.
o Manisfests. Cada vez que um update para uma determinada
aplicação é posto num servidor, deve ser criado um ficheiro
manifest para esse mesmo update. Este ficheiro contém
informação sobre a versão do update, sobre os ficheiros incluídos
no update, e sobre qualquer post processor a ser executado. Os
ficheiros manifest também incluem assinaturas de validação para
cada ficheiro e para os próprios ficheiros manifest, permitindo
que o updater da aplicação valide o update e implemente
protecção contra updates não autorizados ou ataques do tipo
“man in the middle”.
André Coutinho
37
Microsoft .NET – Application Blocks
Figura 9: Mapeamento do ficheiro de configuração do updater da aplicação (application
updater)
•
O ficheiro de configuração do updater da aplicação é mapeado
para a classe UpdaterConfiguration, cada ficheiro de
configuração de cada cliente é mapeado para a classe
ClientApplicationInfo, e cada manifest é mapeado para a
classe ServerApplicationInfo tal como se vê na figura.
O downloader a utilizar quando se copiam ficheiros. Estes componentes
implementam o interface IDownloader definido no UAB. O UAB inclui
um downloader que o usa o BITS (Background Intelligent Transfer
Service) para copiar ficheiros. Adicionalmente é possível desenvolver
downloaders customizados. A arquitectura do downloader pode ser vista
abaixo.
Figura 10: Arquitectura de validação do lado do cliente
A Figura mostra o seguinte processo:
o A classe ApplicationUpdateManager usa a propriedade
Instance da classe UpdaterConfiguration para ler a secção do
<validator> do ficheiro de configuração do updater da aplicação.
Esta secção indica o validator a usar.
o A classe ValidatorFactory é usada para instanciar o validator
especificado, que deve derivar da interface IValidator. Esta
classe também passa a secção de configuração do <validator> ao
método Init do validator. Esta secção tem a chave a usar pelo
validator para validar assinaturas.
o Finalmente a classe ApplicationUpdateManager instancia uma
classe DownloaderManager para cada aplicação a ser actualizada
e passa-a ao validator. A classe DownloaderManager usa então
periodicamente, o validator para validar as assinaturas dos
manifest e outros ficheiros copiados.
André Coutinho
38
Microsoft .NET – Application Blocks
O UAB ainda inclui uma classe chamada BITSDownloader, que
usa o BITS para copiar ficheiros. É possível utilizar esta classe
our criar uma customizada que implemente a interface
IDownloader.
• O validator que será usado para validar os ficheiros descarregados
(downloaded). Estes componentes implementam a interface IValidator
definida no UAB. Este application block inclui dois validators, um
baseado em chaves simétricas e outro baseado em chaves privadas e
públicas.
Também podem ser desenvolvidos validators customizados.
Abaixo está uma imagem que ilustra a arquitectura de validação, mas do
lado do servidor.
Figura 11: Arquitectura de validação do lado do servidor
Na Figura da arquitectura da validação vemos os seguintes aspectos:
o A ManifestUtility instancia o validator especificado pelo
utilizador. Todos os validators derivam da interface IValidator.
O utilizador também especifica uma chave, que é passada ao
validator.
o O validator gera uma assinatura para cada ficheiro no directório
de update de determinada aplicação, no servidor. Os valores
gerados são escritos no ficheiro manifest.
o Finalmente, o validator calcula a assinatura para o ficheiro de
manifest.
3 – O updater da aplicação inicia periodicamente o processo de update. Quando
isto ocorre, o updater usa o downloader especificado, para copiar o ficheiro
André Coutinho
39
Microsoft .NET – Application Blocks
manifest para cada aplicação especificada no ficheiro de configuração, para o
cliente. Se existem updates disponíveis, o downloader copia os ficheiros para
um directório temporário no cliente.
4 – O updater da aplicação carrega o validator apropriado e valida os ficheiros
descarregados. Se forem válidos, são então copiados para o directório correcto
da aplicação.
5 – Se um post processor foi especificado no ficheiro manifest, o updater da
aplicação carrega-o e executa-o.
Esta arquitectura incluída no UAB permite aos programadores criar post
processors para serem executados quando um update é feito com sucesso. Os
post processors são classes .NET que implementam a interface IPostProcessor
e são utilizados tarefas de pós instalação, tais como escrever dados no registo,
criar filas de mensagens, ou qualquer outra tarefa difícil de realizar pela simples
cópia dos ficheiros da aplicação.
A arquitectura de post processing do UAB está ilustrada na Figura seguinte.
Figura 12: Arquitectura de post processing do UAB
6.2.1. Classes do UAB
6.2.1.1. Classe ServerApplicationInfo
Esta classe é usada para entregar a informação dos ficheiros manifest ao updater
de uma aplicação num formato Object Oriented (OO).
6.2.1.1.1. Objectivos
•
A classe ServerApplicationInfo deve expor os settings de uma
aplicação no ficheiro manifest.
André Coutinho
40
Microsoft .NET – Application Blocks
•
Uma instância desta classe deverá ser passada a todos os eventos
expostos pela classe ApplicationUpdaterManager à excepção do
evento DownloadCompleted.
A classe ServerApplicationInfo é mapeada para o ficheiro manifest como se
vê abaixo.
Figura 13: Mapeamento da classe ServerApplicationInfo num ficheiro manifest
6.2.2. Os ficheiros manifest
Cada vez que um update para uma determinada aplicação é colocado num
servidor, um ficheiro manifest deve ser criado para o update. Este ficheiro inclui
informação sobre a versão do update, os ficheiros incluídos no update e
qualquer post processor a executar depois de a operação de update estar
concluída. Também inclui assinatura de validação para cada ficheiro e para o
próprio ficheiro manifest, permitindo a validação do update e protecção contra
updates não autorizados, ou ataques do tipo “man in the middle”.
Os ficheiros manifest são simples ficheiros XML. É possível criá-los
manualmente, ou usando o Manifest Utility.
A seguir encontra-se um exemplo de um ficheiro Manifest.
<ServerApplicationInfo signature="16d~#d9&9">
<availableVersion>2.0.0.0</availableVersion>
<updateLocation>http://appserver/appupdates/2.0.0.0</updateLocat
ion>
<files>
<file
name="post\Microsoft.ApplicationBlocks.ApplicationUpdater.Interf
aces.dll"
signature="25kdsj*7" />
<file name="post\MyPostProcessor.dll" signature="25sd][{*h"
/>
<file name="data\App1Data.mdb" signature="6ydh8i]+8#"
<file name="App1.exe" signature="25+)8j&h" />
<file name="App1.exe.config" signature="19huio%g" />
</files>
<postProcessor type="MyPostProcessor.MyAppProcessor"
assembly="MyPostProcessor, Version=1.0.0.0,
Culture=neutral, PublicKeyToken=null"
name="post\MyPostProcessor.dll" />
</ServerApplicationInfo>
André Coutinho
41
Microsoft .NET – Application Blocks
7. Caching Application Block
7.1. Introdução
O Caching Application Block (CAB) é um componente disponível para a
Framework .NET, que permite armazenar facilmente dados provenientes de
várias fontes, como service providers, por exemplo. Fornece também um
ambiente RAD (Rapid Application Development) que auxilia a construção e
desenvolvimento de aplicações escaláveis usando o Visual Studio .NET e é
fornecido como uma biblioteca de classes .NET.
7.2. Funcionamento
Um cliente ou Service Agent (explicado em seguida) faz um pedido ao Caching
Framework, pedindo dados em cache. Se os dados pedidos estão em cache, são
enviados ao cliente. Se pelo contrário, os dados não estão armazenados, um
Service Agente pode ser usado para obter os dados pedidos. O Cache Manager
adiciona metadados aos dados em cache, de modo que o Framework possa
monitorizar os dados (saber o último acesso aos dados, ou a “idade” dos dados,
por exemplo). Os metadados permitem estabelecer condições para libertação de
recursos e para determinar, por exemplo, qual a data de expiração dos dados.
Os dados podem ser armazenados em vários formatos, incluindo bases de dados
Microsoft SQL Server 2000, ficheiros mapeados em memória, ou objectos. O
CAB também inclui classes para caching, exploração, expiração e protecção de
dados.
7.3. O que são os Service Agents
Os Service Agents são objectos usados para obter dados dos Service providers.
Na sua forma mais básica um Service Agent é criado declarando:
• Uma classe a usar para a criação do Service Agent, que implementa a
interface IServiceAgent.
• Um método Execute, com um PersistCallback e parâmetros de input.
• Um construtor.
Depois de criar um Service Agent, é necessário
ServiceAgentMaster e ServiceAgentMap na base de dados.
adicioná-lo
ao
O método PersistCallback é usado para devolver resultados.
Os parâmetros de input a passar ao Service Agent são aqueles que o utilizador
achar necessários.
Quando o método Execute do Service Agent é chamado, os parâmetros de input
são passados como argumento. É este o método responsável por contactar os
Service providers.
Aquando da obtenção de resultados, o Service Agent não os passa directamente
para o cliente. Em vez disso, os resultados são devolvidos ao Framework. O
cliente deverá pedir os resultados usando o requestID apropriado.
André Coutinho
42
Microsoft .NET – Application Blocks
7.4. A interface IServiceAgent
Esta interface é utilizada pelas classes dos Service Agents criados. Tem um
único método, o método Execute.
public interface IServiceAgent
7.4.1. Métodos da interface IServiceAgent
Execute.
Executa um Service Agent.
7.5. O método PersistCallback
Este método é usado para obter os resultados da execução de um Service Agent.
public delegate void PersistCallBack(
ServiceAgentResult result,
bool isCompleted);
7.6. Término de um Service Agent
Um Service Agent é marcado como Failed na base de dados se:
• O FinishTime (tempo de vida, ou Time-to-live) é inferior à data actual.
• O RetryCount (número de tentativas) é inferior a zero.
• Um pedido é cancelado.
7.7. Usando o CAB com outros application blocks
O CAB incorpora o EMAB (Exception Management Application Block) para
tratamento de excepções, mas é também possível usar técnicas de tratamento de
excepções customizadas. O DAAB (Data Access Application Block) também
está incluído para minimizar o código de acesso a dados a escrever.
O código do CAB pode ser incluído num qualquer projecto e costumizado de
acordo com as necessidades do programador, também é possível usar este
application block sozinho, como uma biblioteca de classes. Também foi
desenhado para cooperar com o AIAB (Asynchronous Invocation Information
Application Block) e o AAB (Aggregation Application Block).
O CAB é composto por várias assemblies, que fornecem flexibilidade,
extensibilidade e facilidade para o armazenamento de dados. Incorporando o
CAB numa aplicação distribuída, é possível melhorar a performance dessa
aplicação, além da sua escalabilidade e disponibilidade.
A tabela seguinte mostra as diferentes assemblies do CAB.
Assembly
Descrição
Microsoft.ApplicationBlocks.Cache
Contém as classes que fornecem
as funcionalidades de caching.
Microsoft.ApplicationBlocks.Data
André Coutinho
Contém as classes que fornecem
43
Microsoft .NET – Application Blocks
o acesso a dados, a bases de
dados SQL Server 2000.
Microsoft.ApplicationBlocks.ExceptionManagement
Contém classes que fornecem
tratamento de excepções.
Microsoft.ApplicationBlocks.ExceptionMangement.Interfaces
Contém
interfaces
para
tratamento de excepções.
Microsoft.ApplicationBlocks.MemoryMappedFile
Contém
classes
trabalhar
para
com
criar
e
ficheiros
mapeados em memória.
Tabela 1: As diferentes assemblies do CAB
7.8. Componentes primários do CAB
Este application block possui três componentes primários que cooperam
mutuamente:
7.8.1. Classe CacheManager
A classe CacheManager fornece a interface de acesso à própria cache.
Esta classe fornece funcionalidades de adição, recuperação e remoção de items e
metadados de e para a cache.
public sealed class CacheManager
7.8.1.1. Métodos da classe CacheManager
•
Add.
Adiciona um item à cache.
public void Add (
string key,
object keyData )
•
Flush.
Limpa a cache.
public void Flush()
•
GetCacheManager.
Devolve a instância única do objecto CacheManager.
public static CacheManager GetCacheManager()
•
GetData. Devolve o item em cache, correspondente à chave
especificada.
public object GetData (
string key )
•
GetItem.
Devolve o item, e o seus metadados, em cache, correspondente
à chave especificada.
André Coutinho
44
Microsoft .NET – Application Blocks
•
public CacheItem GetItem (
string key )
Remove. Remove o item da cache, correspondente
à chave especificada.
public void Remove (
string key )
7.8.1.2. Propriedades da classe CacheManager
•
CacheStorage.
Obtém a interface ICacheStorage.
public static ICacheStorage CacheStorage {get;}
•
Item.
Obtém o item em cache, correspondente à chave especificada.
public object this[ string key ] {get;}
Esta classe é uma classe sealed, portanto não pode ser herdada.
7.8.2.A classe CacheService
A classe CacheService é responsável pela gestão dos mteadados da cache. O
cache service pode ser instalado no mesmo AppDomain do CacheManager ou
não, dependendo do espaço necessário para armazenamento e do seu alcance.
public sealed class CacheService : MarshalByRefObject
7.8.2.1. Métodos da classe CacheService
•
Add.
Adiciona um item com os metadados especificados ao cache
service.
public void Add (
string keyVal,
ICacheItemExpiration[] expirations,
CacheItemPriority priority,
CacheItemRemovedCallback onRemoveCallback )
•
BeginAdd.
Inicia um pedido assíncrono para adicionar um item ao cache
service.
public void BeginAdd (
string key,
ICacheItemExpiration[] expirations,
CacheItemPriority priority,
CacheItemRemovedCallback onRemoveCallback,
AsyncCallback callback,
object asyncState )
•
BeginFlush.
Inicia um pedido assíncrono para limpar todos os items do
cache service.
public void BeginFlush (
André Coutinho
45
Microsoft .NET – Application Blocks
AsyncCallback callback,
object asyncState )
•
BeginNotify.
Inicia um pedido assíncrono para notificação de que um
item foi usado recentemente.
public void BeginNotify (
string key,
System.AsyncCallback callback,
object asyncState )
•
BeginRemove.
Inicia um pedido assíncrono para remover um item.
public void BeginRemove(
string key,
System.AsyncCallback callback,
object asyncState )
•
CacheService.
Construtor para iniciar os processos de exploração e
expiração.
public CacheService()
•
Flush.
Limpa todos os items do cache service.
public void Flush()
•
GetData.
Devolve o item do cache service, correspondente à chave
especificada.
public CacheItem GetData (
string key )
•
InitializeLifetimeService. Obtém um objecto lifetime service
para controlo da política de tempo de vida para esta instância.
public override object InitializeLifetimeService()
•
Notify. Notifica que o item correspondente à chave especificada, foi
usado recentemente.
public void Notify ( string key )
•
Remove.
Remove os metadados do cache service.
public void Remove ( string key )
7.8.3. A interface ICacheStorage
Um storage provider que implemente o interface ICacheStorage consegue
tratar a inserção, recuperação e eliminação de dados em cache e para a
cache.
André Coutinho
46
Microsoft .NET – Application Blocks
O CAB fornece três implementações de armazenamento em cache nos
seguintes namespaces:
•
•
•
MmfCacheStorage
SingletonCacheStorage
SqlServerCacheStorage
Esta interface permite implementar mecanismos de armazenamento em
cache.
7.8.3.1. Métodos da interface ICacheStorage
•
Add.
Armazena um item com a chave e valor especificados
void Add (
string key,
object keyData);
•
Flush.
Remove todos os items do armazenamento.
void Flush();
•
GetData.
Devolve o item, correspondente à chave especificada.
object GetData (
string key);
•
Remove.
Remove o item , correspondente à chave especificada.
void Remove (
string key )
7.8.3.2. Propriedades da interface ICacheStorage
•
Size.
Devolve o número de items armazenados.
int Size{ get; }
7.9. Ficheiros de Configuração
Este application block usa vários ficheiros de configuração para a aplicação, o
serviço de cache, e para os ficheiros Cliente.exe e Server.exe. É necessário
adicionar parâmetros de configuração a cada um destes ficheiros antes de utilizar
o CAB.
App.config
O App.config é usado pelos seguintes parâmetros da classe CacheManager:
•
Protecção de dados
André Coutinho
47
Microsoft .NET – Application Blocks
•
•
•
Armazenamento e modo de armazenamento
Exploração
Expiração
<?xml version ="1.0"?>
<configuration>
<startup>
<requiredRuntime version="v1.0.3705"/>
<supportedRuntime version="v1.0.3705"/>
</startup>
</configuration>
CacheService.config
O CacheService.config é utilizado para configurar os seguintes parâmetros
da classe CacheService:
• Armazenamento
• Exploração
• Expiração
Client.exe.config
O ficheiro de configuração Client.exe.config serve para configurar os
seguintes parâmetros no cliente (remoto):
• Caminho e tipo de um objecto remoto
• Canal usado para comunicar com o cliente
<configuration>
<system.runtime.remoting>
<application>
<channels>
<channel ref="http" useDefaultCredentials="true"
port="0">
<clientProviders>
<formatter
ref="binary"
/>
</clientProviders>
</channel>
</channels>
<client>
<wellknown
url="http://localhost:80/HttpBinary/SAService.rem"
type="ServiceClass, ServiceClass"
/>
</client>
</application>
</system.runtime.remoting>
</configuration>
Server.exe.config
Este ficheiro é utilizado na configuração de vários parâmetros no servidor
(remoto):
André Coutinho
48
Microsoft .NET – Application Blocks
•
•
Caminho e tipo de um objecto remoto
Canal usado para comunicar com o servidor
<configuration>
<system.runtime.remoting>
<application>
<service>
<activated type="ClientActivatedType,
RemoteType"/>
</service>
<channels>
<channel port="8080" ref="http"/>
</channels>
</application>
</system.runtime.remoting>
</configuration>
7.10. Protecção de dados
Os dados armazenados em cache devem ser protegidos contra a adulteração e
spoofing de dados. O CAB possui um interface IDataProtection, (a ver mais à
frente) de modo a permitir a implementação de um esquema de protecção.
A classe DefaultDataProtection funciona como um fornecedor de serviços de
protecção de dados e encapsula o Win32 Data Protection API (DPAPI) para
encriptar/desencriptar items em cache, e usa o algoritmo SHA1 para fazer a
validação.
Quer se use esta classe ou um outro fornecedor de serviços de protecção de
dados, é necessário colocar o atributo Encrypted para o elemento <StorageInfo>
a true, no ficheiro App.config, para encriptar os dados armazenados em cache.
7.10.1. A interface IDataProtection
A interface IDataProtection permite implementar esquema de protecção da
cache.
public interface IDataProtection
7.10.1.1. Métodos do interface IDataProtection
•
ComputerHash.
Faz o hashing para validação de dados.
byte[] ComputeHash(
byte[] plainValue );
•
Decrypt.
Desencripta um array de bytes.
byte[] Decrypt(
byte[] cipherValue );
•
Encrypt.
Encripta um array de bytes.
byte[] Encrypt (
byte[] plainValue )
André Coutinho
49
Microsoft .NET – Application Blocks
•
Init.
Inicializa o serviço de protecção de dados.
void Init(
XmlNode config );
7.11. Expiração
Quando um item é adicionado à cache, é necessário determinar a sua política de
expiração, isto é, qual é a sua data de expiração.
A tabela seguinte lista as classes existentes no namespace
Microsoft.ApplicationBlocks.Cache.Expirations, cada uma destas classes usa o
interface IcacheItemExpiration.
7.11.1. Classe AbsoluteTime
É utilizada para determinar tempos de expiração. Testa se um item da cache já
expirou.
public class AbsoluteTime: ICacheExpiration, ISerializable
7.11.1.1. Construtores da classe AbsoluteTime
•
AbsoluteTime.
Cria uma instância da classe.
public AbsoluteTime()
7.11.1.2. Métodos da classe AbsoluteTime
•
GetObjectData.
Faz a serialização dos membros da classe.
[SecurityPermissionAttribute( SecurityAction.Demand,
SerializationFormatter = true )]
SecurityPermissionAttribute( SecurityAction.LinkDemand,
SerializationFormatter = true )]
public void GetObjectData ( SerializationInfo info,
StreamingContext context )
•
Change.
Indica o tempo de expiração de um item.
public event ItemDependencyChangeEventHandler Change;
7.11.2. Classe ExtendedFormatTime
Esta classe é usada para determinar uma data de expiração, baseada numa
expressão (por exemplo cada minuto, cada Domingo).
public ExtendedFormatTime()
André Coutinho
50
Microsoft .NET – Application Blocks
7.11.3. Classe FileDependency
Usa-se esta classe para definir uma data de expiração, baseando-se no facto de
um ficheiro ter sido alterado ou não.
public
class
ISerializable
FileDependency:
IcacheItemExpiration,
7.11.3.1. Construtores da classe FileDependency
•
FileDependency.
Cria uma instância da classe.
public FileDependency(
string fullFileName )
7.11.3.2. Métodos da classe FileDependency
•
GetObjectData.
Preenche um objecto SerializationInfo, com os
dados necessários para serializar o objecto pretendido.
[SecurityPermissionAttribute(
SecurityAction.Demand, SerializationFormatter =
true)]
[SecurityPermissionAttribute(
SecurityAction.LinkDemand, SerializationFormatter =
true)]
public void GetObjectData( SerializationInfo info,
StreamingContext context )
•
HasExpired.
Indica se um objecto já expirou ou não.
bool ICacheItemExpiration.HasExpired()
•
Key.
Define a chave de dependência externa.
void ICacheItemExpiration.Key(
string keyVal)
•
Notify.
Notifica que um item foi usado.
void ICacheItemExpiration.Notify()
7.11.3.3. Eventos da classe FileDependency
•
Change. Ocorre quando um item expira.
public event ItemDependencyChangeEventHandler Change;
7.11.4. Classe SlidingTime
André Coutinho
51
Microsoft .NET – Application Blocks
É usada para definir o tempo de vida de um qualquer item, especificando uma
data de expiração com base no último acesso a esse item.
public
class
ISerializable
SlidingTime:
IcacheItemExpiration,
7.11.4.1. Métodos da classe SlidingTime
•
GetObjectData. Preenche um objecto SerializationInfo, com os
dados necessários para serializar o objecto pretendido.
public void GetObjectData(
SerializationInfo info,
StreamingContext context )
•
HasExpired.
Indica se um objecto já expirou ou não.
bool ICacheItemExpiration.HasExpired()
•
Key.
Define a chave de dependência externa.
void ICacheItemExpiration.Key(
string keyVal)
•
Notify.
Notifica que um item foi usado.
void ICacheItemExpiration.Notify()
•
SlidingTime.
Cria uma instância da classe.
public SlidingTime ( TimeSpan slidingExpiration )
7.11.4.2. Eventos da classe SlindingTime
•
Change.
Ocorre quando um item expira..
public event ItemDependencyChangeEventHandler Change;
NOTA: se não for definido nenhum tempo de expiração para um qualquer item,
este nunca expira.
É possível utilizar uma implementação customizada, ao invés de usar umas das
classes acima descritas.
No processo de escolha de uma política de expiração, devem-se ter em
consideração os seguintes aspectos:
• Deve ser usada uma expiração com base no tempo, para items voláteis.
Estes são os items que sofrem regularmente actualizações, ou que apenas
são válidos por um período de tempo bem definido (normalmente curto).
• Deve ser usada uma expiração baseada em FileDependency para
definir a validade de um determinado item em cache dependente de
André Coutinho
52
Microsoft .NET – Application Blocks
certas propriedades do ficheiro, que quando alteradas invalidam os dados
armazenados.
7.12. Exploração
A classe LruScavenging pertence ao CAB, e pode ser utilizada para remover
automaticamente items da cache, quando há poucos recursos de armazenamento.
Esta classe usa o algoritmo least recently used para retirar da cache os items que
não são usados há mais tempo.
Se for criada uma classe costumizada para exploração, esta deve ser especificada
no elemento <ScavengingInfo> do ficheiro App.config. As classes criadas para
exploração devem implementar o interface IScavengingAlgorithm.
Quando um item é explorado apartir da cache, é possível especificar um
CacheItemRemovedCallback para representar o método que será invocado
quando um item é removido da cache. O CacheItemRemoveCallback também
especifica a causa para a remoção de um determinado item.
7.12.1. A interface IScavengingAlgorithm
Permite a implementação de algoritmos de exploração.
public interface IScavengingAlgorithm
7.12.1.1. Métodos do interface IScavengingAlgorithm
•
Add.
Adiciona um item à lista do algoritmo
void Add (
string key,
CacheItemPriority priority );
•
Execute.
Executa o algoritmo.
void Execute ();
•
Flush.
Remove todos os items da lista do algoritmo.
void Flush ();
•
Init.
Inicia o algoritmo de exploração.
void Init (
CacheService cacheService,
ICacheStorage cacheStorage,
ICacheMetadata cacheMetadata,
XmlNode config );
•
Notify.
Notifica que o item, correspondente à chave especificada, foi
usado recentemente.
void Notify(
string key );
André Coutinho
53
Microsoft .NET – Application Blocks
•
Remove.
Remove o item, correspondente à chave especificada.
void Remove (
string key);
•
CacheItemRemovedCallback.
Representa o método a invocar quando
um item é removido da cache.
public delegate void
CacheItemRemovedCallback(string
key,CacheItemRemoveCache cause);
7.13. Armazenamento
Existem três opções disponíveis para o armazenamento em cache, usando o
CAB.
•
•
•
MMF (memory-mapped file)
Objectos singulares
Bases de dados SQL Server 2000
7.13.1. Como escolher uma das opções de armazenamento
Ao escolher uma das opções de armazenamento deve-se ter em conta:
•
•
•
•
O alcance da aplicação. Para uma aplicação cliente em Windows Forms,
o MMF só tem alcance no computador cliente.
Os MMFs são mais apropriados para um cenário de caching baseado no
cliente. É possível utilizar MMFs para desenvolver uma cache
distribuída pelos vários AppDomain e processos no mesmo computador.
O Framework .NET não suporta MMFs, portanto qualquer
implementação que use MMFs não beneficia de várias características do
.NET, como por exemplo as características de gestão de memória, (como
o garbage collection) e de segurança.
Os objectos singulares só podem ser usados no alcance do AppDomain,
mas proporcionam melhor performance.
O armazenamento em SQL Server 2000 é mais aconselhado para
aplicações que requerem uma grande durabilidade, ou quando é
necessário armazenar grandes quantidades de dados. Uma vez que o
serviço de caching necessita de aceder ao SQL Server através de uma
rede, e os dados são devolvidos usando queries, tornando portanto, o
acesso relativamente lento.
7.13.2. Classe MemoryMappedFileStream
Esta classe é usado para criar, fornecer acesso, ler, e remover dados da cache, de
um MMF.
public class MemoryMappedFileStream: Sream, IDisposable
André Coutinho
54
Microsoft .NET – Application Blocks
7.13.2.1. Construtores da classe MemoryMappedFileStream
•
MemoryMappedFileStream.
Cria uma instância da classe.
public MemoryMappedFileStream( string name,
MemoryProtection protection )
7.13.2.2. Métodos da classe MemoryMappedFileStream
•
Close.
Fecha o MMF.
public override void Close()
•
CloseMapHandle.
Fecha o map handle do memory map.
public void CloseMapHandle()
•
Dispose.
Descarta o MMF.
public void Dispose()
•
Flush.
Remove todos os MMFs do armazenamento de dados.
void ICacheStorage.Flush ()
•
MapViewToProcessMemory.
Verifica o comprimento e o offset de um
MMF.
public void MapViewToProcessMemory(
int offSet,
int count )
•
OpenDictionary.
Abre o objecto Dictionary, se disponível.
public static IntPtr OpenDictionary (
string name,
MemoryProtection protection )
•
OpenExisting.
Abre um MMF existente.
public static MemoryMappedFileStream OpenExisting(
string name,
MemoryProtection protection )
•
Read.
Lê de um MMF e escreve no buffer.
public override int Read(
byte[] buffer,
int offSet,
int count )
•
Seek.
Procura uma determinada posição num stream de bytes.
André Coutinho
55
Microsoft .NET – Application Blocks
public override long Seek(
long offset,
SeekOrigin origin )
•
SetLength.
Ajusta o comprimento de um MMF.
public override void SetLength(
long memoryLength )
•
SetMaxLength.
Ajusta o comprimento máximo do ficheiro.
public void SetMaxLength(
long maxLength )
•
Write.
Escreve dados binários para um MMF.
public override void Write(
byte[] buffer,
int offSet,
int count )
7.13.2.3. Propriedades da classe MemoryMappedFileStream
•
CanRead.
Verifica se o MMF tem acesso de leitura.
public override bool CanRead {get;}
•
CanSeek.
Verifica se o MMF tem acesso de pesquisa.
public override bool CanSeek {get;}
•
CanWrite.
Verifica se o MMF tem acesso de escrita.
public override bool CanWrite {get;}
•
Length.
Verifica o comprimento do MMF
public override long Length {get;}
•
MaxLength.
Verifica o comprimento máximo do MMF.
public uint MaxLength {get;}
•
Position.
Verifica ou ajusta a posição no MMF.
public override long Position {get; set;}
André Coutinho
56
Microsoft .NET – Application Blocks
8. Aggregation Application Block
8.1. Introdução
O Aggregation Application Block (AAB) é uma extensão ao Framework .NET
que permite a fácil manutenção e junção de informação de vários Service
providers e outros sistemas, para a apresentação aos utilizadores.
Este application block fornece um ambiente RAD (Rapid Application
Development) para auxiliar à construção de aplicações escaláveis, usando o
Visual Studio .NET.
É fornecido como uma biblioteca de classes .NET.
As fontes básicas de dados serão quase sempre serviços baseados em .NET, mas
também poderão ser obtidos apartir de servidores do tipo BizTalkServer 2000 e
SQL Server 2000, por exemplo.
8.2. Funcionamento
Num cenário de agregação de informação, uma aplicação cliente faz um pedido
a vários Service providers para obter os dados de que necessita. Um Service
Agent é usado para comunicar com cada provider, de modo a reunir os dados
requisitados e a entregá-los de forma agregada à aplicação cliente.
Os Service Agents são de extrema importância no AAB. Toda a lógica dos
pedidos de informação, está contida nas classes ServiceAgent criadas. Para
adicionar um novo service provider ou criar um novo service request, com o seu
próprio formato e protocolo de pedido/resposta, uma aplicação necessita apenas
que seja criado um Service Agent. Um ServiceAgent novo pode herdar o
comportamento (ou partes deste) duma classe ServiceAgent mais genérica, que
tenha sido criada.
O RequestProcessor é o componente responsável pela gestão dos pedidos de
agregação de informação. Adiciona Service Agents a uma fila, apartir da qual os
Service Agents são executados.
Os Service Agents retornam os resultados para o Transformation Manager,
para serem transformados para XSL. Usando ficheiros XSL e XSD, serão
devolvidos ao utilizador os resultados agregados num único ficheiro XML.
8.3. Usando o AAB com outros Application Blocks
O AAB incorpora o EMAB (Exception Management Application Block) para o
tratamento de excepções. No entanto, não é obrigatório usar o EMAB em
conjunto com o AAB.
É possível usar o AAB independentemente numa aplicação, mas também com
outros application blocks, tais como, o AIAB (Asynchronous Invocation
Application Block) e o CAB (Caching Application Block).
André Coutinho
57
Microsoft .NET – Application Blocks
8.4. Design do AAB
Abaixo podemos ver a arquitectura do AAB.
Figura 14: Arquitectura do AAB
Na figura podemos ver:
• O cliente cria um objecto AggregationRequest que contêm os detalhes
do pedido de informação. Este objecto lê o ficheiro de configuração
AggregationConfig.xml, para obter o nome da classe, caminho e tempo
de vida para todos os Service Agents criados para atender o pedido.
• O objecto AggregationRequest chaem o método ProcessRequest da
classe RequestProcessor, e passa os detalhes do pedido. O
RequestProcessor cria os objectos ServiceAgentRequestDetails e
adiciona-os
à
fila
ServiceAgentDetailQueue
da
classe
AggregationThreadPool.
• A classe AggregationThreadPool gere uma pool de threads usadas para
executar Service Agents. Uma thread é iniciada chamando o método
WorkerThread.Start.
O ServiceAgentMonitor monitoriza as threads que estão a executar
Service Agents, e aborta as threads que continuam a executar após o seu
tempo de vida ter expirado.
• O Service Agent adquire a informação do service provider e actualiza o
RequestProcessor.XmlResultList, que contém um array de
documentos XML com os resultados.
• O objectos AggregationRequest cria um objecto Transformation
Manager e passa-o ao array de documentos XML, de stylesheets, e ao
schema file. O Transformation Manager transforma e une os
André Coutinho
58
Microsoft .NET – Application Blocks
•
documentos XML que contém os resultados, num único documento
XML.
O objecto AggregationRequest devolve, finalmente, a estrutura
AggregationRequest para o cliente.
8.5. Classe AggregationRequest
Esta classe é utilizada por uma aplicação cliente para fazer um pedido de
agregação da informação que precisa. Passa os pedidos à classe
RequestProcessor, e cria um objecto Transformation Manager para
transformação dos resultados.
public class AggregationRequest
8.5.1. Construtor da classe AggregationRequest
•
AggregationRequest.
Inicializa uma nova instância da classe.
public AggregationRequest()
8.5.2. Métodos da classe AggregationRequest
•
GetResults.
Devolve resultados agregados do RequestProcessor.
public AggregatedResult GetResults(
string requestType )
8.6. A estrutura AggregatedResult
A estrutura AggregatedResult é usada para devolver o resultado da agregação
dos dados ao cliente.
public struct AggregatedResult
8.6.1. Propriedades da estrutura AggregatedResult
•
AggregatedDataSet. Dataset
que contém resultados de pedidos.
public DataSet AggregatedDataSet {get;}
•
AggregatedXml.
Documento
TransformationManager.
XML
agregado,
do
public XmlDocument AggregatedXml {get;}
•
ExceptionMessages.
Obtém as mensagens de erro de Service Agents
que falharam.
public ArrayList ExceptionMessages {get}
André Coutinho
59
Microsoft .NET – Application Blocks
NOTA: esta estrutura pode ser retornada sob a forma de um documento XML ou
Dataset.
8.7. Ficheiro de configuração
O AAB usa um ficheiro de configuração, o App.config, para a configuração de
intervalos de tempo, e pool de threads, para o RequestProcessor.
App.config
•
AggregationConfigFile.
Especifica o
caminho
para o
ficheiro
AggregationConfig.xml
•
RequestProcessorSleepTime.
•
MinThreadPoolSize.
•
MaxThreadPoolSize.
•
ServiceAgentMonitorInterval.
Especifica o tempo (em milisegundos),
durante o qual a thread irá adormecer (sleep) antes de verificar o resultado
e o tempo final de um pedido de agregação.
Especifica o número mínimo de threads estáticas
que deverão estar disponíveis na pool.
Especifica o número máximo de threads estáticas
que deverão estar disponíveis na pool.
Especifica o intervalo de tempo para a
classe ServiceAgentMonitor.
•
Especifica o tempo (em milisegundos) que uma
thread dinâmica espera em suspensão (idle) antes de fazer exit.
•
DynamicThreadCreateTime.
DynamicThreadWaitTime.
Especifica o tempo (em milisegundos) que
deverá esperar na fila antes da classe
AggregationThreadPool criar e iniciar uma thread dinâmica.
um
Service
Agent
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<appSettings>
<!-- FILE PATH SETTING
Use AggregationConfigFile key to specify the path
where the
Aggregationconfig.xml file_u105 ?s available.
-->
<add key="AggregationConfigFile"
value="<AggregationConfigFilePath>\AggregationConfig.xml"
/>
<!-- PROCESSOR SLEEP TIME SETTING
Use RequestProcessorSleepTime key to specify the
amount of time
the main thread sleeps before checking the result
count and
André Coutinho
60
Microsoft .NET – Application Blocks
finish time of the aggregation request.
-->
<add key="RequestProcessorSleepTime" value="1000" />
<!-- THREAD POOL SIZE SETTING
Use MinThreadPoolSize key to specify the minimum
number of threads
that should be available in the thread pool.
-->
<add key="MinThreadPoolSize" value="10" />
<!-- THREAD POOL SIZE SETTING
Use MaxThreadPoolSize key to specify the maximum
number of threads
in the thread pool.
-->
<add key="MaxThreadPoolSize" value="20" />
<!-- MONITOR INTERVAL SETTING
Use ServiceAgentMonitorInterval key to specify the
timer interval
of the ServiceAgentMonitor_u99 ?lass.
-->
<add key="ServiceAgentMonitorInterval" value="1000" />
<!-- THREAD WAIT TIME SETTING
Use DynamicThreadWaitTime key to specify the amount
of time
in milliseconds the dynamic thread idly waits,
before it exits.
-->
<add key="DynamicThreadWaitTime" value="3000" />
<!-- THREAD CREATE TIME SETTING
Use DynamicThreadCreateTime key to specify the
amount of time
in milliseconds. If the service agent has waited in
the queue
for the above mentioned time interval, then a new
dynamic thread
is created and started.
-->
<add key="DynamicThreadCreateTime" value="1000" />
</appSettings>
</configuration>
AggregationConfig.xml
Este ficheiro é utilizado para descrever detalhes do Service Agent,
nomeadamente, o nome da classe do Service Agent, o local de instalação, o
tempo de vida e a localização das style sheets. Sempre que é criada uma nova
classe de Service Agents é necessário actualizar este ficheito para reflectir a
configuração dos Service Agents.
<!DOCTYPE Aggregation[
<!ELEMENT Aggregation (CONFIGITEM+)>
<!ELEMENT CONFIGITEM ANY>
<!ATTLIST CONFIGITEM NAME ID #REQUIRED>
]>
<!-This file contains the details about the service agents like
class name,
André Coutinho
61
Microsoft .NET – Application Blocks
Assembly file location and the style sheet files etc.,
-->
<Aggregation>
<Request>
<!-RequestType definition
-->
<RequestType Type="SampleType">
<ServiceAgent>
<!-SAID - Service agent Id's for the request
type declared above.
-->
<SAID>A</SAID>
<SAID>B</SAID>
<SAID>C</SAID>
</ServiceAgent>
<!-The aggregation request time-to-live value. If
the TTL value is not
passed as an argument, then this value is
considered.
-->
<TimeToLive>5</TimeToLive>
<!-The schema file path
-->
<TransformationSchema>"<SchemaFilePath>\<SchemaFileName>"</Trans
formationSchema>
</RequestType>
<RequestType Type="Sample">
<ServiceAgent>
<SAID>D</SAID>
<SAID>E</SAID>
</ServiceAgent>
<TimeToLive>5</TimeToLive>
<TransformationSchema>"<SchemaFilePath>\<SchemaFileName>"</Trans
formationSchema>
</RequestType>
</Request>
<ServiceAgentDetails>
<!-Details of the service agent, whose SAID is declared
above.
-->
<ServiceAgent SAID="A">
<!-The class name of the service agent
-->
<ClassName><Namespace>.<ClassName></ClassName>
<!-The location of the assembly where this service
agent is defined.
-->
<AssemblyPath>"<ServiceAgentAssemblyPath>\<ServiceAgentAssemblyN
ame.dll>"</AssemblyPath>
<!--
André Coutinho
62
Microsoft .NET – Application Blocks
The style sheet file that is applied over the
xml result
obtained from this service agent
-->
<Transformation>"<XSLTFilePath>\<XSLTFileName>"</Transformation>
</ServiceAgent>
<ServiceAgent SAID="B">
<ClassName><Namespace>.<ClassName></ClassName>
<AssemblyPath>"<ServiceAgentAssemblyPath>\<ServiceAgentAssemblyN
ame.dll>"</AssemblyPath>
<Transformation>"<XSLTFilePath>\<XSLTFileName>"</Transformation>
</ServiceAgent>
<ServiceAgent SAID="C">
<ClassName><Namespace>.<ClassName></ClassName>
<AssemblyPath>"<ServiceAgentAssemblyPath>\<ServiceAgentAssemblyN
ame.dll>"</AssemblyPath>
<Transformation>"<XSLTFilePath>\<XSLTFileName>"</Transformation>
</ServiceAgent>
<ServiceAgent SAID="D">
<ClassName><Namespace>.<ClassName></ClassName>
<AssemblyPath>"<ServiceAgentAssemblyPath>\<ServiceAgentAssemblyN
ame.dll>"</AssemblyPath>
<Transformation>"<XSLTFilePath>\<XSLTFileName>"</Transformation>
</ServiceAgent>
<ServiceAgent SAID="E">
<ClassName><Namespace>.<ClassName></ClassName>
<AssemblyPath>"<ServiceAgentAssemblyPath>\<ServiceAgentAssemblyN
ame.dll>"</AssemblyPath>
<Transformation>"<XSLTFilePath>\<XSLTFileName>"</Transformation>
</ServiceAgent>
</ServiceAgentDetails>
</Aggregation>
André Coutinho
63
Microsoft .NET – Application Blocks
9. Asynchronous Invocation Application Block
9.1. Introdução
O problema das comunicações síncronas
Uma aplicação distribuída poderá necessitar de informação de vários Service
providers. Se todo o processo for feito de maneira síncrona, o cliente terá que
esperar até que todos os Service providers sejam contactados e também terá que
contar com atrasos no estabelecimento da conexão, ou atrasos de serviço. A
comunicação síncrona obriga o utilizador a esperar que todos os Service
providers processem o pedido.
O AIAB resolve este problema de performance, fornecendo um mecanismo de
processamento assíncrono dos pedidos, que aumenta a eficiência do servidor e
melhora a experiência do utilizador.
O AIAB gere as comunicações assíncronas entre um cliente e um ou mais
Foreign Service Providers (FSP). Um FSP pode ser um serviço Web baseado em
.NET ou Java, por exemplo.
Usando este application block numa aplicação Web é possível:
• Melhorar a experiência de browsing do utilizador final.
• Aumentar a performance do servidor.
9.2. Funcionamento
Um cliente faz um pedido para múltiplos Service providers, submetendo esse
pedido ao AIAB. O AIAB usa um Service Agent para comunicar com cada
service provider. Assim que a informação requisitada fica disponível, é enviada
ao cliente. Desta forma, uma página, por exemplo, está pronta a ser visualizada
mesmo antes de toda a informação requisitada estar disponível. O utilizador
final “sente” uma aplicação mais rápida, e os recursos dos servidores são
libertados muito mais rapidamente, do que num cenário de sincronismo.
9.3. Utilização do AIAB com outros application blocks
O AIAB incorpora o EMAB (Exception Management Application Block) para
tratamento de excepções, embora não seja obrigatório usar o EMAB
conjuntamente com o AIAB. O DAAB (Data Access Application Block)
também está incluído para minimizar o código de acesso a dados que seja
preciso escrever.
Este application block pode ser usado sozinho como uma biblioteca de classes,
mas também é possível incluir o seu código fonte num qualquer projecto é
modificá-lo de acordo com as necessidades. Também foi desenhado para
trabalhar em conjunto com o CAB (Caching Application Block) e o AAB
(Aggregation Application Block).
André Coutinho
64
Microsoft .NET – Application Blocks
9.4. Arquitectura do AIAB
A arquitectura deste application block involve vários subsistemas:
• O subsistema Request, que contém classes que permitem criar service
requests e persisti-los numa base de dados.
• O subsistema Dispatcher, que contém classes para recuperar os service
requests da base de dados, pô-los numa fila, e atribuir threads para
executar os Service Agents.
• O subsistema Monitor, que monitoriza a execução dos Service Agents e
executa a garbage collection.
A Figura abaixo ilustra o modo de funcionamento do AIAB.
Figura 15: Arquitectura do AIAB
9.4.1. O subsistema Request
•
•
•
Um cliente cria um objecto AsyncRequestBatch que irá conter os dados
do pedido, e chama o método AddRequest para adicionar os pedidos
individualmente ao AsyncRequestBatch.
O cliente chama o AsyncRequestProcessor.SubmitRequest para
submeter o pedido.
O AsyncRequestProcessor cria uma estrutura Request para armazenar os
detalhes dos pedidos e persisti-los na base de dados usando o
RequestDBOp.
André Coutinho
65
Microsoft .NET – Application Blocks
9.4.1.1. Classe AsyncRequestBacth
Esta classe é utilizada para armazenar os detalhes dos pedidos de informação dos
clientes.
public class AsyncRequestBatch: ISerializable
9.4.1.1.1. Construtor da classe AsyncRequestBatch
•
AsyncRequestBatch.
Inicializa uma nova instância da classe.
public AsyncRequestBatch(
int timeOutValue,
bool isPersistentValue)
9.4.1.1.2. Métodos da classe AsyncRequestBatch
•
AddRequest. Adiciona o friendly name, a chave de referência, a
contagem de retries, o tempo de vida e parâmetros de input para um
Service Agent.
public void AddRequest(
string friendlyName,
string referenceKey)
•
GetObjectData.
Faz a serialização de membros da classe.
public void GetObjectData (
SerializationInfo info,
StreamingContext context)
•
RemoveAllServiceAgentInputData.
Remove todas as estrutura, do
objecto AsyncRequestBatch.
public void RemoveAllServiceAgentInputData()
•
RemoveServiceAgentInputData. Remove a estrutura que contém a
chave de referência passada como parâmetro.
public void RemoveServiceAgentInputData(
string referenceKey)
9.4.1.1.3. Propriedades da classe AsyncRequestBatch
•
Count.
Conta o número de pedidos no serviceAgentInputDataList.
public int Count {get;}
•
IsPersistent.
Especifica se um Service Agent é persistente ou não.
public bool IsPersistent {get;}
André Coutinho
66
Microsoft .NET – Application Blocks
•
TimeOut.
Obtém o valor de time out de um Service Agent.
public int TimeOut {get;}
•
AsyncRequestProcessor.SubmitRequest. Persiste o objecto Request
na base de dados e retorna uma string requestID.
public static string SubmitRequest(
AsyncRequestBatch requestBatch)
9.4.2. O subsistema Dispatcher
•
•
•
•
•
•
•
Quando o AsyncROHService arranca, obtém a instância do
AsyncDispatcher, cria uma nova thread para o Processor e chama o
método
ExecuteServiceAgent
para
adicionar
objectos
ServiceAgentReqDetails à pool AsyncThreadPool.
O Processor lê os pedidos dos Service Agents da base de dados,
segundo um escalonamento FIFO. A seguir cria um objecto
ServiceAgentReqDetails para uso do ServiceAgent, para o contacto
com os Service providers.
O Processor adiciona cada objecto ServiceAgentReqDetails à fila de
Service Agents. As threads da pool AsyncThreadPool lêem os Service
Agents da fila de Service Agents e executam-nos. O Processor só
recupera novos Service Agents se existirem threads suficientes na pool
de threads.
Depois de um atraso de poll-back, o Processor volta a inquirir a base de
dados para descobrir novos Service Agents.
As threads da pool AsyncThreadPool lêem os Service Agents da fila
respectiva e executam-nos.
Os Service Agents comunicam com os Service providers e retornam os
resultados. Os resultados são persistidos na base de dados através de
um procedure (usando o objecto DispatcherDBOp) e passando o
objecto Result.
O cliente inquire o ResultManager para ver o estado do pedido e
resultado, ou para cancelar o pedido. Enquanto é processado, um
pedido poderá encontrar-se num de vários estados:
public enum RequestStatus
{
Init,
Executing,
Completed,
MarkedForDeletion,
ToBeCleared,
Failed,
PartiallyCompleted,
Unknown
}
Estados
•
André Coutinho
Init.
O pedido foi iniciado.
67
Microsoft .NET – Application Blocks
•
•
•
•
•
•
•
Executing.
O pedido está a executar.
Completed. O pedido foi completo.
MarkedForDeletion. O pedido está assinalado para ser
removido.
ToBeCleared. O pedido está assinalado para ser terminado.
Failed. O pedido falhou.
PartiallyCompleted. O pedido está parcialmente completo.
Unknown. O pedido está num estado não desconhecido.
9.4.2.1. Classe AsyncROHServices
Esta classe é um serviço que permite a execução de Service Agents.
public class AsyncRohService : ServiceBase
9.4.2.1.1. Construtor da classe AsyncROHService
•
AsyncRohService.
Construtor da classe
public AsyncRohService()
9.4.2.1.2. Métodos da classe AsyncROHService
•
Dispose.
Liberta os recursos usados pelo serviço.
protected override void Dispose(
bool isDisposing)
•
OnCustomCommand.
Executa uma operação específica enquanto o serviço
está a correr.
protected override void OnCustomCommand(
int command)
•
OnStart.
Chamado quando o serviço arranca.
protected override void OnStart(
string[] args)
•
OnStop.
Chamado quando o serviço pára.
protected override void OnStop()
9.4.2.2. Classe AsyncDispatcher
A classe AsyncDispatcher é uma classe usada para instanciar o Processor.
public class AsyncDispatcher
9.4.2.2.1. Propriedades da classe AsyncDispatcher
André Coutinho
68
Microsoft .NET – Application Blocks
•
AsyncProcessor.
Obtém o Processor, do AsyncDispatcher.
public Processor AsyncProcessor {get;}
•
Dispatcher.
Obtém a instância única da classe.
public static AsyncDispatcher Dispatcher {get;}
9.4.2.3. Classe Processor
Classe que serve para criar e adicionar objectos ServiceAgentReqDetails à
pool de threads, e arrancar o Service Agent Monitor.
public class Processor
9.4.2.3.1. Métodos da classe Processor
•
ExecuteServiceAgent.
ServiceAgentReqDetails.
Executa
um
objecto
public void ExecuteServiceAgent()
•
RefreshCache. Apaga os dados actuais da tabela de hash e actualiza-a
com os dados mais recentes da base de dados.
public void RefreshCache
9.4.2.4. Classe ServiceAgentReqDetails
Esta classe armazena os detalhes dos Service Agent.
public class ServiceAgentReqDetails
9.4.2.4.1. Construtor público da classe ServiceAgentReqDetails
•
ServiceAgentReqDetails.
Construtor público da classe.
public ServiceAgentReqDetails(
string requestID,
string serviceAgentID,
int timeToLive,
int retryCount,
string referenceKey,
object[] inputParams,
string assemblyPath,
string className)
9.4.2.4.2. Métodos da classe ServiceAgentReqDetails
•
UpdateFinishTime.
Actualiza o tempo de término para um Service
Agent.
André Coutinho
69
Microsoft .NET – Application Blocks
public void UpdateFinishTime()
9.4.2.4.3. Propriedades da classe ServiceAgentReqDetails
•
AssemblyPath.
Obtém o caminho da assembly para o Service Agent.
public string AssemblyPath{get;}
•
ClassName.
Obtém o nome da classe do Service Agent.
public string ClassName{get;}
•
CurrentRetryCount.
Obtém ou altera o número de retries do Service
Agent.
public int CurrentRetryCount{get; set;}
•
FinishTime.
Obtém o tempo de término do Service Agent.
public DateTime FinishTime {get;}
•
InputParams.
Obtém o objecto InputParams.
public object[] InputParams {get;}
•
ReferenceKey.
Obtém a reference key do Service Agent.
public string ReferenceKey {get;}
•
RequestID. Obtém o RequestID do pedido que está a ser tratado pelo
Service Agent.
public string RequestID {get;}
•
ServiceAgentID.
Obtém o ServiceAgentID do Service Agent.
public string ServiceAgentID {get;}
•
State.
Obtém ou altera o estado do Service Agent.
public ServiceAgentStatus State {get; set;}
9.4.2.5. Classe ResultManager
A classe ResultManager é utilizada para obter o estado dos pedidos e resultados.
public sealed class ResultsManager
9.4.2.5.1. Métodos da classe ResultManager
André Coutinho
70
Microsoft .NET – Application Blocks
•
CancelRequest.
Actualiza
MarkedForDeletion.
o
estado
de
um
pedido
para
public static void CancelRequest(
string requestID)
•
ClearResults.
Actualiza o estado de um pedido para ToBeCleared.
public static void ClearResults(
string requestID)
•
GetIncrementedResults.
Obtém os resultados não lidos para o
requestID e reference key passados.
public static InvocationResult GetIncrementalResults(
string requestID)
•
GetRequestStatus.
Obtém o estado do pedido, para o requestID
passado.
public static RequestStatus GetRequestStatus(
string requestID)
•
GetResultCompletionStatus.
Devolve “Pending” ou “Completed”,
conforme o pedido esteja terminado ou não.
public
static
GetResultCompletionStatus(
string requestID)
•
ResultCompletionStatus
GetResults.
Obtém os resultados lidos/não lidos para o requestID e
reference key passados.
public static InvocationResult GetResults(
string requestID)
9.4.3. O subsistema Monitor
O Recovery Monitor corre em intervalos regulares para monitorizar a execução
dos Service Agents e determinar se algum terá excedido o seu tempo de vida. Se
um Service Agent excedeu o seu número de retries, é marcado como Failed na
base de dados. O Monitor também procura Service Agents que estão como
MarkedForDeletion e pára as suas threads.
Se houver uma falha no servidor, o Processor nessa máquina volta a ler a base
de dados quando reinicia. Se um qualquer service request está à espera de ser
processado, será então carregado e processado.
O Recovery Monitor também verifica os pedidos em estado Executing
quando o tempo de execução excedeu o CompletedTimetoLive do pedido, e
não foi marcado como Failed. Se existirem pedidos nestas condições o pedido
reinicia.
O garbage collection apaga os objectos Request da base de dados depois do seu
tempo de vida expirar, ou quando o status é MarkedForDeletion.
André Coutinho
71
Microsoft .NET – Application Blocks
9.4.3.1. Classe RecoveryMonitor
Esta classe é usada para resubmeter Service Agents que estão em execução para
além do seu tempo de vida.
public class RecoveryMonitor
9.4.3.1.1. Construtor da classe RecoveryMonitor
•
RecoveryMonitor.
Construtor da classe.
public RecoveryMonitor
9.4.3.1.2. Métodos da classe RecoveryMonitor
•
StopTimer.
Liberta todos os recursos usados pelo RecoveryMonitor.
public void StopTimer()
9.4.3.2. Classe GarbageCollection
A classe GarbageCollection é utilizada para apagar detalhes de um pedido,
que estejam marcados para remoção, ou para pedidos já expirados.
public class GarbageCollection
9.4.3.2.1. Construtor da classe GarbageCollection
•
GarbageCollector.
GarbageCollect.
Activa
o
timer
que
invoca
o
método
public GarbageCollector
9.4.3.2.2. Métodos da classe GarbageCollection
•
StopTimer.
Liberta todos os recursos usados pelo GarbageCollector.
public void StopTimer
9.4.4. Design da base de dados
André Coutinho
72
Microsoft .NET – Application Blocks
A Figura seguinte ilustra a base de dados SQL Server 2000 usada pelo AIAB.
Figura 16: Base de dados usada pelo AIAB
9.4.5. Ficheiros de configuração
O AIAB usa três ficheiros App.config para configurar o acesso à base de dados,
o intervalo de tempo de serviços como o Garbage Collection e a recuperação de
Service Agents, tamanho da pool de threads, entre outros.
Antes de se proceder a qualquer configuração. Só após as alterações se pode
reiniciar o serviço.
A seguir descrevem-se os três ficheiros de configuração usados pelo AIAB.
MonitorService App.config
•
•
•
•
ConnectionString. Especifica a base de dados e permissões de acesso
para o SQL Server 2000.
AsyncGarbageCollectorTimeInterval. Especifica o intervalo de
tempo (em milisegundos) usado para o Garbage Collector.
AsyncRecoveryMonitorTimeInterval. Especifica o intervalo de
tempo (em milisegundos) do timer do recovery service.
MaxNoofRequestsForGC. Especifica o número máximo de pedidos que
o Garbage Collector irá apagar quando é chamado.
André Coutinho
73
Microsoft .NET – Application Blocks
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<appSettings>
<!-- DATABASE SETTING
Use ConnectionString key to specify the database
used for Asynchronous Framework Application Block
and to set database related access permissions
-->
<add key="ConnectionString" value="Data
Source=localhost;Initial
Catalog=AsynchronousFramework;Integrated Security=SSPI" />
<!-- GARBAGE COLLECTOR SETTING
Use AsyncGarbageCollectorTimeInterval key to specify
the time interval(in msecs) of the timer
used for garbage collecor service of
AsynchronousInvocation Framework Application Block
-->
<add key="AsyncGarbageCollectorTimeInterval" value="10000"
/>
<!-- RECOVERY MONITOR SETTING
Use AsyncRecoveryMonitorTimeInterval key to specify
the time interval(in msecs) of the timer
used for recovery service of AsynchronousInvocation
Framework Application Block
-->
<add key="AsyncRecoveryMonitorTimeInterval" value="10000"
/>
<!-- GARBAGE COLLECTOR SETTING
Use MaxNoofRequestsForGC key to specify the number
of requests to be garbage collected
in a single run by the garbage collector service of
Asynchronous Framework Application Block
-->
<add key="MaxNoofRequestsForGC" value="10" />
</appSettings>
</configuration>
ROHService App.config
•
•
•
•
ConnectionString.
Especifica a base de dados e permissões de acesso
para o SQL Server 2000.
AsyncThreadPoolSize. Especifica o número de threads na pool de
threads. É possível ajustar este número de acordo com o número de
Service Agents a processar.
AsyncMinimumNoOfFreeThreads. Especifica o número mínimo de
threads disponíveis.
AsyncReCheckTimeInterval. Especifica o tempo (em milisegundos)
para o Dispatcher. É feito um Sleep antes de verificar o número
mínimo de threads disponíveis para a execução de Service Agents.
André Coutinho
74
Microsoft .NET – Application Blocks
•
•
•
•
AsyncServiceAgentQueueSize.
Especifica o tamanhoda fila de
Service Agents na pool de threads.
AsyncSAMonitorTimeInterval. Especifica o intervalo de tempo (em
milisegundos) do timer usado pelo Service Agent Monitor.
CommandRefreshCache. Especifica o valor (inteiro) para o comando
customizado refrescar os dados SQL do Service Agent Master na cache
do ROHService.
MachineID. Especifica o machine ID no qual o ROHService está a
correr. Se o ROHService está instalado em várias máquinas para loadbalancing, este valor tem que ser único.
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<appSettings>
<!-- DATABASE SETTING
Use ConnectionString key to specify the database
used for Asynchronous Framework Application Block
and to set database related access permissions
-->
<add key="ConnectionString" value="Data
Source=localhost;Initial
Catalog=AsynchronousFramework;Integrated Security=SSPI" />
<!-- THREAD POOL SIZE SETTING
Use AsyncThreadPoolSize key to specify number of
threads of the
thread pool of Asynchronous Framework Application
Block
-->
<add key="AsyncThreadPoolSize" value="10" />
<!-- THRESHOLD SETTING
Use AsyncMinimumNoOfFreeThreads key to specify
minimum number of threads free in the
thread pool of Asynchronous Framework Application
Block
-->
<add key="AsyncMinimumNoOfFreeThreads" value="5" />
<!-- DISPATCHER SLEEP TIME SETTING
Use AsyncReCheckTimeInterval key to specify the
sleep time(in msecs) for Dispatcher
subsystem of AsynchronousInvocation Framework
Application Block. This sleep time is
used before checking for minimum number of free
threads available for service agent
execution.
-->
<add key="AsyncReCheckTimeInterval" value="3000" />
<!-- SERVICE AGENT QUEUE SIZE SETTING
Use AsyncServiceAgentQueueSize key to specify the
size of the service agent queue
of the thread pool of Asynchronous Framework
Application Block
-->
<add key="AsyncServiceAgentQueueSize" value="20" />
André Coutinho
75
Microsoft .NET – Application Blocks
<!-- SERVICE AGENT MONITOR SETTING
Use AsyncSAMonitorTimeInterval
time interval(in msecs) of the
used for service agent monitor
Framework Application Block
-->
<add key="AsyncSAMonitorTimeInterval"
key to specify the
timer
of Asynchronous
value="10000" />
<!-- CUSTOM COMMAND SETTING
Use COMMAND_REFRESH_CACHE key to specify the integer
value for the
custom command for refreshing the ServiceAgentMaster
data in the cache
of the remote object host windows service.
-->
<add key="CommandRefreshCache" value="128" />
<!-- MACHINE SETTING
Use MachineId key to specify the machine id in which
the dispatcher service
is running. This is an integer value.
-->
<add key="MachineId" value="1" />
</appSettings>
</configuration>
SolutionItem App.config
•
ConnectionString. Especifica a base de dados e permissões de acesso
para o SQL Server 2000.
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<appSettings>
<!-- DATABASE SETTING
Use ConnectionString key to specify the database
used for Asynchronous Framework Application Block
and to set database related access permissions
-->
<add key="ConnectionString" value="user
id=sa;password=sa;Network=DBMSSOCN;DATABASE=AsyncDatabase;S
ERVER=ÜsyncServer" />
</appSettings>
</configuration>
André Coutinho
76
Microsoft .NET – Application Blocks
10. User Interface Process Application Block
10.1. Introdução
A maioria das aplicações requer algum tipo de controlo do processo de
interacção com o utilizador, quer seja a mudança de uma página Web para outra,
ou controlar o fluxo entre os forms de uma aplicação de tipo Wizard.
Normalmente o código para controlar o processo de interacção com o utilizador
(UIP) é escrito na própria camada de interacção com o utilizador. Esta prática
não facilita a reutilização de código, manutenção e extensibilidade.
À medida que as aplicações crescem em complexidade é útil introduzir um
interface de interacção com o utilizador, que resolva os seguintes pontos:
• Gestão do fluxo de controlo. O que os utilizadores vêem e o que são
capazes de fazer, depende do estado de uma aplicação. Codificar esta
lógica directamente na camada de interacção com o utilizador vai
complicar a manutenção e reutilizaçã do código.
• Gestão do estado. A interacção do utilizador com uma aplicação pode
ser vista como uma conversa, com um estado associado. Será importante
gerir o estado (da “conversa”) separadamente do estado operacional da
aplicação.
• Separação da lógica. A lógica que controla o fluxo e estado deve ser
separada da lógica dos pedidos de informação dos utilizadores.
• Encapsulamento do fluxo de contrlo e estado para um use case
específico. Um use case é uma unidade lógica de trabalho. O
encapsulamento de um use case resulta na possível reutilização de
mesmo use case.
O User Interface Process Application Block (UIPAB) foi criado para resolver os
pontos acima descritos e permite escrever facilmente interfaces para o utilizador
e processos de workflow, reusáveis e extensíveis.
Especificamente o UIPAB ajuda a:
• Separar o fluxo de controlo das páginas e forms, com que o utilizador
interage.
• Abstrair a gestão do estado de um use case, dos forms e controlos que
trabalham com esses mesmos dados.
• Usar o mesmo modelo de programação para o código que gere o fluxo de
controlo e estado para diferentes tipos de aplicação, incluindo aplicações
baseadas em Windows e aplicações Web, por exemplo.
• Escrever aplicações capazes de gerir as tarefas do utilizador em cenários
complexos, por exemplo, reatribuir tarefas a diferentes utilizadores ou
permitir que os utilizadores retomem tarefas interrompidas.
10.2. Descrição da solução
O UIPAB é baseado no modelo MVC (model-view-controller) que fornece uma
forma para organizar sistemas que suportam múltiplas formas de apresentar os
mesmos dados. Este modelo separa o processo de interface com o utilizador em
três objectos diferentes:
André Coutinho
77
Microsoft .NET – Application Blocks
•
•
•
Model. Este objecto conhece todos os pormenores dos dados a serem
mostrados. Pode ser visto como a parte de processamento de um sistema
do tipo input-process-output.
View. Os views são usados para gerir a informação a ser mostrada aos
utilizadores. É possível usar vários views para mostrar a mesma
informação de diferentes formas. Pode ser visto como a parte de output
de um sistema do tipo input-process-output.
Controller. É usado para permitir que o utilizador interaja com a
aplicação. Recebe o input do utilizador e passa instruções ao modelo.
Pode ser visto como a parte de input de um sistema do tipo inputprocess-output.
Figura 17: Funcionamento do Controller
10.3. Classes Factory
A criação dos principais objectos no UIPAB usa o padrão factory, o que resulta
no código de criação do objectos entralizado.
Problema
Todos os tipos de objectos a serem usados numa aplicação UIPAB estão
identificados na configuração da aplicação. O código para criar cada uma destas
classes encontra-se duplicado por todo o código de criação de objectos.
André Coutinho
78
Microsoft .NET – Application Blocks
Solução
Para reduzir a duplicação de código e melhorar a manutenção deste, o código de
criação de objectos é centralizado na classe GenericFactory, e é chamado para
cada tipo específico.
10.3.1. Classe GenericFactory
Esta classe é uma classe abstracta que fornece métodos para a criação de
diferentes tipos de objectos. A classe GenericFactory centraliza todo o código
de activação de objectos num único sítio, portanto todas as mudanças feitas a
esse código só precisarão de ser feitas uma vez. Porque só é usada dentro do
UIPAB está declarada, esta classe, como sealed class.
10.3.1.1. Métodos da classe GenericFactory
A classe fornece dois overloads do método Create que carregam a assembly
apropriada, baseando-se nos parâmetros passados ao método. Os overloads deste
método suportam diferentes parâmetros, portanto é possível decidir como o
assembly name e argumentos são passados.
10.3.2. Classe ControllerFactory
A classe ControllerFactory é utilizada para criar uma instância da classe
ControllerBase e devolvê-la ao código que a chamou. Usa o método
GenericFactory.Create que contém o código usado para a sua activação. Foi
desenhada para ser unicamente usada pelas outras classes do UIPAB, e como tal,
está declarada como internal.
10.3.2.1. Métodos da classe ControllerFactory
Esta classe contém um overload do método Create, que cria e devolve uma
instância da classe ControllerBase à função que chamou o método.
10.3.3. Classe StatePersistenceFactory
Classe usada para criar uma instância de uma implementação da interface
A implementação a ser usada é identificada no ficheiro de
configuração da aplicação.
IStatePersistence.
André Coutinho
79
Microsoft .NET – Application Blocks
11. Conclusão
O estudo feito sobre os application blocks apresentado neste trabalho teve como
objectivo, não só a exposição das suas classes, métodos, interfaces e
propriedades mais importantes, documentando esta tecnologia, mas fazer uma
avaliação de como tirar partido das capacidades de cada um, para integração em
aplicações reais.
Os cenários de utilização incluídos neste documento, mostram exemplos de
como a integração em aplicações poderá ser feita, ou de como é possível tirar
partido das capacidades dos application blocks.
No caso do DAAB as suas capacidades de acesso e gestão de dados, tais como, a
execução de Stored Procedures e comandos SQL, por exemplo, ou ainda a
manipulação de Datasets, podem ser utilizadas em aplicações de comércio
electrónico.
O encapsulamento dos métodos mais comuns de acesso a dados permitem um
desenvolvimento mais rápido das aplicações, uma vez que este tipo de
aplicações requer a execução de updates a bases de dados, na gestão de clientes
e produtos, por exemplo.
Quanto ao LAB, este application block, facilita a implementação dos cenários
mais comuns de logging, sendo portanto de grande utilidade a quase todo o tipo
de aplicações existentes nos nossos dias.
A gestão das excepções de logging deve ser feita de forma eficiente e
consistente. Como tal, em conjunto com o LAB deverá ser usado o EMAB, que
aumenta a robustez e facilita a depuração do código de uma aplicação, graças à
encapsulação que faz dos métodos mais comuns de gestão das excepções de
logging. A sua flexibilidade permite configurar as suas funcionalidades usando
um simples ficheiro .NET XML.
A utilidade do CMAB também é muito diversificada, uma vez que todos os tipos
de aplicações, de alguma forma, adquirem, gerem e/ou armazenam informação.
Este application block proporciona uma solução simples e flexível para a
configuração de dados e aplicações.
O UAB segundo o estudo realizado neste projecto poderá ser utilizado em
organizações de média e grande dimensão, nomeadamente na actualização
automática de todos os desktops ligados à rede da empresa.
No que toca ao AAB, este applicaton block poderá ser usado em aplicações
Web, nomeadamente em cenários onde a agregação de informação é necessária.
Uma vez que a informação requerida pelos clientes pode ter diversas fontes, o
AAB permite a fácil manutenção e junção de informação de vários Service
Providers.
O AAB incorpora o EMAB para o tratamento de excepções e pode ser usado
com o AIAB e o CAB.
O AIAB gere as comunicações assíncronas entre um cliente e um ou mais
Foreign Service Providers.
Quanto ao UIPAB, facilita o controlo do processo de interacção com o
utilizador, podendo ser usado em aplicações Web e do tipo Wizard,
nomeadamente para separar o fluxo de controlo das páginas e forms com que o
utilizador interage, e para escrever aplicações capazes de gerir as tarefas do
utilizador em cenários complexos, por exemplo.
André Coutinho
80
Microsoft .NET – Application Blocks
Apesar de existir espaço para melhoramentos, concretamente na implementação
de uma aplicação exemplo que demonstrasse na prática cada um dos application
blocks em funcionamento, integrados na referida aplicação. Para terminar
considerou-se o trabalho concluído satisfatoriamente, tendo sido compreendidos
os objectivos desta tecnologia da MicroSoft, e como podem ser usados na escrita
de aplicações.
André Coutinho
81
Microsoft .NET – Application Blocks
12. Bibliografia
http://aspnet.4guysfromrolla.com/articles/062503-1.aspx - Introdução ao Data
Access Application Block.
http://aspnet.4guysfromrolla.com/articles/070203-1.aspx - Exemplos das
vantagens do Data Access Application Block.
http://msdn.microsoft.com/library/default.asp?url=/library/enus/dnbda/html/daab-rm.asp - Documentação da Microsoft sobre o Data Access
Application Block.
http://builder.com.com/5100-6373-5054665.html - Exemplos de alguns métodos
do Data Access Application Block.
DAAB.chm – Documentação do Data Access Application Block, fornecida com
o código do application block.
http://scarecrow.fmrp.usp.br/~mavcunha/public/anti-patterns.php - Problemas de
programação.
http://www.dca.fee.unicamp.br/courses/POOCPP/node37.html - Sobre a
encapsulação.
http://www.clarionmag.com/col/98-03-reuse.html - Vantagens da programação
orientada a objectos e reutilização de código.
http://www.clarionmag.com/col/97-07-reusablecode.html - Vantagens da
reutilização de código.
http://msdn.microsoft.com/library/default.asp?url=/library/enus/dnpag/html/logging-ch01.asp - Documentação da Microsoft sobre o Logging
Application Block.
Logging Block.chm - DAAB.chm – Documentação do Logging Application
Block, fornecida com o código do application block.
http://msdn.microsoft.com/library/default.asp?url=/library/enus/dnbda/html/cmab.asp - Documentação da Microsoft sobre o Configuration
Management Application Block.
CMAB.chm - DAAB.chm – Documentação do Configuration Management
Application Block, fornecida com o código do application block.
http://msdn.microsoft.com/library/default.asp?url=/library/enus/dnpag/html/CachingBlock.asp - Documentação da Microsoft sobre o Caching
Application Block.
Cache.chm - DAAB.chm – Documentação do Caching Application Block,
fornecida com o código do application block.
http://msdn.microsoft.com/library/default.asp?url=/library/enus/dnpag/html/PAIBlock.asp - Documentação da Microsoft sobre o
Asynchronous Invocation Application Block.
Asyn.chm - DAAB.chm – Documentação do Asynchronous Invocation
Application Block, fornecida com o código do application block.
http://msdn.microsoft.com/library/default.asp?url=/library/enus/dnpag/html/ServiceAgg.asp - Documentação da Microsoft sobre o
Aggregation Application Block.
Aggregation.chm - DAAB.chm – Documentação do Aggregation Application
Block, fornecida com o código do application block.
http://msdn.microsoft.com/library/default.asp?url=/library/enus/dnbda/html/uip.asp - Documentação da Microsoft sobre o User Interface
Process Application Block.
André Coutinho
82
Microsoft .NET – Application Blocks
UIPAB.chm - Documentação do User Interface Process Application Block,
fornecida com o código do application block.
EMAB.chm - DAAB.chm – Documentação do Exception Management
Application Block, fornecida com o código do application block.
http://msdn.microsoft.com/library/default.asp?url=/library/enus/dnbda/html/updater.asp - Documentação da Microsoft sobre o User Interface
Process Application Block.
UAB.chm - Documentação do Updater Application Block, fornecida com o
código do application block.
André Coutinho
83
Download

Microsoft .NET Application Blocks Departamento de Engenharia