Usuário com melhor resposta
Erro The creator of this fault did not specify a Reason e propagação do erro no serviço para o cliente

Pergunta
-
Amigos,
Construi uma pequena aplicação e desenvolvi o serviço desta forma:
Classe que armazena o detalhe do erro que será passada para o cliente através de uma faultexception:
using
System;
namespace
Jetro.WCF
{
public class DetalhesDoErro
{
public string Mensagem { get; set; }
}
}
Aqui está a interface do serviço:
[
OperationContract]
[
FaultContract(typeof(DetalhesDoErro))]
bool UsuarioNaoCadastrado(string Nome);
Aqui está a implementação do serviço:
public bool UsuarioNaoCadastrado(string Nome)
{
try
{
using (var BLL = new UsuarioBLL())
{
var conexaoBanco = WebConfigurationManager.ConnectionStrings["ConexaoBanco"].ConnectionString;
return BLL.UsuarioNaoCadastrado(Nome, conexaoBanco);
}
}
catch (Exception ex)
{
DetalhesDoErro detalhesErro = new DetalhesDoErro();
detalhesErro.Mensagem = ex.Message;
throw new FaultException<DetalhesDoErro>(detalhesErro);
}
}
Aqui está como eu faço no cliente para pegar o erro:
JetroClient Proxy = new JetroClient();
using (Proxy as IDisposable)
{
try
{
Proxy.UsuarioNaoCadastradoAsync(cmbUsuarios.Text);
Proxy.UsuarioNaoCadastradoCompleted +=
new EventHandler<UsuarioNaoCadastradoCompletedEventArgs>(Proxy_UsuarioNaoCadastradoCompleted);
}
catch (FaultException<JetroWCF.DetalhesDoErro> ex)
{
MessageBox.Show(ex.Detail.Mensagem);
}
}
Está acontecendo dois problemas que são:
1) No lado do serviço está acontecendo este erro: The creator of this fault did not specify a Reason, nesta linha:throw new FaultException<DetalhesDoErro>(detalhesErro).Se eu altero ela para que fique assim:throw new FaultException<DetalhesDoErro>(detalhesErro, new FaultReason(detalhesErro.Mensagem)) funciona e passa. A minha dúvida é se esta construção está certa e tem que ser feita dessa forma, ou seja, especificando a FaultReason?
2) O segundo problema é que eu não estou conseguindo exibir a mensagem do erro que aconteceu no serviço no lado do cliente. Sempre é exibida a mensagem:The remote server returned an error: NotFound, e ai aparece um montão de palavrões...rs
Por favor, seria possível alguém dar uma luz?
Um forte abraço a todos.
Respostas
-
Boas Marcelos,
Coloca isso na sua aplicação Silverlight:
WebRequest.RegisterPrefix("http://", WebRequestCreator.ClientHttp);Mais informações:
http://www.israelaece.com/post/Stacks-de-Comunicacao-do-Silverlight.aspx
http://www.israelaece.com/post/Propagando-excecoes-para-o-Silverlight.aspx
http://www.israelaece.com- Marcado como Resposta Marcelos de Oliveiras quarta-feira, 5 de janeiro de 2011 14:56
Todas as Respostas
-
Boas Marcelo,
A questão é que você está invocando a operação de forma assíncrona, ou seja, se algum problema ocorrer durante a execução da mesma, a exceção vai ser reportada dentro do evento que acontece quando a chamada é finalizada, que no seu caso é a Proxy_UsuarioNaoCadastradoCompleted. É dentro deste evento que deve estar o tratamento de erro.
http://www.israelaece.com- Sugerido como Resposta AndreAlvesLimaModerator terça-feira, 4 de janeiro de 2011 15:20
-
Bom dia Marcelo.
Em relação ao seu primeiro problema, isto acontece porque uma FaultException, ao ser lançada requer que uma FaultReason seja especificada na propriedade Reason.
Quando você passa a mensagem como parametro ao construtor, ele automaticamente cria a FaultReason. Portanto você pode criar a FaultException passando a string que representa a FaultReason ou pode criar o objeto e depois atribuir a FaultReason.
Já em relação ao segundo problema, faultou você definir a sua classe DetalhesDoErro como um contrato de dados, colocando a annotation DataContract na classe e DataMember nos atributos. Como você já colocou a annotation FaultContract nos métodos, tudo deve funcionar. E assim como falado acima, você deve invocar o método de forma síncrona.
Seguem alguns links que explicam melhor o que eu disse.
Espero ter ajudado. Qualquer dúvida estou à disposição. -
Marcelo,
Se você estiver debugando podem ser as configurações do Visual Studio. Vá em Tools -> Options -> Debugging -> General.
As opções "Enable the exception assistant" e "Enable just my Code (Managed only)" devem ser desmarcadas.
Espero ter ajudado.
Allan Ferreira
Allan -
Amigos,
Obrigado pelas respostas rápidas de todos vocês.
Porém ainda estou com dúvidas de como resolver este problema, e por alguma razão que eu não sei, eu ainda não estou conseguindo pegar a mensagem de erro que acontece no servico e mostrar no cliente.
Estou usando WCF, SL4, C# em uma aplicação n-camadas, então de acordo com todas as respostas eu fiz as seguintes alterações:
- Classe de irá transportar o erro do serviço para o cliente: Eu acrescentei as propriedade
DataContract e DataMember e ela ficou dessa forma:
namespace
Jetro.WCF
{
[DataContract]
public class DetalhesDoErro
{
[DataMember]
public string Mensagem { get; set; }
}
} - Camada DAL: Nesta camada eu tenho um método que verifica se o usuário está cadastrado pelo nome, e para testar a geração do erro e pega-lo no cliente, de propósito eu escrevi o nome do
campo errado na declaração SQL.
O método ficou assim:
public
bool UsuarioNaoCadastrado(string Nome, string ConexaoBanco)
{
using (var conexaoBanco = new SqlConnection(ConexaoBanco))
{
using (var cmdSql = new SqlCommand())
{
cmdSql.Connection = conexaoBanco;
cmdSql.CommandText = "Select NomeUsuario from Usuario " +
//"Where Upper(NomeUsuario) = '" + Nome.ToUpper() + "'"; **Linha correta
"Where Upper(NomeUsu) = '" + Nome.ToUpper() + "'"; **Linha Errada
cmdSql.Connection.Open();
using (var dr = cmdSql.ExecuteReader())
{
if (dr.HasRows == false)
return true;
else
return false;
}
}
}
} - Camada BLL: A chamda do método nesta camada ficou dessa forma:
public
bool UsuarioNaoCadastrado(string Nome, string ConexaoBanco)
{
using (var DAL = new UsuarioDAL())
{
return DAL.UsuarioNaoCadastrado(Nome, ConexaoBanco);
}
} - Serviço : Na implementação do serviço fiz desta forma:
public
bool UsuarioNaoCadastrado(string Nome)
{
try
{
using (var BLL = new UsuarioBLL())
{
var conexaoBanco = WebConfigurationManager.ConnectionStrings["ConexaoBanco"].ConnectionString;
return BLL.UsuarioNaoCadastrado(Nome, conexaoBanco);
}
}
catch (Exception ex)
{
DetalhesDoErro detalhesErro = new DetalhesDoErro();
detalhesErro.Mensagem = ex.Message;
throw new FaultException<DetalhesDoErro>(detalhesErro, new FaultReason(detalhesErro.Mensagem));
}
} - Página do Silverlight: Testou fazendo desta forma a chamada ao serviço:
JetroClient Proxy = new JetroClient();
using (Proxy as IDisposable)
{
Proxy.UsuarioNaoCadastradoAsync(cmbUsuarios.Text);
Proxy.UsuarioNaoCadastradoCompleted += new
EventHandler<UsuarioNaoCadastradoCompletedEventArgs> (Proxy_UsuarioNaoCadastradoCompleted);
} - Evento UsuarioNaoCadastradoCompleted: Eu tento pegar o erro desta forma:
void Proxy_UsuarioNaoCadastradoCompleted(object sender, UsuarioNaoCadastradoCompletedEventArgs e)
{
if (e.Error == null)
{
}
else if (e.Error is FaultException<DetalhesDoErro>)
{
FaultException<DetalhesDoErro> erro = e.Error as FaultException<DetalhesDoErro>;
MessageBox.Show(erro.Detail.Mensagem);
}
}
Ao debugar vejo que o erro que é retornado para o cliente é o System.ServiceModel,CommunicationExcpetion, e não o FaultException que fiz no serviço.
E eu realmente não entendi porque isso acontece, já que no serviço eu tranformo tudo em FaultException, independente do tipo do erro, ou não é assim?
Desculpe pela dissertação acima e obrigado a todos que puderem ajudar
- Classe de irá transportar o erro do serviço para o cliente: Eu acrescentei as propriedade
DataContract e DataMember e ela ficou dessa forma:
-
Boas Marcelos,
Coloca isso na sua aplicação Silverlight:
WebRequest.RegisterPrefix("http://", WebRequestCreator.ClientHttp);Mais informações:
http://www.israelaece.com/post/Stacks-de-Comunicacao-do-Silverlight.aspx
http://www.israelaece.com/post/Propagando-excecoes-para-o-Silverlight.aspx
http://www.israelaece.com- Marcado como Resposta Marcelos de Oliveiras quarta-feira, 5 de janeiro de 2011 14:56
-