El objeto de comunicación, System.ServiceModel.Channels.ServiceChannel, no puede ser utilizado para la comunicación porque se encuentra en estado Faulted.
¿De qué se trata este error y cómo puedo resolverlo?
El objeto de comunicación, System.ServiceModel.Channels.ServiceChannel, no puede ser utilizado para la comunicación porque se encuentra en estado Faulted.
¿De qué se trata este error y cómo puedo resolverlo?
Obtienes este error porque permitiste que ocurriera una excepción de .NET en tu servidor, y no la capturaste ni la manejaste, y tampoco la convertiste en una falla SOAP.
Ahora, dado que el servidor "falló", el tiempo de ejecución de WCF ha "fallado" el canal, es decir, el enlace de comunicación entre el cliente y el servidor no es utilizable; después de todo, parece que tu servidor acaba de explotar, por lo que ya no puedes comunicarte con él.
Entonces, lo que necesitas hacer es:
siempre capturar y manejar tus errores en el servidor - no permitas que las excepciones de .NET viajen del servidor al cliente - siempre envuélvelas en fallas SOAP interoperables. Consulta la interface IErrorHandler de WCF e implementarla en el lado del servidor
si estás a punto de enviar un segundo mensaje a través de tu canal desde el cliente, asegúrate de que el canal no esté en estado de falla:
if(client.InnerChannel.State != System.ServiceModel.CommunicationState.Faulted)
{
// llamar al servicio - todo está bien
}
else
{
// canal falló - recrea tu cliente y luego intenta de nuevo
}
Si lo está, lo único que puedes hacer es desecharlo y volver a crear el proxy del lado del cliente y luego intentarlo de nuevo
Para evitar que el servidor caiga en estado de error, debes asegurarte de que no se genere ninguna excepción no controlada. Si WCF detecta una excepción inesperada, no se aceptarán más llamadas - la seguridad es lo primero.
Dos posibilidades para evitar este comportamiento:
Usar una FaultException (esta no es inesperada para WCF, por lo que WCF sabe que el servidor aún tiene un estado válido)
en lugar de
throw new Exception("Error xy en mi función")
siempre usar
throw new FaultException("Error xy en mi función")
quizás puedas envolver todo el bloque en un try..catch y lanzar una FaultException en todos los casos de una excepción
try
{
... algún código aquí
}
catch (Exception ex)
{
throw new FaultException(ex.Message)
}
Decirle a WCF que maneje todas las excepciones usando un Errorhandler. Esto se puede hacer de varias maneras, yo elegí una forma simple usando un Atributo:
Lo único que tenemos que hacer es usar el atributo [SvcErrorHandlerBehaviour]
en la Implementación de Servicio deseada
using System;
using System.Collections.ObjectModel;
using System.ServiceModel;
using System.ServiceModel.Channels;
using System.ServiceModel.Description;
using System.ServiceModel.Dispatcher;
namespace MainService.Services
{
///
/// Proporciona FaultExceptions para todas las llamadas a métodos de un servicio que fallan con una excepción
///
public class SvcErrorHandlerBehaviourAttribute : Attribute, IServiceBehavior
{
public void Validate(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase)
{ } // Implementación no necesaria
public void AddBindingParameters(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase, Collection endpoints,
BindingParameterCollection bindingParameters)
{ } // Implementación no necesaria
public void ApplyDispatchBehavior(ServiceDescription serviceDescription, ServiceHostBase serviceHostBase)
{
foreach (ChannelDispatcherBase chanDispBase in serviceHostBase.ChannelDispatchers)
{
ChannelDispatcher channelDispatcher = chanDispBase as ChannelDispatcher;
if (channelDispatcher == null)
continue;
channelDispatcher.ErrorHandlers.Add(new SvcErrorHandler());
}
}
}
public class SvcErrorHandler: IErrorHandler
{
public bool HandleError(Exception error)
{
// Puedes registrar el mensaje si quieres.
return true;
}
public void ProvideFault(Exception error, MessageVersion version, ref Message msg)
{
if (error is FaultException)
return;
FaultException faultException = new FaultException(error.Message);
MessageFault messageFault = faultException.CreateMessageFault();
msg = Message.CreateMessage(version, messageFault, faultException.Action);
}
}
}
Este es un ejemplo sencillo, puedes profundizar en IErrorHandler no usando la FaultException
desnuda, sino una FaultException<>
con un tipo que proporcione información adicional ver IErrorHandler para un ejemplo detallado.
De hecho, si no tiene éxito después de seguir las sugerencias de marc_s, tenga en cuenta que un elemento en la configuración de enlace del servidor (o la falta de este) en web.config en el servidor puede causar esta excepción. Por ejemplo, si el servidor espera seguridad a nivel de Mensaje
y el cliente está configurado como Ninguno
(o si el servidor no forma parte de un dominio de Active Directory pero el host remoto del cliente sí).
Consejo: En tales casos, es muy probable que la aplicación cliente invoque el servicio web correctamente cuando se ejecute directamente en la máquina del servidor bajo una cuenta administrativa en una sesión RDP.
Adjunta al evento faulted
para averiguar por qué y cuándo ocurrió el error.
Edición: También sería útil si publicaras más información sobre lo que estás haciendo.
No es una solución a este problema, pero si estás experimentando el error mencionado con Ektron eSync, podría ser que tu base de datos se haya quedado sin espacio en disco.
Edición: De hecho, este no es exclusivamente un problema de Ektron eSync. Esto podría ocurrir en cualquier servicio que esté consultando una base de datos completa.
Edición: La falta de espacio en disco o el bloqueo de acceso a un directorio necesario causarán este problema.
Iteramos es una comunidad de desarrolladores que busca expandir el conocimiento de la programación mas allá del inglés.
Tenemos una gran cantidad de contenido, y también puedes hacer tus propias preguntas o resolver las de los demás.