Visão geral: esta seção descreve principalmente exceções e exceções simuladas que podem ocorrer em chamadas de serviço e analisa quando e quais exceções podem ser capturadas e como passar exceções de serviço para o cliente da maneira correta.
No final do artigo, é fornecida a sequência de captura para capturar exceções corretamente. Esta captura de exceção é apenas uma introdução, e algumas delas são funções de aplicativo, portanto, o código e a escrita são relativamente simples. Ela também apresenta algumas técnicas para tratamento de exceções no lado do servidor.
1. Primeiro, criamos um servidor e cliente de calculadora simples, como segue:
Clique para expandir o código
//Servidor[ServiceContract]interface pública ICalc{[OperationContract][FaultContract(typeof(GreentingError))]string Div(int x, int y);}public class Calc : ServiceBase, ICalc {public string Div(int x, int y ) ) {string resultado = string.Empty; try {resultado = string.Format("resultado: {0}", x / y); catch (DivideByZeroException ex) {throw ex; [ServiceContract] interface pública ICalc { [OperationContract] [FaultContract(typeof(GreentingError))] string Div(int x, int y } public class CalcClient : ClientBase<ICalc>, ICalc{ public string Div(int x, int y); ) ) {return base.Channel.Div(x, y }});
Ok, admito que o código é bem simples, mas gosto de coisas simples.
2. Coisas simples são boas, e chamá-las é muito mais simples;
tente {CalcClientcalcclient = new CalcClient string result =calcclient.Div(10, 0); Console.WriteLine(resultado); ex) {lançar ex;} catch (FaultExceptionex) {lançar ex; catch (System.ServiceModel.CommunicationException ex) {lançar ex;
3. Quando chamamos o método Div(int x, int y) do serviço e passamos o valor 0 para o logaritmo y, o servidor lançará uma exceção DivideByZeroException, o que é esperado. Neste momento,
Esta exceção é capturada na seção FaultException do cliente.
4. Não tem problema, lançaremos FaultException manualmente no código do servidor.
catch (DivideByZeroException ex){exceção FaultException = new FaultException(ex.Message lançar exceção;}
Neste momento, descobri que FaultException capturou essa exceção. Por quê?
5. Faça outro teste.
Adicione este código ao serviço: System.Threading.Thread.Sleep(70000);
Desta vez, TimeOutException finalmente capturou a exceção do servidor, então temos que perguntar: quando FaultException<GreentingError> capturará a exceção? A resposta é que quando o servidor lançar FaultException<GreentingError>, cite uma passagem no MSDN (parte verde):
Se o ouvinte receber um erro SOAP que não é esperado ou especificado no contrato de operação, um objeto FaultException será lançado. Dois tipos de erros SOAP podem ser enviados: declarados e não declarados. Um erro SOAP declarado é aquele em que uma operação possui o atributo System.ServiceModel.FaultContractAttribute que especifica um tipo de erro SOAP personalizado. Erros SOAP não declarados são erros que não estão especificados no contrato da operação. O "erro SOAP inesperado ou não especificado" aqui se refere a um tipo de erro personalizado que não é agrupado com FaultContractAttribute na operação de serviço.
6. Então, quando CommincationException será detectada?
MSDN diz: O aplicativo lida com objetos CommunicationException que podem ser lançados durante a comunicação
Bem, para levantar esta exceção, fazemos o seguinte. Primeiro feche o objeto de canal atual no servidor.
OperationContext.Current.Channel.Close();
Infelizmente, o cliente não capturou CommunicationException, mas capturou TimeOutException! Como nenhuma exceção ocorreu após o fechamento do canal de serviço, nenhuma mensagem foi retornada ao cliente. Após aguardar um determinado período de tempo, o cliente atingiu o tempo limite e saiu.
Portanto, especificamos um TimeSpan ao fechar o canal. Isso permite que a chamada retorne imediatamente. É claro que o retorno da chamada também pode ser concluído através de Channel.Abort.
OperationContext.Current.Channel.Close(new TimeSpan(5000));
Ao chamar o método Close de IContextChannel, especifique o tempo que a operação de envio deve ser concluída antes do tempo limite, para que a mensagem possa ser retornada imediatamente dentro do tempo especificado sem ter que esperar o tempo limite da chamada de serviço, caso contrário o cliente irá definitivamente lançar uma exceção TimeOutException em vez da exceção CommunicationException.
7. Remédios
Ao mesmo tempo, para tomar algumas medidas corretivas quando ocorre uma exceção no serviço, criamos uma nova classe abstrata ServiceBase e herdamos a classe de implementação do serviço Calc, para que possamos obter controle sobre as várias transições de estado de o serviço. A classe ServiceBase é a seguinte:
public abstract parcial class ServiceBase { private IContextChannel canal = null; protegido ServiceBase() { canal = OperationContext.Current.Channel; canal.Opening += new EventHandler(delegate(object sender, EventArgs e) {/* TO DO*/ }) ; canal.Opened += new EventHandler(delegate(object sender, EventArgs e) {/* TO DO*/ }); }); canal.Closed += new EventHandler(delegate(object sender, EventArgs e) { Abort(); }); ; } void Open() {/* TO DO*/ } void Close() { /* TO DO*/} void Abort() { channel.Abort() }}
Como pode ser visto no código acima, após o fechamento do canal de atendimento, paramos imediatamente o atendimento e deixamos a mensagem retornar imediatamente, mesmo que o atendimento seja encerrado durante a operação sem especificar o tempo de término do timeout, a chamada. ainda pode retornar imediatamente.
Desta vez o cliente finalmente capturou a CommunicationException, conforme mostrado na figura abaixo:
Por que isso está acontecendo?
8. Vamos dar uma olhada na hierarquia de herança de CommunicationException, na qual podemos nos inspirar.
8.1. A primeira é a hierarquia de herança de FaultException<TDetail>.
8.2, novamente a hierarquia de herança de TimeOutException.
9. Como pode ser visto na figura acima, TimeOutException e CommunicationException herdam da classe SystemException, enquanto FaultException herda de CommunicationException e, finalmente, FaultException<TDetail> herda da classe FaultException.
10. Por fim, concluímos que a ordem correta de captura de exceções no cliente deveria ser:
TimeOutException> FaultException<TDetail> > FaultException > CommunicationException > Exceção. É altamente recomendável que os desenvolvedores lancem e capturem exceções do tipo FaultException<TDetail>.
Autor: Lao Mi Fonte: http://www.cnblogs.com/viter/
Os direitos autorais deste artigo pertencem ao autor e ao Blog Park. A reimpressão é bem-vinda. No entanto, esta declaração deve ser mantida sem o consentimento do autor, e um link para o texto original deve ser fornecido em uma posição óbvia na página do artigo. o direito de exercer responsabilidade legal é reservado.