Temos um aplicativo Windows Forms que se conecta a alguns serviços da web. Ele lista os documentos no sistema e quando o usuário clica duas vezes, baixamos o arquivo para o computador local e abrimos o documento para que eles sejam editados. Depois que o usuário fecha o documento, então o enviamos de volta para o sistema. Para este processo temos monitorado o bloqueio de arquivo no documento. Assim que o bloqueio de arquivo é liberado nós carregamos o documento. O método IsFileLocked se parece com isso: Chamamos isso em um loop com um sono de 5 segundos entre tentativas. Isso parece funcionar grande na maioria das vezes, mas ocasionalmente vemos uma IOException deste método. Não consigo ver como é possível que essa exceção seja lançada. A exceção é: A outra parte ímpar é o rastreamento de pilha. Isso se refere ao GetOutlook que é uma parte diferente do sistema inteiramente (não relacionado ao manuseio de documentos). Existem dois caminhos de código em IsFileLocked e nem são acessíveis através do método GetOutlookInternal. É quase como se a pilha está ficando corrompido. Como uma nota lateral, consideramos usar um FileSystemWatcher para monitorar as alterações de arquivo, mas descontado essa abordagem, porque o usuário pode manter o documento aberto e continuar a fazer alterações adicionais a ele. Nossos serviços web desbloquear o documento assim que enviá-lo para que não podemos fazer isso até que o usuário concluiu terminou com ele. Estamos apenas preocupados com os documentos bloqueados pela sua aplicação. Eu aprecio que existem algumas aplicações que não bloqueiam seus arquivos, mas não precisamos considerá-los aqui. Os métodos do Outlook Abaixo está o método GetOutlookInternal que aparece na pilha - como você pode ver, ele está lidando apenas com o Outlook Interop e não está relacionado à abertura do documento. Não chama IsFileLocked: Eu acidentalmente tropeçado através deste artigo que ajudou a encontrar a causa do meu problema: Marshal. GetHRForException faz mais do que apenas Get-HR-For-Exception Acontece que nós tínhamos dois segmentos, um estava chamando Marshal. GetHRForException (.) Em uma IOException para determinar se um arquivo está bloqueado (código de erro Win32 32 ou 33). Outra thread estava chamando Marshal. GetActiveObject (.) Para se conectar a uma instância do Outlook usando Interop. Se GetHRForException é chamado primeiro e, em seguida, GetActiveObject é chamado segundo mas lança um COMException. Então você começa completamente a exceção errada e rastreamento de pilha. Isso ocorre porque GetHRForException está efetivamente definindo a exceção e GetActiveObject irá lançar que em vez da COMException real. Exemplo de código a ser reproduzido: Este problema pode ser reproduzido usando o seguinte código. Crie um novo aplicativo de console, importe a referência COM do Outlook e cole o código. Verifique se o Outlook não está sendo executado quando você inicia o aplicativo: Você esperaria ver o COMException no console, mas isso é o que você vê Note como a exceção é DirectoryNotFoundException. E a pilha sugere incorretamente GetActiveObject chamado em IsFileLocked. A solução para esse problema foi simplesmente usar a propriedade Exception. HResult em vez de GetHRForException. Anteriormente esta propriedade foi protegida, mas agora está acessível desde que atualizamos o projeto para o. NET 4.5 Com essa alteração, o comportamento é o esperado. O console agora mostra: TLDR: Não use Marshal. GetHRForException se você também estiver usando componentes COM. Eu tenho algum código IO que lê um fluxo dentro de um try..catch. Ele captura IOException e chama System. Runtime. InteropServices. Marshal. GetHRForException () dentro do catch, em uma tentativa de tomar ações diferentes com base no HResult. Algo como isto: Mas executando este código no ASP. NET com o trustmedium, eu recebo esta exceção: Algumas perguntas: Acho que a exceção está ocorrendo porque GetHRForException chama em código não gerenciado, o que não é permitido na confiança média. Corrigir Esta exceção está sendo lançada, não no momento da execução de GetHRForException, mas no momento em que o método está sendo JITed - Correto (O stacktrace mostra meu método, mas tenho certeza de que uma exceção de IO não ocorreu) Existe uma maneira para mim variar o comportamento em um ambiente de confiança parcial, para que eu não chamar o GetHRForException (código não gerenciado) onde não é permitido Em outras palavras, como posso permitir que o JIT para ter sucesso na compilação, enquanto também Avaliando em tempo de execução se o código deve chamar GetHRForException () Algo como isto: Eu acho que há um mecanismo de tempo de execução para testar se as permissões estão disponíveis, mas havent sido capaz de encontrá-lo. EDIT. É este artigo de blog a resposta ShawnFa da Microsoft diz que você não pode fazer uma tentativa. Catch (SecurityException) em torno de um método protegido por um LinkDemand. Se MethodA () chama MethodB (), e MethodB () é marcado com LinkDemand para confiança total, em seguida, o LinkDemand é verificado com MethodA é Jited. Portanto, para evitar a SecurityException, preciso extrair Marshal. GetHRForException em um método separado. É isso correto Aplicado ao meu código, MethodA () pode ser o código que chama Read e, em seguida, na captura tenta chamar GetHRForException (). GetHRForException é MethodB (). O LinkDemand é avaliado quando MethodA () é JITd. (Este LinkDemand falha no meu cenário de médio-confiança ASP. NET). Se eu mover o GetHRForException em um novo método, MethodC (), e chamar condicionalmente MethodC () somente após uma permissão imperativa. Demand () é bem-sucedida, teoricamente eu deveria ser capaz de evitar a SecurityException no tempo JIT, porque MethodC () será JITd somente após a permissão. Demain () tiver êxito. Pediu Jul 12 09 at 14:20 O método necessário é SecurityPermission. IsUnrestricted (). Retorna um verdadeiro ou falso indicando se a permissão é permitida ou não. Ele não exige uma permissão, como faz SecurityPermission. Demand (). Eu uso IsUnresticted com SecurityPermissionFlag. UnmanagedCode para ver se o assembly é permitido chamar código não gerenciado e, em seguida, chamar o código não gerenciado somente se permitido. Há uma torção adicional. O compilador JIT, ao compilar um método, verifica para LinkAcessos de CodeAccessPermission em qualquer método chamado my o método a ser compilado. Marshal. GetHRForException () é marcado com um LinkDemand. Assim, meu método que chama Marshal. GetHRForException () irá lançar uma excepção de segurança uncatchable no momento da compilação JIT, quando executado em um ambiente restrito, como ASP. NET com confiança média. Portanto, nunca devemos JIT o método que chama Marshal. GetHRForException () nesse caso, o que significa que eu preciso para quebrar Marshal. GetHRForException () em um método separado no meu código que é chamado (e assim JITted) apenas quando UnmanagedCode é Sem restrições. Heres algum código de exemplo: respondeu Jul 20 09 at 17:56 Sim - confiança médio não permitirá chamadas em código não gerenciado. O único nível de confiança que o permite é a confiança total. Depende. As demandas de CAS podem ocorrer em tempo de execução, mas o ambiente de hospedagem também pode ir em um vagar e procurar coisas que não podem fazer. Você pode testar para ver se você pode fazer uma chamada para código não gerenciado usando uma demanda CAS com uma instância de SecurityPermission. O código para fazer uma demanda CAS parece com isso respondido Jul 12 09 at 14:32 OK, esta é a grande informação. Isso abrange a parte b da Q3. Mas e sobre a parte a Como faço para obter a compilação JIT para ter sucesso Posso marcar o meu método com um atributo de segurança ou. Lembre-se, minha teoria é que o erro SecurityPermission não está acontecendo em tempo de execução, ele está acontecendo durante JIT - e eu acho que você confirmou que isso é possível. Então a questão é, como eu escrevo o código para permitir que o JIT compile. Ndash Cheeso Jul 12 09 at 15:50 Deve estar acontecendo em tempo de execução, caso contrário, o assembly wouldn39t mesmo carregar - e para que isso aconteça o assembly precisa ser marcado como exigindo a permissão. Mesmo então isso é provavelmente uma verificação de tempo de execução, como acontecerá na carga de montagem, que poderia estar em tempo de execução. Ndash blowdart Jul 12 09 at 16:24 Diferentes tipos de verificação, as demandas de link são atributos em um método, e são de fato verificadas no tempo JIT. Ele é muito usado pela própria estrutura e é raro vê-lo fora da fonte CLR. O que eu demonstro é uma demanda imperativa, não declarativa como um SecurityPermission (SecurityAction. LinkDemand, Unrestricted true) ndash blowdart Jul 12 09 at 18: 55O catch Blocks Você associa manipuladores de exceção com um bloco try fornecendo um ou mais blocos catch diretamente Após o bloco try. Nenhum código pode estar entre o fim do bloco try e o início do primeiro bloco catch. Cada bloco catch é um manipulador de exceção que manipula o tipo de exceção indicado pelo seu argumento. O tipo de argumento ExceptionType. Declara o tipo de exceção que o manipulador pode manipular e deve ser o nome de uma classe que herda da classe Throwable. O manipulador pode se referir à exceção com nome. O bloco catch contém código que é executado se e quando o manipulador de exceção é invocado. O sistema de tempo de execução invoca o manipulador de exceção quando o manipulador é o primeiro na pilha de chamadas cujo ExceptionType corresponde ao tipo da exceção lançada. O sistema considera uma correspondência se o objeto lançado puder ser legalmente atribuído ao argumento do handler39. A seguir, dois manipuladores de exceção para o método writeList: Os manipuladores de exceção podem fazer mais do que apenas imprimir mensagens de erro ou interromper o programa. Eles podem fazer a recuperação de erros, solicitar ao usuário que tome uma decisão ou propagar o erro até um manipulador de nível superior usando exceções encadeadas, conforme descrito na seção Exceções encadeadas. Capturando mais de um tipo de exceção com um manipulador de exceção No Java SE 7 e posterior, um único bloco catch pode manipular mais de um tipo de exceção. Esse recurso pode reduzir a duplicação de código e diminuir a tentação de capturar uma exceção excessivamente ampla. Na cláusula catch, especifique os tipos de exceções que o bloco pode manipular e separe cada tipo de exceção com uma barra vertical (): Observação. Se um bloco catch tratar mais de um tipo de exceção, então o parâmetro catch é implicitamente final. Neste exemplo, o parâmetro catch ex é final e, portanto, não é possível atribuir quaisquer valores a ele dentro do bloco catch. O uso desta página e de todo o material nas páginas sob o banner quotThe Tutorialsquot está sujeito a estes avisos legais. Copyright copy 1995, 2017 Oracle e / ou suas afiliadas. Todos os direitos reservados. Queixas Compliments Sugestões Dê-nos seu feedback.
No comments:
Post a Comment