Detection of product '{0}', feature 'Base_And_Client', component '{1}' failed

Finalmente consegui resolver o problema que estava tendo com o Windows Installer e o COM+ de uma forma aceitável.

O Problema

O problema inicial foi quando criei um instalador, utilizando o InstallShield, para empacotar um aplicativo que utilizamos onde trabalho, que havia sido migrado de .NET 1.1 para .NET 2.0. Este aplicativo é composto de componentes .NET 1.1 (para manter a compatibilidade com versões de sistemas que usam esse runtime), .NET 2.0 com windows services e COM+ (também para manter compatibilidade).

A compatibilidade foi necessária para fazer com que os sistemas que utilizassem a versão em .NET 1.1 desse aplicativo pudessem passar a utilizar a nova, sem a necessidade de alterações em código. E para manter a compatibilidade, foi criado o pacote COM+ citado acima, para ser o divisor de águas entre os runtimes 1.1 e 2.0, permitindo as chamadas.

Quando este pacote foi instalado nos servidores de componentes, a cada chamada do aplicativo, eram logados os eventos abaixo, além de ter um pequeno atraso na execução do mesmo.



Detection of product '{3FAE8AAC-EA51-4060-8181-7FC647E5EC9E}', feature 'Base_And_Client', component '{5A249606-8811-4E9D-BF61-36E04087B112}' failed. The resource '' does not exist.

Detection of product '{3FAE8AAC-EA51-4060-8181-7FC647E5EC9E}', feature 'Base_And_Client' failed during request for component '{3E87C314-FFBB-4F7F-A52C-609189873BB3}'
O produto {3FAE8AAC-EA51-4060-8181-7FC647E5EC9E} é o aplicativo que foi migrado para .NET 2.0. O componente {3E87C314-FFBB-4F7F-A52C-609189873BB3} é o componente que fica no COM+, responsável por rotear as chamadas vindas do .NET 1.1 para .NET 2.0 e o componente {5A249606-8811-4E9D-BF61-36E04087B112} é o componente que fez a chamada ao componente do COM+. Ambos também são instalados no GAC.

Obs. Utilizar COM+ para fazer a interoperabilidade entre as versões do runtime do .NET talvez não tenha sido a melhor idéia. Poderia ter utilizado .NET Remoting ou mesmo Web Services para isso, mas esse questionamento fica para depois.

A Análise

Como introduzimos o instalador MSI para empacotar o aplicativo, minha desconfiança caiu sobre o Windows Installer. Após algumas pesquisas, descobri que existe uma funcionalidade no Windows Installer chamada “resiliency” (comentei sobre ela neste post http://galorebr.blogspot.com/2009/09/windows-installer-application.html). Basicamente ela restaura uma instalação caso um componente não seja encontrado.

Parecia que a CLR do .NET 1.1 não encontrava o componente COM+ em .NET 2.0, mesmo estando no GAC. Talvez isso seja porque existem diferenças de localização do GAC entre essas versões do runtime: a primeira coloca as dll’s em C:\WINDOWS\assembly\GAC, a segunda em C:\WINDOWS\assembly\GAC_MSIL.

Utilizando o Filemon (http://technet.microsoft.com/en-us/sysinternals/bb896642.aspx), não encontrei evidências de não se encontrar o arquivo.
A próxima análise foi utilizando o log do Fusion (http://blogs.msdn.com/suzcook/archive/2003/05/29/57120.aspx). Com isso, conseguimos identificar que o CLR tomava um capote quando tentava achar o componente do COM+. Um detalhe que percebemos é que o erro acontecia quando o sistema que chamava nosso aplicativo se encontrava no COM+ também (.NET 1.1). Um dos locais onde era pesquisada a existência da dll era o diretório C:\Windows\System32\.

Como o CLR não encontrava a dll, chamava o Windows Installer para perguntar por que ela não existia (http://msdn.microsoft.com/en-us/library/15hyw9x3(VS.71).aspx, If Assembly2 is not found at either of those locations, the runtime queries the Windows Installer ). Isso é que provavelmente ocasionava a tentativa de reparação.

A Solução

Talvez não seja a solução ideal, nem a mais bela, mas funcionou. Simplesmente colocamos uma cópia do componente que vai no COM+ dentro do diretório C:\Windows\System32\. Com isso, o CLR localiza o componente e não pergunta nada ao Windows Installer.

Somente uma ressalva, não fizemos testes quando os sistemas que chamam nosso aplicativo possuem a propriedade Application Root Directory ajustada no COM+. Com isso, teoricamente o CLR não iria procurar no System32. Mas se isso acontecer, podemos ajudar no arquivo de config desse sistema para localizar o componente no lugar certo, através do Probing (http://msdn.microsoft.com/en-us/library/4191fzwb(VS.71).aspx.

Ufa, finalmente este problema foi resolvido!

[]’s

Comentários

Postagens mais visitadas deste blog

Trocando configurações padrão do Live TIM

Uma proposta de Clean Architecure com Modelo de Atores

Testes automatizados em sistemas autenticados com certificados digitais, usando Selenium e PhantomJS