Traitement des erreurs côté client WCF

Je consum un serveur WCF encombrant qui lève parfois diverses exceptions et renvoie en outre certaines de ses erreurs sous forme de ssortingng . Je n’ai aucun access au code du serveur.

Je souhaite redéfinir la méthode d’appel de demande WCF-client interne, gérer toutes les exceptions internes et les erreurs codées en dur renvoyées par le serveur, et déclencher l’événement Fault cas d’erreur, pseudo:

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

Ainsi, lorsque j’appelle myClient.GetHelloWorld() , il passe par ma méthode surchargée.

Comment cela peut il etre accompli?
Je sais que je ne suis pas obligé d’utiliser le client généré, mais je ne veux pas ClientBase tous les contrats et je veux utiliser la sous-classe ClientBase générée ou au moins son canal.
Ce dont j’ai besoin, c’est du contrôle de la méthode d’appel de requête interne.

Mettre à jour

J’ai lu cette réponse et j’ai IErrorHandler c’était en partie ce que je cherchais, mais je me demande s’il existe un moyen d’attacher un IErrorHandler au code du client (client) uniquement. Je souhaite l’append à la firebase database ClientBase par exemple en quelque sorte.

Mettre à jour

Cet article semble aussi très prometteur mais cela ne fonctionne pas. L’atsortingbut appliqué ne semble pas prendre effet. Je ne parviens pas à append IServiceBehavior au client.

Mettre à jour

J’ai essayé de joindre un IErrorHandler via IEndpointBehavior.ApplyClientBehavior appel IEndpointBehavior.ApplyClientBehavior :

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

( clientRuntime est un paramètre), mais des exceptions sont toujours MyErrorHandler ignorant directement MyErrorHandler .
ApplyDispatchBehavior n’est pas appelé du tout.

Conclusion

J’ai besoin de réaliser deux aspects:

  1. Enveloppez toutes les exceptions susceptibles de se produire pendant la durée de vie d’un BaseClient et décide si elles doivent être BaseClient . Cela devrait prendre en charge toutes les opérations (le service que je consum expose quelques dizaines de personnes)
  2. Analyser toutes les réponses de serveur et émettre des exceptions pour certaines d’entre elles afin qu’elles soient transférées comme dans l’instruction 1.

Vous pouvez utiliser et modifier le générateur de proxy WCF de gestion des exceptions , plus précisément la classe de base qu’il utilise. L’idée de base (vérifiez également cette description ) est de fournir la résilience de la connexion en attrapant les erreurs de connexion et en renouvelant l’opération ayant échoué. Comme vous pouvez l’imaginer, à cette fin, il doit pouvoir détecter les exceptions renvoyées et inspecter le résultat des appels.

La fonctionnalité principale est donnée par la classe de base ExceptionHandlingProxyBase , que vous utilisez à la place de ClientBase . Cette classe de base a une méthode Invoke comme suit, vous devrez le modifier.

Invoke simplifié:

 protected TResult Invoke(ssortingng 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; } 

Vous devrez modifier la throw targetEx.InnerException; partie pour gérer les exceptions que vous avez besoin, et évidemment la valeur resturn devrait également être inspecté pour vos besoins. Sinon, vous pouvez laisser la logique de nouvelle tentative ou la jeter si vous ne vous attendez pas à des problèmes de connexion. Il existe une autre variante des méthodes Invoke for void return.

Oh, et d’ailleurs, cela fonctionne également avec les canaux duplex, il existe une autre classe de base pour ceux-ci.

Si vous ne souhaitez pas utiliser le générateur (cela pourrait même ne pas fonctionner dans les versions les plus récentes de VS), vous pouvez simplement prendre la classe de base par exemple à partir d’ ici et générer la classe d’implémentation réelle avec T4 à partir de votre interface de service.

Si le service ne renvoie pas une véritable exception, mais simplement un message, vous souhaiterez probablement append ClientMessageInspector en tant que nouveau comportement du client. Veuillez consulter: https://msdn.microsoft.com/en-us/library/ms733786.aspx

J’ai fini par utiliser quelque chose basé sur les réponses à cette question.

Il s’en tient au code client généré et permet d’appeler les opérations de manière générique.

Le code est incomplet, n’hésitez pas à le bifurquer et à le modifier. S’il vous plaît, informez-moi si vous avez trouvé des bugs ou apporté des mises à jour.

C’est assez encombrant, je vais donc partager le code d’utilisation:

 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"); }