Gestione degli errori lato client WCF

Sto consumando un server WCF goffo che occasionalmente genera varie eccezioni e restituisce anche alcuni dei suoi errori come string . Non ho affatto accesso al codice del server.

Voglio sovrascrivere il metodo di richiamo della richiesta del client WCF interno e gestire tutte le eccezioni interne e gli errori hard-coded restituiti dal server e generare l’evento Fault se si verifica un errore, pseudo:

 class MyClient : MyServiceSoapClient { protected override OnInvoke() { object result; try { result = base.OnInvoke(); if(result == "Error") { //raise fault event } catch { //raise fault event } } } 

In modo che quando chiamo myClient.GetHelloWorld() , passa attraverso il mio metodo sovrascritto.

Come può essere realizzato?
So che non devo usare il client generato, ma non voglio ri-implementare tutti i contratti di nuovo, e voglio usare la sottoclass ClientBase generata o almeno il suo canale.
Quello di cui ho bisogno è il controllo sul metodo di chiamata della richiesta interna.

Aggiornare

Ho letto questa risposta , e sembra che sia in parte ciò che sto cercando, ma mi chiedo se c’è un modo per colbind un IErrorHandler al solo codice consumer (client), voglio aggiungerlo al ClientBase istanza in qualche modo.

Aggiornare

Questo articolo sembra molto promettente ma non funziona. L’attributo applicato non sembra avere effetto. Non riesco a trovare un modo per aggiungere IServiceBehavior al lato client.

Aggiornare

Ho provato ad albind un IErrorHandler tramite chiamata IEndpointBehavior.ApplyClientBehavior :

 public void ApplyClientBehavior(ServiceEndpoint endpoint, ClientRuntime clientRuntime) { clientRuntime.CallbackDispatchRuntime.ChannelDispatcher.ErrorHandlers .Add(new ErrorHandler()); } 

( clientRuntime è un parametro), ma le eccezioni vengono comunque generate saltando direttamente MyErrorHandler .
ApplyDispatchBehavior non viene chiamato affatto.

Conclusione

Devo raggiungere due aspetti:

  1. Riunisci tutte le eccezioni che potrebbero verificarsi durante la vita di un BaseClient e decidi se gestirle o lanciarle. Questo dovrebbe occuparsi di tutte le operazioni (il servizio che sto consumando espone poche decine)
  2. Analizza tutte le risposte del server e genera eccezioni per alcune di esse, quindi vengono inoltrate come nell’istruzione 1.

    È ansible utilizzare e modificare il generatore di proxy WCF di Exception Handling , in particolare la class base che utilizza. L’idea di base (controlla anche questa descrizione ) è quella di fornire la resilienza della connessione rilevando gli errori di connessione e riprovando l’operazione fallita. Come potete immaginare, per questo scopo ha bisogno di essere in grado di rilevare le eccezioni generate, e inoltre, può ispezionare il risultato delle chiamate.

    La funzionalità principale è data dalla class base ExceptionHandlingProxyBase , che viene utilizzata al posto di ClientBase . Questa class base ha un metodo Invoke come segue, dovresti modificarlo.

    Invoke semplificato:

     protected TResult Invoke(string operationName, params object[] parameters) { this.Open(); MethodInfo methodInfo = GetMethod(operationName); TResult result = default(TResult); try { this.m_proxyRecreationLock.WaitOne(this.m_proxyRecreationLockWait); result = (TResult)methodInfo.Invoke(m_channel, parameters); } catch (TargetInvocationException targetEx) // Invoke() always throws this type { CommunicationException commEx = targetEx.InnerException as CommunicationException; if (commEx == null) { throw targetEx.InnerException; // not a communication exception, throw it } FaultException faultEx = commEx as FaultException; if (faultEx != null) { throw targetEx.InnerException; // the service threw a fault, throw it } //... Retry logic } return result; } 

    Avrai bisogno di modificare la destinazione throw targetEx.InnerException; parte per gestire le eccezioni di cui hai bisogno e ovviamente anche il valore di restituzione shoudl deve essere controllato per le tue esigenze. Altro quindi che puoi lasciare la logica dei tentativi o buttarla via se non ti aspetti problemi di connessione. C’è un’altra variante del metodo Invoke for void return.

    Oh, a proposito, funziona anche con i canali duplex, c’è un’altra class base per quelli.

    Se non si desidera utilizzare il generatore (potrebbe non funzionare nemmeno nelle versioni più recenti di VS), si potrebbe semplicemente prendere la class base per esempio da qui e generare la class di implementazione effettiva con T4 dall’interfaccia di servizio.

    Se il servizio non restituisce una vera eccezione, ma solo un messaggio, probabilmente si desidera aggiungere un ClientMessageInspector come nuovo comportamento del client. Vedere: https://msdn.microsoft.com/en-us/library/ms733786.aspx

    Ho finito per utilizzare qualcosa in base alle risposte in questa domanda.

    Si attacca al codice client generato e consente di invocare genericamente le operazioni.

    Il codice è incompleto, sentiti libero di cambiarlo e modificarlo. Per favore informami se hai trovato bug o fatto aggiornamenti.

    È piuttosto ingombrante quindi condividerò solo il codice di utilizzo:

     using (var proxy = new ClientProxy()) { client.Exception += (sender, eventArgs) => { //All the exceptions will get here, can be customized by overriding ClientProxy. Console.WriteLine($@"A '{eventArgs.Exception.GetType()}' occurred during operation '{eventArgs.Operation.Method.Name}'."); eventArgs.Handled = true; }; client.Invoke(client.Client.MyOperation, "arg1", "arg2"); }