O Arquivo Preso
Após uma alteração pequena, surgiu um comportamento estranho e intermitente na aplicação: ao acessar pela segunda vez um arquivo bmp, ocorria uma exceção indicando que o arquivo "já estava aberto por outro processo".
Demorou algum tempo até descobrir que o problema estava em uma chamada ao método Bitmap.FromFile. Apesar da documentação falar claramente que o arquivo fica preso até o objeto ser destruído, várias coisas conspiraram para eu não perceber isto:
- Eu estava interessado somente nas dimensões da imagem, usei este método somente porque parecia ser o jeito mais simples de obtê-las.
- Não é o tipo de função que se espere que mantenha o arquivo preso. Os motivos dela manter o arquivo aberto estão explicados aqui.
- Não existe uma função explícita para fechar o arquivo, ele só será liberado quando o objeto for destruído.
- O objeto estava declarado em um bloco bem curto de código. Mas é claro que isto não faz diferença. O .Net só vai destruir o objeto (e liberar o arquivo) quando rodar o garbage collector. Para quem aprendeu primeiro C++ fica a falsa ilusão de que o objeto será destruído no final do bloco, liberando todos os recursos.
- No ASP.Net os conceitos de início e fim da execução de um programa são vagos. No desktop é bem claro quando um programa inicia e termina (tirando os casos de programas que ficam como zumbis depois que a gente manda ele terminar, né Thunderbird?). A rigor um programa web precisa rodar somente o tempo para atender a um get ou post. Como isto é muito desperdício de recursos e atrapalha o desempenho, o runtime do ASP.Net reaproveita instâncias do programa. O efeito prático, neste caso, era a intermitência do programa. Dois acessos consecutivos à mesma imagem sempre causava o bug, mas depois de algum tempo o programa terminava, liberando o arquivo.
E Tudo Para de Funcionar!
Ao tentar acessar qualquer página da aplicação, o .Net dá o erro "The located assembly's manifest definition does not match the assembly reference."
A causa? O cliente, como toda pessoa bem cuidadosa, renomeou a versão antiga para algo como xyz_old.dll antes de colocar a versão nova de xyz.dll. A lógica de localização e carga do .Net fez alguma bagunça entre os dois e não conseguiu carregar nenhum.
Bastou mover para outro canto a versão antiga para tudo voltar ao normal (sem o bug da imagem, é claro).
Nenhum comentário:
Postar um comentário