Quelle est la meilleure solution pour la WCF client à l'aide de " bloquer problème?
J'aime l'instanciation de mon service WCF clients au sein d'un using
bloc comme il est à peu près la norme de façon à utiliser les ressources qui mettent en œuvre des IDisposable
:
using (var client = new SomeWCFServiceClient())
{
//Do something with the client
}
Mais, comme indiqué dans cet article MSDN, l'enveloppant d'un WCF client dans un using
bloc pourrait masquer les erreurs qui en résultent dans le client se retrouve dans une reproché à l'etat (comme un délai d'attente ou de problème de communication). Longue histoire courte, lorsque dispose() est appelée, la méthode Close() les feux, mais renvoie une erreur car il est dans un état faulted. L'exception d'origine est alors masqué par la deuxième exception. Pas bonne.
La solution de contournement proposée dans l'article MSDN est d'éviter complètement à l'aide d'un using
bloc, et au lieu d'instancier vos clients et de les utiliser quelque chose comme ceci:
try
{
...
client.Close();
}
catch (CommunicationException e)
{
...
client.Abort();
}
catch (TimeoutException e)
{
...
client.Abort();
}
catch (Exception e)
{
...
client.Abort();
throw;
}
Par rapport à la using
bloc, je pense que c'est laid. Et beaucoup de code à écrire à chaque fois vous avez besoin d'un client.
Heureusement, j'ai trouvé quelques autres solutions, comme celle-ci sur IServiceOriented. Vous commencez avec:
public delegate void UseServiceDelegate<T>(T proxy);
public static class Service<T>
{
public static ChannelFactory<T> _channelFactory = new ChannelFactory<T>("");
public static void Use(UseServiceDelegate<T> codeBlock)
{
IClientChannel proxy = (IClientChannel)_channelFactory.CreateChannel();
bool success = false;
try
{
codeBlock((T)proxy);
proxy.Close();
success = true;
}
finally
{
if (!success)
{
proxy.Abort();
}
}
}
}
Ce qui permet alors:
Service<IOrderService>.Use(orderService =>
{
orderService.PlaceOrder(request);
});
C'est pas mal, mais je ne pense pas que c'est expressive et facilement compréhensible que la using
bloc.
La solution de contournement, je suis en train d'essayer de les utiliser j'ai lu à ce sujet sur blog.davidbarret.net. Fondamentalement, vous remplacez le client Dispose()
méthode partout où vous les utilisez. Quelque chose comme:
public partial class SomeWCFServiceClient : IDisposable
{
void IDisposable.Dispose()
{
if (this.State == CommunicationState.Faulted)
{
this.Abort();
}
else
{
this.Close();
}
}
}
Cela semble être en mesure de permettre la using
bloc de nouveau, sans le danger de masquage d'une reproché à l'état d'exception.
Donc, existe-il d'autres astuces que j'ai à regarder dehors pour l'utilisation de ces solutions de contournement? A quelqu'un de venir avec quelque chose de mieux?
- Le dernier (qui inspecte cette.De l'état) est une course; elle ne pourrait pas être prise en défaut lorsque vous vérifiez le booléen, mais peut être prise en défaut lorsque vous appelez Close().
- Vous lisez état; elle n'est pas prise en défaut. Avant de vous appeler Close(), le canal de défauts. Close() throws. Game over.
- Le temps passe. Il peut être une très courte période de temps, mais techniquement, dans la période de temps entre la vérification de l'état du canal et de lui demander de fermer le canal de l'état peut changer.
- Je suis allé avec la solution trouvée ici: omaralzabir.com/do-not-use-using-in-wcf-client Bon sujet, malheureux, mais je suis content qu'il était là quand j'en avais besoin...
- Je voudrais utiliser
Action<T>
au lieu deUseServiceDelegate<T>
. mineure. - Je n'aime vraiment pas cette assistance statique
Service<T>
car elle complique les tests unitaires (comme la plupart statique de choses à faire). Je préfère qu'il soit non-statique qui peut être injecté dans la classe qui l'utilise. - Être conscient de ne pas faire de gros contrats WCF, sinon le premier démarrage à froid à l'aide de la ChannelFactory va tuer votre performance sur le premier appel. Vous pouvez bien sûr le cache de l'usine, mais pour les développeurs, c'est un cauchemar à chaque fois pour avoir ce démarrage à froid sur chaque départ.
- Juste couru à travers cela, mais n'ont pas enquêté sur: nuget.org/packages/ChannelAdam.Wcf
- gros contrats WCF les bonnes pratiques et modèles ? l'intégralité du code source de l'échantillon à l'aide de
Cache ChannelFactory
à l'aide de P&P ? Références: comment-faire-appel-wcf-service correctement et comment faire facilement appel de la wcf service correctement et dzimchuk.net/post/wcf-error-helpers - meilleure solution est une comment-faire-appel-wcf-service correctement . La meilleure explication à ce sujet et contient l'intégralité du code source.
Vous devez vous connecter pour publier un commentaire.
En fait, bien que je blogué (voir La réponse de luc), je pense que cette est mieux que mon IDisposable wrapper. Typique code:
(l'édition par les commentaires)
Depuis
Use
retourne void, le moyen le plus facile pour gérer les valeurs de retour est via une capture de variable:public static TResult Use<TResult>(Func<T, TResult> codeBlock) { ... }
https://devzone.channeladam.com/articles/2014/07/how-to-call-wcf-service-properly/
ethttps://devzone.channeladam.com/articles/2014/09/how-to-easily-call-wcf-service-properly/
ethttp://dzimchuk.net/post/wcf-error-helpers
https://devzone.channeladam.com/articles/2014/07/how-to-call-wcf-service-properly/
new ChannelFactory<T>("");
déclenche une exception n'a pas Pu trouver d'extrémité de l'élément avec le nom ". Ai-je raté quelque chose?Donné un choix entre la solution préconisée par IServiceOriented.com et la solution préconisée par David Barret blog, je préfère la simplicité offerte par des raisons impérieuses le client Dispose() de la méthode. Cela me permet de continuer à utiliser l'aide de() déclaration que l'on pourrait s'attendre à un objet jetable. Cependant, comme @Brian l'a souligné, cette solution contient une condition de concurrence en ce que l'État pourrait ne pas être prise en défaut lorsqu'il est vérifié, mais pourrait être par le temps de Fermer() est appelée, dans ce cas la CommunicationException se produit encore.
Donc, pour contourner ce problème, j'ai utilisé une solution qui allie le meilleur des deux mondes.
success
drapeau à tous? Pourquoi ne pastry { Close(); } catch { Abort(); throw; }
?Close(); success = true;
? Je ne veux pas d'une exception levée si je pouvais réussir à l'abandonner dans le bloc finally. J'avais envie d'une exception levée si l'Abort() a échoué dans ce cas. De cette façon, le try/catch serait de masquer le potentiel de la race état d'exception et toujours vous permettent d'abort() la connexion dans le bloc finally.J'ai écrit un d'ordre supérieur de la fonction pour le faire marcher droit. Nous avons utilisé dans plusieurs projets et il semble fonctionner à merveille. C'est la façon dont les choses ont été faites depuis le début, sans "l'aide" paradigme ou ainsi de suite.
Vous pouvez faire des appels comme ceci:
C'est à peu près juste comme vous avez dans votre exemple. Dans certains projets, nous écrivons fortement typé méthodes d'assistance, on se retrouve donc écrit des choses comme "Wcf.UseFooService(f=>f...)".
Je le trouve assez élégant, toutes choses considérées. Est-il un problème particulier vous rencontrés?
Cela permet à d'autres fonctionnalités intéressantes à être branché. Par exemple, sur un site, le site s'authentifie sur le service au nom de l'utilisateur connecté. (Le site n'a pas d'informations d'identification par lui-même.) Par l'écriture de notre propre "UseService" méthode helper, nous pouvons configurer le canal de l'usine de la façon dont nous voulons, etc. Nous sommes également pas lié à l'utilisation de l'généré procurations -- aucune interface n'.
GetCachedFactory
méthode?Microsoft, qui est le moyen recommandé pour traiter WCF client appelle:
Pour plus de détails voir: Prévu Des Exceptions
Des informations supplémentaires
Donc, beaucoup de gens semblent poser cette question sur WCF que Microsoft a même créé un dédié exemple pour montrer comment gérer les exceptions:
c:\WF_WCF_Samples\WCF\Basic\Client\ExpectedExceptions\CS\client
Télécharger l'échantillon:
C# ou VB
Considérant qu'il y a beaucoup de problèmes,impliquant l'utilisation de déclaration, (chauffée?) Des discussions à l'interne et fils sur cette question, je ne vais pas perdre mon temps à essayer de devenir un code de cow-boy et de trouver une manière plus propre. Je vais le sucer, et de mettre en œuvre WCF clients cette verbose (encore confiance) de manière, pour mon serveur d'applications.
Facultatif Échecs Supplémentaires pour attraper
De nombreuses exceptions dériver de
CommunicationException
et je ne pense pas que la plupart de ces exceptions doivent être rejugés. Je drudged par le biais de chacun d'exception sur MSDN et trouvé une courte liste de retry-mesure des exceptions (en plus deTimeOutException
ci-dessus). Ne laissez-moi savoir si j'ai raté une exception qui doit être retentée.Certes, c'est un peu banal de code à écrire. Actuellement, je préfère cette réponse, et ne vois pas de "hacks" dans ce code qui peuvent provoquer des problèmes sur la route.
"Hope this code wasn't important, because it might not happen."
est toujours exécutée...J'ai enfin trouvé quelques étapes solides vers une solution propre à ce problème.
Codeplex a lancé un projet appelé la gestion des exceptions WCF Générateur de Proxy. Essentiellement, il s'installe un nouvel outil personnalisé pour Visual Studio; 2008, puis utiliser cet outil pour générer le nouveau service de proxy (Ajouter une référence de service). Il a quelques belles fonctionnalités pour gérer les reproché canaux, les délais d'attente et l'élimination sans danger. Il y a une vidéo d'excellente qualité que l'on appelle ici ExceptionHandlingProxyWrapper expliquer exactement comment cela fonctionne.
Vous pouvez utiliser en toute sécurité les
Using
relevé à nouveau, et si le canal est reproché à toute demande (TimeoutException ou CommunicationException), le Wrapper de ré-initialiser le faillées canal et relancez la requête. Si cela échoue, alors il va appeler leAbort()
de commande et de disposer de la procuration et de relever de l'Exception. Si le service lance unFaultException
de code, il va s'arrêter, et la procuration sera annulée en toute sécurité en jetant l'exception correcte comme prévu.Basée sur les réponses de Marc Gravel, MichaelGG, et Matt Davis, nos développeurs sont venus avec les personnes suivantes:
Exemple d'utilisation:
C'est aussi près de la "aide" de la syntaxe que possible, vous n'avez pas à retourner une valeur factice lors de l'appel d'une méthode void, et vous pouvez faire plusieurs appels au service (et retourner plusieurs valeurs) sans avoir à utiliser des n-uplets.
Aussi, vous pouvez l'utiliser avec
ClientBase<T>
descendants au lieu de ChannelFactory si vous le souhaitez.La méthode d'extension est exposée si un développeur veut manuellement disposer d'un proxy/canal à la place.
DisposeSafely
privé est certainement une option, et d'éviter la confusion. Il peut y avoir des cas d'utilisation où quelqu'un aurait envie de l'appeler directement, mais je ne peux pas venir avec désinvolture.https://devzone.channeladam.com/articles/2014/07/how-to-call-wcf-service-properly/
@Marc Gravel
Ne serait-il pas autorisé à utiliser ce:
Ou, la même chose
(Func<T, TResult>)
en cas deService<IOrderService>.Use
Ces rendrait le retour des variables plus facile.
Qu'est-ce que cela?
C'est la CW version de la accepté de répondre mais avec (ce que je considère complète) la gestion des exceptions inclus.
La accepté de répondre à des références ce site qui n'est plus autour de. Pour vous sauver de la difficulté, je suis y compris les parties les plus pertinentes ici. En plus, je l'ai modifiée légèrement pour inclure exception nouvelle tentative de manipulation pour gérer ces satanés délais d'attente réseau.
WCF très Simple d'Utilisation Client
Une fois que vous générez votre côté client proxy, c'est tout ce que vous devez mettre en œuvre.
ServiceDelegate.cs
Ajouter ce fichier à votre solution. Aucune modification n'est nécessaire pour ce fichier, sauf si vous souhaitez modifier le nombre de tentatives ou des exceptions que vous souhaitez gérer.
PS: j'ai fait ce post un wiki de la communauté. Je ne recueillons pas de "points" à partir de cette réponse, mais je préfère vous upvote si vous êtes d'accord avec la mise en œuvre, ou de le modifier pour le rendre meilleur.
success == false
au final si l'instructionhttps://devzone.channeladam.com/articles/2014/07/how-to-call-wcf-service-properly/
, la plupart des solution correcte: 1) Effectuer la fermeture/Abandon modèle sans condition de course 2) Gérer la situation lorsque le fonctionnement du service, lève des exceptions 3) Gérer les situations où à la fois la Proximité et Abandonner les méthodes de lancer des exceptions 4) Gérer les exceptions asynchrones tels que la ThreadAbortException -What's about it?
Ci-dessous est une version améliorée de la source à partir de la question et étendu à cache canaux multiples usines et de tenter de rechercher le point de terminaison dans le fichier de configuration par le nom du contrat.
Il utilise .NET 4 (plus précisément: la contravariance, LINQ,
var
):UseServiceDelegate<T>
au lieu deAction<T>
?Action<T>
fonctionne tout aussi bien.Un wrapper de ce genre:
Qui devrait vous permettre d'écrire du code comme:
L'emballage pourrait bien sûr attraper plus d'exceptions, si cela est nécessaire, mais le principe reste le même.
Dispose
sur un IChannel il pourrait lever une exception si le canal est dans un état faulted, c'est un problème depuis que Microsoft préciser queDispose
ne devrait jamais jeter. Donc, ce que le code ci-dessus ne est chargé de l'affaire quandClose
déclenche une exception. SiAbort
jette il pourrait être quelque chose de grave. J'ai écrit un billet de blog à ce sujet en décembre dernier: blog.tomasjansson.com/2010/12/disposible-wcf-client-wrapperJ'ai utilisé Château dynamique de proxy pour résoudre le Dispose() problème, et également la mise en œuvre de l'actualisation automatique de la chaîne quand elle est dans un état inutilisable. Pour l'utiliser, vous devez créer une nouvelle interface qui hérite de votre contrat de service et IDisposable. La dynamique de proxy implémente cette interface et enroule une WCF canal:
J'aime cela, car vous pouvez injecter des services WCF, sans que les consommateurs ont besoin de vous soucier de tous les détails de la WCF. Et il n'y a pas d'ajout de fichiers inutiles comme les autres solutions.
Avoir un coup d'oeil au code, c'est en fait assez simple:
WCF Dynamique Proxy
Si vous n'avez pas besoin Cio ou sont générés automatiquement à l'aide d'un client (Service de Référence), alors vous pouvez simplement utiliser un wrapper pour gérer la fermeture et de laisser le GC prendre la clientbase quand il est dans un état de sécurité qui permettra de ne pas jeter d'exception. Le GC appel Jeter dans serviceclient, et cela appel
Close
. Depuis qu'il est alread fermé, il ne peut pas causer de dommages. Je me sers de ce sans problèmes dans le code de production.Puis lorsque vous accédez au serveur, vous créez le client et l'utilisation
using
dans le autodisconect:Utiliser une méthode d'extension:
Résumé
En utilisant les techniques décrites dans cette réponse, on peut consommer un service WCF dans un bloc using avec la syntaxe suivante:
Vous pouvez bien sûr adapter encore plus loin et d'atteindre une plus concis modèle de programmation spécifique à votre situation - mais le point est que nous pouvons créer une mise en œuvre de
IMyService
reprenting le canal qui implémente correctement le modèle jetable.Détails
Toutes les réponses jusqu'à présent aborder le problème de l'obtenir autour de le "bug" dans la WCF Canal de mise en œuvre de l'
IDisposable
. La réponse qui semble offrir le plus concis modèle de programmation (vous permettant d'utiliser lesusing
bloc de disposer sur les ressources non managées) est cette une - si le mandataire est modifiable à mettre en œuvreIDisposable
avec un bug de mise en œuvre libre. Le problème avec cette approche est la maintenabilité - nous devons ré-implémenter cette fonctionnalité pour jamais proxy que nous utilisons. Sur une variation de la réponse, nous allons voir comment nous pouvons utiliser composition plutôt que l'héritage de faire de cette technique générique.Première Tentative
Il ne semble pas que les différentes implémentations de la
IDisposable
mise en œuvre, mais pour la clarté de l'exposé, nous allons utiliser une adaptation de celui utilisé par la actuellement accepté de répondre à.Armé avec les classes ci-dessus, nous pouvons maintenant écrire
Cela nous permet de consommer notre service à l'aide de la
using
bloc:Faire de ce générique
Tout ce que nous avons fait jusqu'à présent consiste à reformuler Tomas solution. Qu'est ce qui empêche ce code générique est le fait que
ProxyWrapper
classe doit être mis en oeuvre pour chaque contrat de service que nous voulons. Nous allons maintenant examiner une classe qui nous permet de créer ce type dynamiquement à l'aide de l'IL:Avec notre nouvelle classe d'aide, nous pouvons maintenant écrire
Notez que vous pouvez également utiliser la même technique (avec de légères modifications) pour les auto-généré clients hérite pour
ClientBase<>
(au lieu d'utiliserChannelFactory<>
), ou si vous souhaitez utiliser une autre mise en œuvre deIDisposable
à proximité de votre chaîne.J'aime cette façon de fermeture de la connexion:
J'ai écrit une simple classe de base qui gère cela. Il est disponible comme un Package NuGet et il est très facile à utiliser.
De sorte qu'il permet d'écrire des instructions return joliment:
Je tiens à ajouter de mise en œuvre de Service de Marc Gravel réponse pour le cas de l'utilisation ServiceClient au lieu de ChannelFactory.
Pour ceux que cela intéresse, voici un VB.NET traduction de la accepté de répondre (ci-dessous). J'ai affiné un peu pour des raisons de concision, combinant quelques-uns des conseils par d'autres dans ce fil.
J'avoue que c'est hors-sujet pour les originaires des balises (C#), mais comme je n'étais pas en mesure de trouver un VB.NET la version de cette solution je suppose que d'autres seront à la recherche ainsi. Le Lambda de la traduction peut être un peu délicat, alors j'aimerais sauver quelqu'un les ennuis.
Noter que cette application offre la possibilité de configurer le
ServiceEndpoint
au moment de l'exécution.Code:
Utilisation:
L'architecture de notre système utilise souvent le L'unité Cio cadre pour créer des instances de ClientBase donc il n'y a pas de moyen sûr pour faire valoir ce que les autres développeurs utilisent même
using{}
blocs. Afin de le rendre aussi infaillible que possible, j'ai fait cette classe personnalisée qui s'étend ClientBase, et les poignées de fermeture du canal à jeter, ou à finaliser dans le cas où quelqu'un ne fait pas explicitement dispose de l'Unité créée instance.Il y a aussi des trucs qui devait être fait dans le constructeur pour le canal de badges personnalisés et des trucs, donc c'est ici aussi...
Puis un client peut simplement:
Et l'appelant peut faire aucune de ces:
J'ai évoqué quelques réponses sur ce post et de la personnaliser selon mes besoins.
Je voulais la possibilité de faire quelque chose avec WCF client avant de l'utiliser de sorte que le
DoSomethingWithClient()
méthode.Ici est la classe helper:
Et je peux l'utiliser comme:
J'ai ma propre enveloppe d'un canal qui met en Disposer comme suit:
Cela semble bien fonctionner et permet une aide de bloc pour être utilisé.
L'assistance suivante permet d'appeler
void
et non des méthodes void. Utilisation:La classe elle-même est:
Remplacer le client Dispose() sans la nécessité de générer une classe proxy basé sur ClientBase, aussi, sans la nécessité de gérer le canal de la création et de la mise en cache! (Notez que WcfClient n'est pas une classe ABSTRAITE et est basé sur ClientBase)
Ma méthode de le faire a été de créer une classe héritée explicitement implémente IDisposable. Ceci est utile pour les gens qui utilisent l'interface graphique pour ajouter une référence de service ( Ajouter une Référence de Service ). Je viens de déposer cette classe dans le projet de rendre le service de référence et d'utiliser à la place du client par défaut:
Note: Ceci est juste une mise en œuvre simple d'en disposer, vous pouvez mettre en œuvre plus complexe disposer logique si vous le souhaitez.
Vous pouvez alors remplacer tous vos appels avec le service régulier du client avec la sécurité des clients, comme ceci:
J'aime cette solution car elle ne nécessite pas de moi pour avoir accès aux définitions de l'Interface et je peux utiliser le
using
déclaration que je m'attends tout en permettant à mon code ressemble plus ou moins la même.Vous aurez toujours besoin pour gérer les exceptions qui peuvent être levées comme indiqué dans d'autres commentaires dans ce thread.
Vous pouvez également utiliser un
DynamicProxy
de prolonger laDispose()
méthode. De cette façon, vous pourriez faire quelque chose comme: