Desenvolvimento - Visual Basic .NET
Aplicações Distribuídas com Visual Basic.NET
Entenda como funcionam as aplicações distribuídas no .NET Framework. Neste artigo você aprenderá como criar e consumir um componente através das tecnologias Enterprise Services, XML WebServices e .NET Remoting.
por Carlos de MattosVou assumir que você está familiarizado com os conceitos de aplicações COM+. Provavelmente já desenvolveu (ou está planejando desenvolver) aplicações distribuídas utilizando o Visual Basic .NET. O COM+ oferece muitos recursos importantes para proporcionar às aplicações corporativas maior robustez, escalabilidade e ainda aumentar a produtividade da equipe de desenvolvimento na medida em que os componentes são reutilizados. Funcionalidades como gerenciamento de transações, comunicação assíncrona (com o MSMQ) e segurança integrada são apenas algumas das razões para você utilizar o COM+ para publicar seus componentes. Um dos pontos fortes do COM+, o qual ganhou a atenção dos desenvolvedores corporativos, é a facilidade com a qual você pode modificar o comportamento de um componente sem escrever uma única linha de código. Por exemplo, você pode criar um componente com uma estrutura simples, implementar métodos para manipulação de tabelas de um banco de dados, sem se preocupar em codificar as transações, e depois torná-lo transacional com apenas alguns cliques de mouse na janela de propriedades do componente como mostra a Figura 1.
Figura 1: Janela de propriedades do componente COM+
No ambiente .NET Framework, você poderá utilizar todas as funcionalidades do COM+ já conhecidas, assim como os novos serviços oferecidos pelo namespace System.EnterpriseServices. Então, se você está pensando em escrever uma aplicação que tenha que executar tarefas como participar de transações, desfrutar dos recursos de segurança integrada, interagir com um objeto queue, com certeza você utilizará os serviços do Component Services oferecido pelo .NET Framework. Você acompanhará neste artigo a implementação de um componente com funcionalidades para manipular dois bancos de dados do SQL Server simultâneamente e verá três formas diferentes para consumir este componente: Direct Call, XML WebService e .NET Remoting.
A evolução: do COM ao System.EnterpriseServices
É importante esclarecer as diferenças entre as tecnologias COM, COM+ e .NET Enterprise Services. Numa análise rápida, poderíamos dizer que o COM+ é uma nova versão do COM e que o namespace EnterpriseServices é basicamente uma versão atualizada do COM+ para o ambiente .NET Framework.
De vários pontos de vista isto é verdade. Contudo, durante a primeira fase desta evolução, referir-nos ao COM+, como uma nova versão do COM não seria adequado. Os objetos COM eram implementados com o auxílio do add-on criado para o Windows NT 4.0, o Microsoft Transaction Server (MTS). O COM+ por sua vez, oferece todos os recursos do MTS e muito mais. Além disso, ele está totalmente integrado na estrutura dos sistemas operacionais Windows 2000 e Windows XP.
Da mesma forma, em tempos de .NET, referir-nos ao namespace Enterprise Services como uma versão atualizada do COM+ não seria correto e poderia levar o desenvolvedor a acreditar que deveria continuar utilizando o COM+ exatamente da mesma forma como fazíamos com os objetos COM no MTS, apenas com um nome diferente. O namespace Enterprise Services oferece todas as funcionalidades do COM+ e muitas outras classes que implementam recursos específicos destinados ao ambiente .NET Framework para o qual ele foi concebido.
É correto afirmarmos que os componentes escritos para o .NET usando o namespace Enterprise Services podem ser executados no ambiente COM+ com Windows 2000 ou Windows XP, mas não podem ser executados no MTS.
Os serviços oferecidos pelo namespace EnterpriseServices
O namespace Enterprise Services provê uma variedade de serviços e recursos específicos que devem ser avaliados individualmente para verificar se são realmente necessários à sua aplicação. Os serviços e recursos oferecidos pelo namespace Enterprise Services são poderosos e, em muitos casos, podem reduzir significativamente a quantidade de código necessária para a implementação do componente. Entretanto, os serviços e recursos deste namespace devem ser utilizados apenas quando estritamente necessários à sua aplicação. A Tabela 1 apresenta uma lista dos serviços básicos encontrados no namespace Enterprise Services.
Serviço ou Recurso | Descrição | Usar ou não usar |
2-phase transactional protection | Quando atualizando dois ou mais bancos de dados, este serviço provê gerenciamento protegido de transações para as atualizações. Não é requerido para atualização de um único banco de dados (mesmo quando falamos de várias tabelas num único banco de dados). | Use este recurso se você tem dois ou mais bancos de dados para atualizar de forma transacional. Use este recurso se você não quer se preocupar com a codificação de um gerenciamento de transações. Ele simplificará seu código.Evite utilizá-lo se você está atualizando um único banco de dados e não está criando componentes de dados reutilizáveis que podem ser chamados a partir de outras configurações. |
Just-In-Time (JIT) Activation | Cria seu objeto para server à um único método específico e destrói o objeto quando o método for completado | Use este recurso apenas se você já estiver usando o namespace EnterpriseServices para outras finalidades.Você pode conseguir a mesma funcionalidade com XML WebServices e .NET Remoting utilizando o objeto Singlecall. |
Object construction string | Se o seu componente de uma única configuração em formato String você pode conseguir através deste recurso. | Use este recurso apenas se você já estiver usando o namespace EnterpriseServices para outras finalidades.Você pode utilizar o arquivo de configurações da aplicação para a mesma finalidade. |
Object pooling | Se você precisa criar um pool de objetos e estabelecer um número mínimo e máximo para esses objetos, utilize este recurso. | Use somente se você precisar de um conjunto de objetos idênticos previamente carregados.Use se você precisa monitorar o número de objetos carregados a qualquer momento.Se você precisa trabalhar apenas com um único componente, consulte a opção Singleton no .NET Remoting. |
Queued components | Este recurso permite ao desenvolvedor implementar código cliente para invocar métodos de um objeto e fazer com que todas essas chamadas sejam gravadas, enfileiradas, e depois serem re-executadas pelo objeto original em qualquer momento no futuro.Queued components são poderosos e oferecem um gerenciamento de chamadas eficiente e transportam as informações de segurança e identificação do cliente para o objeto automaticamente. | Use este recurso se você deseja implementar um ambiente assíncrono para sua aplicação.Use se você precisa de um gerenciamento eficiente de mensagens entre o cliente e o objeto servidor (message retry, dead message).Se você procura apenas o enfileiramento de mensagens entre o cliente e o objeto servidor, consulte o namespace System.Messaging. |
Role-based security | Permite ao desenvolvedor controlar o acesso aos seus componentes baseado na identificação do cliente que invocou o objeto e todo o contexto no qual ele está inserido.Observe que a implementação do CLR role-based security não pode transportar as informações de identificação e segurança através do TCP Remoting channel, e exige trabalho extra para transportar essas informações através do HTTP channel. | Utilize este recurso se você está implementando um componente de middle-tier que precisa ser executado sob uma conta específica de usuário.Use este recurso quando você quer controlar a segurança da middle-tier de forma integrada.Use este recurso quando você precisar transportar informações de identificação e segurança através da camada middle-tier. |
SOAP services | Este recurso permite ao desenvolvedor expor um componente como um XML WebService através do COM+.Este recurso utiliza o .NET Runtime para expor a aplicação COM+ através do protocolo SOAP e provê acesso eficiente aos componentes executados no COM+. | Use este recurso apenas se você já estiver usando o namespace EnterpriseServices para outras finalidades e deseja que seu componente esteja disponível através do protocolo SOAP. |
Synchronization | Controla automaticamente como uma aplicação com múltiplas threads acessará seu componente. | Use se você deseja garantir que apenas uma thread que faça parte do contexto possa invocar os métodos disponíveis no objeto COM+.Este recurso não é necessário na maioria dos cenários de aplicaçãos WebServices, JIT-activation ou Remoting. |
Tabela 1: Serviços básicos oferecidos pelo namespace System.EnterpriseServices De todos os recursos apresentados na Tabela 1, certamente o 2-phase transactional support é o mais conhecido e utilizado. Contudo, a função principal deste recurso (suporte transacional para componentes que manipulam dois ou mais bancos de dados) é desprezada por boa parte dos desenvolvedores. Muitos acreditam que esse recurso representa a tecnologia adequada para oferecer suporte transacional a qualquer tipo de componente, e acabam utilizando-o para implementar suporte transacional para um componente que manipula um único banco de dados. Esta prática é inadequada, pois não podemos esquecer que existe um custo de performance associado à este recurso que deve ser considerado quando você estiver desenvolvendo componentes para um único banco de dados. É verdade que conseguir um gerenciamento de transações eficiente e com código simples é um atrativo para qualquer um, porém, considere a utilização de outros recursos existentes no .NET Framework que podem oferecer funcionalidades semelhantes. Veja a Tabela 2.
Recurso | Descrição |
Database connection pooling | Você pode usar ODBC, OleDB e os providers do ADO.NET para implementar connection pooling. O provider para o SQL Server disponível no ADO.NET possui um algoritmo altamente otimizado cuja performance é bastante superior a do ODBC e OleDB. |
Thread management | Este recurso pode ser implementado através do IIS, do ASP.NET e WebServices e através do .NET Remoting. |
Simple transactions | ADO.NET e Stored Procedures oferecem todos os recursos necessários para implementarmos gerenciamento de transações para atualizar múltiplas tabelas de um único banco de dados. |
Queued messaging | O namespace System.Messaging pode ser utilizado para manipular as funcionalidades básicas do Microsoft Message Queue (MSMQ). |
Tabela 2: Alternativas para o namespace EnterpriseServices
Implementando nosso componente com o Enterprise Services
Quando nós escrevemos um assembly para implementar um componente no ambiente .NET que utiliza o namespace Enterprise Services, estamos na verdade escrevendo uma aplicação COM+. Para que tudo funcione corretamente temos que obecer os conceitos de aplicações COM (Componente Object Model). O primeiro passo é criar um novo projeto no Visual Basic.NET chamado NorthwindServices utilizando o template Class Library, como mostra a Figura 2.
Figura 2: Janela "Novo Projeto" - Class Library
Antes de codificar nosso componente é imprescindível que o desenvolvedor faça a referência ao namespace Enterprise Services que será utilizado. Selecione o menu Project, em seguida Add Reference... e, na janela Add Reference que será exibida, selecione a guia .NET e localize a DLL System.EnterpriseServices como mostra a Figura 3. Certifique-se de selecionar esse item da lista e clique no botão OK para continuar.
Figura 3: A janela Add Reference
Configurando nosso componente
Os assemblies criados no .NET são inseridos no contexto das aplicações COM+ automaticamente (quando uma aplicação cliente criada no mesmo computador invoca esse assembly) ou com a utilização da ferramenta regsvcs.exe através do prompt de comando. Em ambos os casos, precisamos fazer algumas modificações para que o assembly seja carregado corretamente no contexto das aplicações COM+.
Todo projeto criado no Visual Basic.NET possui um arquivo de configurações chamado AssemblyInfo.vb. Este arquivo deverá ser modificado de acordo com as explicações a seguir. No topo do arquivo, adicione a linha para importar o namespace como mostra o Quadro 1.
Imports System Imports System.Reflection Imports System.Runtime.InteropServices Imports System.EnterpriseServices |
Quadro 1: AssemblyInfo.vb - Importando o namespace System.EnterpriseServices
Continuando com a configuração do nosso assembly devemos inserir outros três atributos ao nosso arquivo. O atributo ApplicationName que indicará o nome da aplicação COM+ que será criada para armazenar nosso componente. Caso já exista uma aplicação COM+ com o mesmo nome, nosso componente será inserido no mesmo contexto desta aplicação. O atributo Description oferece uma descrição resumida para o usuário do componente. Outro atributo importante é o ApplicationActivation que é utilizado apenas quando uma nova aplicação COM+ for criada para armazenar nosso componente. Neste caso, este atributo definirá se a nova aplicação será criada como Library Application ou Server Application. Se já existir uma aplicação com o nome indicado no atributo ApplicationName então o atributo ApplicationActivation não terá efeito. O Quadro 2 apresenta as linhas necessárias para inserir os atributos mencionados neste parágrafo. O leitor deve inserir essas linhas logo após as declarações de importação.
<Assembly: ApplicationName("NorthwindServices")> <Assembly: Description("Northwind Database Services")> <Assembly: ApplicationActivation(ActivationOption.Library)> |
Quadro 2: AssemblyInfo.vb - Adicionando atributos
Se você estiver criando um componente que será utilizado com o MSMQ deverá incluir a seguinte linha no arquivo AssemblyInfo.vb: <Assembly: ApplicationQueuing()>. Para cada recurso disponível no EnterpriseServices você pode encontrar uma referência específica que deverá ser incluida no arquivo de configurações da sua aplicação. Consulte o Help do .NET Framework SDK para obter maiores detalhes sobre os recursos e seus respectivos atributos. Criando um StrongName para seu assembly
Uma exigência para qualquer componente que será executado numa aplicação COM+ é possuir um StrongName que permita ao .NET Framework identificá-lo de forma única. O StrongName é formado pelo nome do assembly, número da versão e uma chave única de identificação da empresa que está publicando o componente. Algumas corporações possuem um Publisher Key que deve ser utilizado para gerar esta chave única. Caso sua empresa não possua esse Publisher Key, não se preocupe, você pode gerar uma chave de identificação única com o uso do utilitário sn.exe e apenas uma linha de comando. Abra o prompt de comando do Visual Studio.NET e digite: sn -k forum.snk. Isto resultará na criação de um arquivo com o nome forum.snk que armazenará uma chave única gerada pelo utilitário sn.exe. Uma vez criada a chave única, você deve incluir mais uma linha no arquivo AssemblyInfo.vb para associar esta chave ao assembly. Quando o assembly for compilado, a parte pública da chave gerada será adiconada automaticamente à biblioteca (DLL), atribuindo ao componente um StrongName que será utilizado pelo EnterpriseServices. O Quadro 3 mostra a linha que deve ser acrescentada no arquivo AssemblyInfo.vb.
<Assembly: ApplicationName("NorthwindServices")> <Assembly: Description("Northwind Database Services")> <Assembly: ApplicationActivation(ActivationOption.Library)> <Assembly: AssemblyKeyFile("<path>\forum.snk")> |
Quadro 3: AssemblyInfo.vb - StrongName
Nota importante: ao executar o utilitário sn.exe no prompt de comando, o arquivo contendo a StrongName será gerado na pasta atual. Certifique-se de indicar corretamente o path para o arquivo forum.snk no arquivo AssemblyInfo.vb.
Apenas para informação do leitor: se indicarmos somente o nome do arquivo, por exemplo: <Assembly: AssemblyKeyFile("forum.snk")>, o arquivo forum.snk deve ser colocado na pasta \obj\debug\ da aplicação, neste exemplo, o arquivo seria colocado na pasta NorthwindServices\obj\debug.
Permitindo a execução do componente através do ASP.NET
Para que nosso componente possa ser invocado a partir de uma página ASP.NET é necessário acrescentar outro atributo fundamental para que o IIS permita que o assembly seja executado. O atributo ApplicationAccessControl será utilizado para esta tarefa. Esta é uma das diferenças entreo .NET Framework 1.1 em relação a versão 1.0. Esta mudança teve como objetivo fortalecer a segurança das aplicações .NET através da Internet. O Quadro 4 apresenta as linhas que devem ser acrescentadas ao arquivo AssemblyInfo.vb.
"Controle de acesso ao componente através do ASP.NET <Assembly: ApplicationAccessControl(AccessChecksLevelOption.ApplicationComponent)> |
Quadro 4: AssemblyInfo.vb - ApplicationAccessControl
Conceitos de Herança aplicados ao componente
É fundamental explicarmos que qualquer classe que utilizará os recursos do namespace Enterprise Services deve ser derivada da classe System.EnterpriseServices.ServicedComponent, ou seja, a nova classe herdará todas as características da classe ServicedComponent. Para completarmos esta etapa, precisamos alterar o código do nosso arquivo Class1.vb como mostra o Quadro 5.
Imports System.EnterpriseServices Public Class SupplierService Inherits ServicedComponent End Class |
Quadro 5: Arquivo Class1.vb
Atributos de Classes
Com a herança da classe System.EnterpriseServices.ServicedComponent, nossa classe adquiri a habilidade necessária para utilizar os recursos disponíveis através do namespace Enterprise Services. Para estabelecermos quais os serviços específicos que nossa classe utilizará, precisamos definir os atributos dos métodos e procedimentos da nossa classe. A maioria dos serviços oferecidos pelo namespace Enterprise Services requer que um ou mais atributos sejam adicionados à nossa classe. Um dos atributos mais utilizados é o <EventTrackingEnabled()>. Este atributo permite que nosso componente seja monitorado através do console de gerenciamento (MMC) Component Services. Outros exemplos de atributos aplicados com freqüência são apresentados na Tabela 3.
Atributo | Finalidade |
<ObjectPooling(True, 10, 50)> | Este atributo ativa o recurso de Object Pooling. |
<Synchronization(SynchronizationOption.Required)> | Este atributo ativa o recurso de sincronização. |
Tabela 3: Atributos da Classe
Atributos dos Métodos
O desenvolvedor pode ainda implementar atributos associados aos métodos contidos na classe. Por exemplo, você pode utilizar o recurso de segurança integrada (role-based security) para proteger um método da classe. Veja o exemplo apresentado no Quadro 6.
<SecurityRole("Admin")> _ Public Sub DoSomething( ) |
Quadro 6: Exemplo de atributo associado à um método da classe
Codificando nosso componente
Neste exemplo, vamos utilizar o recurso mais comum do namespace Enterprise Services - 2-phase transactional support - para demonstrarmos como criar um componente com suporte transacional. Uma rotina comum às aplicações distribuídas é interagir com vários bancos de dados simultaneamente. Em algumas situações, o desenvolvedor precisa implementar componentes capazes de atualizar múltiplos bancos de dados num cenário transacional, uma tarefa nada fácil. A técnica utilizada para implementar componentes deste tipo é conhecida como 2-phase commit. Neste conceito, as atualizações são efetuadas em cada banco de dados envolvido na transação, porém, só serão efetivadas quando todos os bancos confirmarem a alteração.
Para implementarmos o suporte transacional em nosso componente, precisamos acrescentar o atributo correspondente a este serviço. Nesta altura, nosso arquivo Class1.vb deverá conter o código apresentado no Quadro 7.
Imports System.EnterpriseServices <Transaction(TransactionOption.Required), EventTrackingEnabled(True)> _ Public Class AuthorService Inherits ServicedComponent End Class |
Quadro 7: O código do arquivo Class1.vb
As opções disponíveis para o atributo Transaction são explicadas na Tabela 4.
Valor do atributo | Comportamento do componente no cenário transacional |
Disabled | O objeto será executado no contexto de outros componentes transacionais, porém, ele mesmo não participará de nenhuma transação. |
NotSupported | O objeto será executado num contexto isolado de qualquer componente transacional, não podendo participar de nenhuma transação. |
Required | O objeto será executado no contexto de uma transação existente ou uma nova transação será criada caso não exista nenhuma. |
RequiredNew | O objeto sempre será executado numa nova transação, mesmo que já exista outra. |
Supported | O objeto participará do contexto de uma transação existente ou será executado sem transação caso nenhuma exista. |
Tabela 4: Valores do atributo Transaction Entendendo o atributo <AutoComplete()>
Com as alterações já implementadas no arquivo Class1.vb, todos os métodos contidos nesta classe terão suporte transacional. Além disso, cada método pode ser associado ao atributo <AutoComplete()> para controlar como nosso código vai interagir com o ambiente COM+ para efetivar as transações. Este atributo pode apresentar dois valores: True ou False, como está apresentado na Tabela 5.
Valor do atributo | Comportamento da transação |
True | Quando <AutoComplete()> for igual a True, o sucesso ou falha do método ocorrerá quando ou não o método disparar um erro. Se um erro for disparado, a transação toda será cancelada. Se nenhum erro for disparado pelo método, a transação será efetivada assumindo que nenhum outro componente falhou durante o processo. |
False | Utilizando o valor False, o desenvolvedor terá que codificar os métodos do seu componente de forma a ter controle direto sobre o sucesso ou falha das transações. |
Tabela 5: O atributo <AutoComplete()>
Neste exemplo, utilizaremos o gerenciamento de transações automático, atribuindo o valor True para o atributo <AutoComplete()>. Apenas para ilustrar o gerenciamento manual das transações, apresentarei um fragmento de código de um componente hipotético que utiliza os métodos SetAbort e SetComplete para controlar manualmente suas transações. Estes métodos são providos pelo objeto ContextUtil que está disponível para todas as classes derivadas da classe ServicedComponent. Observe o código do Quadro 8.
<AutoComplete(False)> _ ... Public Sub UpdateName(ByVal au_id As String, ByVal lname As String) Dim cn As New SqlConnection(DB1) cn.Open() Dim cm As New SqlCommand() Try cm.CommandType = CommandType.Text cm.Connection = cn cm.CommandText = "UPDATE authors SET au_lname="" & lname & _ "" WHERE au_id="" & au_id & """ cm.ExecuteNonQuery() ContextUtil.SetComplete() Catch ContextUtil.SetAbort() Finally cm.Dispose() cn.Close() cn.Dispose() End Try End Sub ... |
Quadro 8: Fragmento de código utilizando o <AutoComplete(False)>
Northwind Suppliers Services
Continuando com a codificação do nosso componente de exemplo, utilizaremos o banco de dados Northwind do SQL Server, para implementar um procedimento que atualizará a tabela Suppliers. Para ilustrar o uso adequado do recurso 2-phase transactions (concebido para atualização de múltiplos bancos de dados), criei uma réplica do Northwind original com o nome de Northwind2, desta forma, nosso componente atualizará dois bancos de dados simultaneamente dentro de um cenário transacional. É óbvio que existem diversas abordagens para implementarmos componentes com essas características, a abordagem apresentada neste artigo é apenas uma delas. O Quadro 9 apresenta o código-fonte do nosso componente na sua íntegra, observe os atributos da classe e dos métodos. Após inserir o código, compile a solução através da opção Build Solution do menu Build.
Imports System.EnterpriseServices Imports System.Data.SqlClient <Transaction(TransactionOption.Required), EventTrackingEnabled(True)> _ Public Class SupplierService Inherits ServicedComponent Private Const nwind1 As String = _ "Data Source=localhost;User ID=sa;Password=;Initial Catalog=Northwind;" Private Const nwind2 As String = _ "Data Source=localhost;User ID=sa;Password=;Initial Catalog=Northwind2;" <AutoComplete(True)> _ Public Sub UpdateContactName(ByVal SupplierID As String, ByVal ContactName As String) UpdateNwind1(SupplierID, ContactName) UpdateNwind2(SupplierID, ContactName) End Sub Private Sub UpdateNwind1(ByVal SupplierID As String, ByVal ContactName As String) Dim cn As New SqlConnection(nwind1) cn.Open() Dim cm As New SqlCommand Try cm.CommandType = CommandType.Text cm.Connection = cn cm.CommandText = "UPDATE suppliers SET contactname="" & ContactName & _ "" WHERE supplierid="" & SupplierID & """ cm.ExecuteNonQuery() Finally cm.Dispose() cn.Close() cn.Dispose() End Try End Sub Private Sub UpdateNwind2(ByVal SupplierID As String, ByVal ContactName As String) Dim cn As New SqlConnection(nwind2) cn.Open() Dim cm As New SqlCommand Try cm.CommandType = CommandType.Text cm.Connection = cn cm.CommandText = "UPDATE suppliers SET contactname="" & ContactName & _ "" WHERE supplierid="" & SupplierID & """ cm.ExecuteNonQuery() Finally cm.Dispose() cn.Close() cn.Dispose() End Try End Sub End Class |
Quadro 9: O código do componente SupplierService na íntegra
Registrando nosso componente no COM+
Completada a fase de codificação do componente, precisamos criar uma aplicação COM+ e registrar o assembly para que as aplicações cliente possam invocar os métodos do nosso componente com sucesso. Esta tarefa deve ser feita manualmente, caso contrário a aplicação cliente (quando realizar uma chamada para o componente) tentará criar uma aplicação COM+ e registrar o assembly automaticamente, contudo, a segurança do Windows 2000/XP entrará em ação e não permitirá a instalação, provocando uma exception.
Lembram do utilitário regsvr32.exe? No .NET Framework temos o - regsvcs - um utilitário semelhante, utilizado para registrar as aplicações COM+. Mais uma vez utilizaremos o prompt de comando do Visual Studio.NET. Na janela do prompt, navegue até o diretório bin da sua aplicação e digite a linha de comando apresentada no Quadro 10.
regsvcs northwindservices.dll |
Quadro 10: Registrando a aplicação COM+ manualmente
Após executar este comando, você poderá abrir o snap-in Component Services, através do menu Ferramentas Administrativas, e visualizar a nova aplicação COM+ criada e com o nosso componente devidamente registrado, como mostra a Figura 4.
Figura 4: A janela do Component Services - Nossa aplicação COM+ devidamente registrada
Consumindo nossa aplicação COM+
O DCOM poderia ser utilizada para acessar nosso componente, tecnicamente isso é possível. Porém, para trabalharmos com o DCOM precisaríamos expor nossos objetos .NET através do COM Interop o que não seria adequado, a menos que estivéssemos implementando uma aplicação cliente com Visual Basic 6.0 ou ASP. Para acessarmos nossos componentes através de clientes .NET o mais adequado é utilizarmos as tecnologias nativas deste ambiente. Temos três opções: Direct Call, XML Web Services e .NET Remoting.
Direct Call
Esta tecnologia permite que uma aplicação cliente obtenha acesso direto ao componente desde que resida na mesma máquina. Isto não é útil se estivermos trabalhando com aplicações Windows Forms, contudo, aplicações ASP.NET são clientes ideais para esta tecnologia uma vez que essas aplicações são processadas no servidor (normalmente a mesma máquina onde residem os objetos). Para ilustrar o uso desta tecnologia, adicione um novo projeto à sua solução utilizando o template ASP.NET Web Application, chame-o de NorthwindAspNet. Altere o nome do WebForm1.aspx para UpdateContactName.aspx. Abra a janela Add Reference através do menu Project e certifique-se de selecionar a referência ao projeto NorthwindServices, como mostra a Figura 5.
Figura 5: Adicionando a referência ao projeto NorthwindServices
Uma vez completada esta etapa, vamos codificar nossa aplicação ASP.NET para acessar nosso componente através do COM+. Esta tarefa é bastante simples. Adicione ao WebForm os controles apresentados na Tabela 6 e posicione-os de acordo com a Figura 6.
Controle | Propriedade | Valor |
Label1 | Text | Supplier ID: |
Label2 | Text | Contact Name: |
TextBox | ID | TxtSupplierID |
TextBox | ID | txtContactName |
Button | ID | btnUpdateDatabases |
Text | Atualizar Bancos de Dados |
Tabela 6: Controles do WebForm UpdateContactName.aspx
Figura 6: A interface do WebForm UpdateContactName.aspx
No modo design do Visual Basic.NET, dê um duplo-clique no botão de comando btnUpdateDatabases e insira o código apresentado no Quadro 11. Compile a aplicação através da opção Build Solution do menu Build. Neste ponto sua aplicação poderá ser testada. Abra o Internet Explorer para acessar sua página ASP.NET e informe um número válido para o SupplierID (entre 1 e 29). Preencha o campo ContactName e pressione o botão Atualizar Bancos de Dados. Você ainda poderá confirmar a execução do seu componente através do snap-in Component Services.
Private Sub btnUpdateDatabases_Click( _ ByVal sender As System.Object, ByVal e As System.EventArgs) _ Handles btnUpdateDatabases.Click Dim objCOM As New NorthwindServices.SupplierService objCOM.UpdateContactName(txtSupplierID.Text, txtContactName.Text) End Sub |
Quadro 11: O código para invocar nosso componente
Utilizando o componente através de um XML Web Service Esta é outra abordagem que podemos utilizar para acessar nosso componente através da rede. Posso garantir ao leitor que é mais fácil do que parece. O conceito é bastante simples: precisamos de uma aplicação do tipo WebService que se encarregará de invocar nosso componente e uma aplicação cliente ASP.NET que utilizará o WebService para atualizar os bancos de dados. Acompanhe a seguir, os passos necessários para completar esta etapa.
Adicione um novo projeto à sua solução utilizando o template ASP.NET WebService e dê o nome de NorthwindWebService para esta aplicação. Altere o nome do WebService1.asmx para UpdateContactNameWS.asmx. Altere para o modo code view e modifique o nome da classe de WebService1 para UpdateContactNameWS. Mais uma vez, abra a janela Add Reference através do menu Project e certifique-se de selecionar a referência ao projeto NorthwindServices como já mostramos na Figura 5 deste artigo. Agora vá para o modo code-view e digite o código apresentado no Quadro 12.
<WebMethod()> _ Public Sub UpdateContactName(ByVal SupplierID As String, ByVal ContactName As String) Dim objCOM As New NorthwindServices.SupplierService objCOM.UpdateContactName(SupplierID, ContactName) End Sub |
Quadro 12: Código do WebService UpdateContactNameWS
Modificando a aplicação cliente NorthwindAspNet
Para testarmos a aplicação COM+ através do WebService, utilizaremos a mesma aplicação ASP.NET que criamos anteriormente, fazendo apenas algumas modificações necessárias. O primeiro passo é adicionar uma Web Reference que apontará para o WebService recém criado. Abra a janela Add Web Reference através do menu Project. Na barra de endereço que será exibida, digite: http://localhost/northwindwebservice/updatecontactnamews.asmx e clique no botão [GO]. O assistente para configuração da Web Reference localizará o Web Service indicado e exibirá uma mensagem de sucesso da operação, como mostra a Figura 7. Clique no botão Add Reference para finalizar esta operação.
Figura 7: Adicionando uma Web Reference ao projeto
Além da Web Reference, fundamental para que a aplicação de teste funcione corretamente, apenas a declaração do objeto no código da aplicação cliente deverá ser alterada. O Quadro 13 apresenta o código devidamente alterado. Após completar esta etapa, compile a solução mais uma vez, através da opção Build Solution do menu Build. Isto feito, o leitor já poderá executar sua aplicação novamente e verificar que o acesso ao componente é completado com sucesso.
Private Sub btnUpdateDatabases_Click( _ ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnUpdateDatabases.Click Dim objWebService As New localhost.UpdateContactNameWS objWebService.UpdateContactName(txtSupplierID.Text, txtContactName.Text) End Sub |
Quadro 13: Código da aplicação cliente para testar o WebService
Utilizando o .NET Remoting
Outra forma de acessarmos nosso componente remotamente é provida pelo .NET Remoting. Esta técnica permite duas abordagens diferentes: criar uma aplicação do tipo Windows Service ou utilizar um projeto ASP.NET como host da nossa aplicação. Para este artigo, vamos utilizar um projeto ASP.NET devido a sua facilidade na implementação.
Nota Importante: Esta etapa requer máxima atenção do leitor para os detalhes envolvidos na implementação.
Em primeiro lugar, adicione um projeto vazio (Empty Web Project) com o nome de NorthwindRemoting. Abra a janela Add References através do menu Project e certifique-se de selecionar a referência ao projeto NorthwindServices, como foi mostrado na Figura 5. Isto fará com que o componente NorthwindServices.dll seja compiado para a pasta bin desta aplicação, o que é necessário para que nós possamos expor este objeto através do .NET Remoting.
Para completar o próximo passo, selecione a opção Add New Item através do menu Project para adicionar um arquivo XML baseado no template Web Configuration File (Web.config) ao projeto. Abra este arquivo e adicione o fragmento de código apresentado no Quadro 14. Certifique-se que este código fique envolvido pelos tags <configuration> ... </configuration>, mas fora dos tags <system.web> ... </system.web>. Compile sua solução novamente.
<system.runtime.remoting> <application> <service> <wellknown mode="SingleCall" objectUri="SupplierService.rem" type="NorthwindServices.SupplierService, NorthwindServices" /> </service> </application> </system.runtime.remoting> |
Quadro 14: Código do arquivo Web.config
O tag <service> é a chave para que esta implementação funcione corretamente. A propriedade objectUri será utilizada para compor a URL que proverá o acesso ao componente através do .NET Remoting: http://localhost/NorthwindRemoting/SupplierService.rem.
Modificando a aplicação cliente para utilizar o .NET Remoting
A aplicação cliente (NorthwindAspNet) deverá ser modificada mais uma vez, para testarmos o acesso ao componente através do .NET Remoting. Vá para o modo code-view e altere o código associado ao botão btnUpdateDatabases de acordo com o Quadro 15.
Private Sub btnUpdateDatabases_Click( _ ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnUpdateDatabases.Click Dim objREM As New NorthwindServices.SupplierService objREM.UpdateContactName(txtSupplierID.Text, txtContactName.Text) End Sub |
Quadro 15: O código da aplicação cliente para acessar o .NET Remoting
Observe mais uma vez, que praticamente não houve alteração no código da aplicação cliente. Para que nossa aplicação cliente saiba que o componente NorthwindServices deve ser invocado remotamente e não em modo local, devemos alterar o arquivo Global.asax. A primeira alteração será a inclusão da declaração: Imports System.Runtime.Remoting. Certifique-se que esta declaração será incluida. Continuando com a edição do arquivo, acrescente o código apresentado no Quadro 16 ao procedimento Application_Start. Após concluir esta etapa, compile mais uma vez sua solução e realize os testes de acesso ao componente.
Sub Application_Start(ByVal sender As Object, ByVal e As EventArgs) RemotingConfiguration.RegisterWellKnownClientType( _ GetType(NorthwindServices.SupplierService), _ "http://localhost/NorthwindRemoting/SupplierService.rem") End Sub |
Quadro 16: Alterando o arquivo Global.asax
Assim como o WebService, o acesso através do .NET Remoting pode ser feito através da rede e firewalls sem problema algum. Comparado a abordagem utilizada com o WebService, o .NET Remoting oferece uma melhor performance, além de uma implementação mais simples.
Conclusão
Neste artigo você conheceu o conjunto de recursos oferecido pelo namespace Enterprise Services, e aprendeu como utilizá-los através de uma aplicação ASP.NET. O leitor pode acompanhar como criar um componente usando o Visual Basic.NET, registrar sua aplicação COM+ e como interagir com esta aplicação através das técnicas Direct Call, XML WebServices e .NET Remoting. As mesmas abordagens ilustradas neste artigo podem ser aplicadas às aplicações Windows Forms. Procure reproduzir os exemplos apresentados aqui. Crie seus próprios componentes. Pratique! Até a próxima oportunidade.
Livros:
Developer"s Guide to Upgrading to Microsoft .NET
Microsoft Press
Developing Web Applications with Microsoft Visual Basic.NET and Microsoft Visual C# .NET. (MCAD/MCSD - Self-Paced Training Kit)
Microsoft Press
Internet:
.NET Development
http://www.msdn.microsoft.com/nhp/default.asp?contentid=28000519
MSDN Library - Upgrading to Microsoft .NET
http://msdn.microsoft.com/net/upgrading
MSDN Library - System.EnterpriseServices
http://msdn.microsoft.com/library/en-us/cpref/html/frlrfSystemEnterpriseServices.asp
MSDN Library - Visual Basic .NET Adventures
http://www.msdn.microsoft.com/library/en-us/dv_vstechart/html/vstchColumns.asp
Carlos de Mattos
E-mail: carlos@quarteirao.net
MSN Messenger: mattos_carlos@hotmail.com
Microsoft Most Valuable Professional
Microsoft Certified Professional
Líder do Grupo de Usuários Quarteirão.NET
http://www.quarteirao.net
Colaborador da Revista Forum Access
Coordenador de TI do Colégio Universitário de Sorocaba
Professor de Linguagem de Programação e Tecnologias para Internet
- Entity Framework 4: Repositório GenéricoVisual Basic .NET
- As edições 14 da Easy .net Magazine e 88 da .net Magazine já estão disponíveis.ADO.NET
- Postando no Twiiter com .NET e Migre.meC#
- Setup ApplicationsVisual Basic .NET
- Problemas na manipulação de arquivos do MS Excel com .NETVisual Basic .NET