2012-01-06 13 views
14

Supongamos que tenemos un método de servicio que realiza algunas comprobaciones de seguridad, recupera datos de DB y de un servicio web de terceros, construye MyDataDTO, escribe una entrada de auditoría en DB. Y queremos códigos de error granulares bien estructurados, ¿no? Somos buenos muchachos y siga las pautas de tratamiento de errores estándar de WCF:Contratos de falla de WCF en el mundo real

[FaultContract(typeof(AccessDenied))] 
[FaultContract(typeof(KeyNotFound))] 
[FaultContract(typeof(WsFault))] 
[FaultContract(typeof(DbFault))] 
MyDataDTO GetData(string key); 

Ahora vamos a añadir un nuevo método que actualiza los datos. El método llama al GetData() internamente (o parte principal de él), realiza la validación y agrega actualizaciones a los datos. Por lo tanto, debe tener todos los fallos de GetData() duplicado además añadir sus propias faltas:

[FaultContract(typeof(InvalidState))] 
[FaultContract(typeof(DataNotValid))] 
[FaultContract(typeof(AccessDenied))] 
[FaultContract(typeof(KeyNotFound))] 
[FaultContract(typeof(WsFault))] 
[FaultContract(typeof(DbFault))] 
void UpdateData(MyDataDTO data); 

Hasta aquí todo bien. Esto nos permite incluso generar documentación XML que podemos proporcionar a los consumidores de nuestro servicio para que sepan qué códigos de error pueden esperar.

Ahora imagina que tenemos 10 servicios con 10 métodos como los anteriores (o incluso más complejos) cada uno. Y la definición de todos los contratos de fallo se convierte en pesadilla ya que este es un proceso muy propenso a errores:

  1. No hay manera de definir anomalías generales (como DbFault) para todo el servicio de
  2. No se puede garantizar que un fallo definido en un contrato de operación realmente ser devuelto (cuestiones de copiar y pegar)
  3. no se puede garantizar que no se pierda alguna falta agregar al contrato de operación

no hay que tener en versiones interfaz de la cuenta aquí :)

Por lo tanto, usted se hizo una idea si apoya los servicios de WCF en producción. ¿Deberíamos abandonar los contratos de falla y usar un buen viejo estilo C (como tener la clase base DTOBase con propiedad ErrorCode)? Reducir la granularidad de error? ¿Cómo asegurarse de que la documentación sea correcta/esté actualizada? Estoy interesado en algunas mejores prácticas.

+4

Una cosa que debe preguntarse es si sus clientes realmente usarán esos códigos de error granulares. ¿Tomarán en realidad acciones diferentes en función de la falla que se devuelve, o solo mostrarán el mensaje de error? –

+0

Muestra en su mayoría. Esto es para un diagnóstico de problemas más rápido en lugar de diferentes acciones. – UserControl

+4

Entonces solo necesitas un solo FaultContract que contenga una cadena de 'Mensaje'. –

Respuesta

1

Bueno, se puede implementar esta:

public void ProvideFault(Exception error, MessageVersion version, ref Message fault) 

En ese caso, usted tendrá un solo lugar, donde podrá cambiar según el tipo de excepción/mensaje y proporcionar los fallos propios.

http://msdn.microsoft.com/en-us/library/system.servicemodel.dispatcher.ierrorhandler.providefault.aspx

o mejor aún con muestras:

http://blogs.msdn.com/b/pedram/archive/2008/01/25/wcf-error-handling-and-some-best-practices.aspx

+0

Will esta actualización el WSDL con el las fallas deben ser devueltas por cada operación? –

+0

@JohnSaunders. No, no actualizará el WSDL. –

9

Uno de los problemas con su original enfoque es que usted está tratando de replicar la multitud de errores/excepciones que podrían ocurrir sistema. Como la complejidad del sistema aumenta con cada nueva función, la cantidad de problemas posibles que tiene que tener en cuenta aumenta exponencialmente (¡o incluso más!)

Sugeriría el siguiente enfoque: ya que está creando un "sistema" de servicios y acceder a llamadas, solo definir FaultContracts relacionados con ese sistema. Los clientes solo deberían estar interesados ​​en las siguientes preguntas:

  1. ¿Esto es un problema con los datos que quería o la forma en que pregunté?
  2. Si no es así, ¿es un problema mío o se trata de un problema relacionado con la TI (bloqueo del sistema, error de red, problema con la base de datos, lo que sea)?

Con un poco de reproceso, puede reducir el número de contratos de falla que debe proporcionar. Por ejemplo (y esto está fuera de la parte superior de la cabeza):

//Base class to define general problems 
[DataContract] 
public class SysFault 
{ 
    //MyDataDTO-specific general error. 
    [DataMember] 
    public string SysMsg {get;set;} 

    //boolean for "this is a problem with me or the hosting system?" 
    [DataMember] 
    public bool IsSystemic {get;set;} 
} 

//Subclass to expose synchronization issues--if that's one you want to define 
[DataContract] 
public class SyncFault : SysFault 
{ 
    [DataMember] 
    public string SyncMsg { get;set; } 
} 

//Subclass to expose validation issues 
[DataContract] 
public class ValFault : SysFault 
{ 
    [DataMember] 
    public string ValMsg { get;set; } 
} 

Ahora, puede utilizar los tipos de falta de separar lo que está pasando con sus servicios. Por ejemplo:

[ServiceContract] 
public interface IRecordSys 
{ 
    [OperationContract] 
    [FaultContract(typeof(SysFault))] //Raised for underlying problem 
    [FaultContract(typeof(ValFault))] //Raised if there is an issue with the key value 
    MyDataDTO getData(string key); 

    [OperationContract] 
    [FaultContract(typeof(SysFault))] //Raised for underlying problem elsewhere 
    //Raised for some issue, such as unable to get two subsystems to update properly 
    //with the given data 
    [FaultContract(typeof(SyncFault))] 
    void update(MyDataDTO data); 
} 

Su implementación particular será diferente, pero la idea es transmitir mensajes que conciernen su sistema, no cada pequeño problema sistémico que puede venir.

Cuestiones relacionadas