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.
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
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
Postar um comentário