Übersicht: In diesem Abschnitt werden hauptsächlich Ausnahmen und simulierte Ausnahmen beschrieben, die bei Dienstaufrufen auftreten können. Außerdem wird analysiert, wann und welche Ausnahmen abgefangen werden können und wie Dienstausnahmen korrekt an den Client übergeben werden.
Am Ende des Artikels wird die Abfangsequenz zum korrekten Abfangen von Ausnahmen angegeben. Diese Ausnahmeerfassung ist nur eine Einführung, und einige davon sind Anwendungsfunktionen, sodass der Code und das Schreiben relativ einfach sind. Außerdem werden einige Techniken zur Ausnahmebehandlung auf der Serverseite vorgestellt.
1. Zuerst erstellen wir einen einfachen Rechnerserver und -client wie folgt:
Klicken Sie, um den Code zu erweitern
//Server[ServiceContract]public interface ICalc{[OperationContract][FaultContract(typeof(GreentingError))]string Div(int x, int y);}public class Calc : ServiceBase, ICalc {public string Div(int x, int y ) ) {string result = string.Empty; try {result: {0}", x / y); Catch (DivideByZeroException ex) {throw ex;}//Client [ServiceContract] öffentliche Schnittstelle ICalc { [OperationContract] [FaultContract(typeof(GreentingError))] string Div(int x, int y); } public class CalcClient : ClientBase<ICalc>, ICalc{ public string Div(int x, int y ) ) {return base.Channel.Div(x, y);
Okay, ich gebe zu, dass der Code recht einfach ist, aber ich mag einfache Dinge.
2. Einfache Dinge sind gut und es ist viel einfacher, sie zu benennen.
try { CalcClientcalcclient = new CalcClient(); Console.WriteLine(result); {throw ex; ex) {throw ex; } Catch (FaultExceptionex) {throw ex; Catch (System.ServiceModel.CommunicationException) {throw ex;
3. Wenn wir die Div(int x, int y)-Methode des Dienstes aufrufen und den Wert 0 an den Logarithmus y übergeben, löst der Server eine erwartete DivideByZeroException-Ausnahme aus. Zu diesem Zeitpunkt,
Diese Ausnahme wird im FaultException-Abschnitt des Clients abgefangen.
4. Kein Problem, wir werden FaultException manuell im Servercode auslösen.
Catch (DivideByZeroException ex){FaultExceptionException = new FaultException(ex.Message);}
Zu diesem Zeitpunkt habe ich festgestellt, dass FaultException diese Ausnahme abgefangen hat.
5. Führen Sie einen weiteren Test durch.
Fügen Sie diesen Code zum Dienst hinzu: System.Threading.Thread.Sleep(70000); um eine Zeitüberschreitung des Dienstes zu verursachen.
Dieses Mal hat TimeOutException endlich die Serverausnahme abgefangen, also müssen wir uns fragen: Wann wird FaultException<GreentingError> die Ausnahme abfangen? Die Antwort lautet: Wenn der Server FaultException<GreentingError> auslöst, zitieren Sie eine Passage auf MSDN (grüner Teil):
Wenn der Listener einen SOAP-Fehler empfängt, der nicht erwartet oder im Operationsvertrag angegeben ist, wird ein FaultException-Objekt ausgelöst. Es können zwei Arten von SOAP-Fehlern gesendet werden: deklarierte und nicht deklarierte. Ein deklarierter SOAP-Fehler ist ein Fehler, bei dem ein Vorgang über das System.ServiceModel.FaultContractAttribute-Attribut verfügt, das einen benutzerdefinierten SOAP-Fehlertyp angibt. Nicht deklarierte SOAP-Fehler sind Fehler, die nicht im Vertrag des Vorgangs angegeben sind. Der „unerwartete oder nicht angegebene SOAP-Fehler“ bezieht sich hier auf einen benutzerdefinierten Fehlertyp, der im Dienstvorgang nicht mit FaultContractAttribute umschlossen ist.
6. Wann wird die CommincationException abgefangen?
MSDN sagt: Die Anwendung verarbeitet CommunicationException-Objekte, die während der Kommunikation ausgelöst werden können
Um diese Ausnahme auszulösen, gehen wir wie folgt vor. Schließen Sie zunächst das aktuelle Kanalobjekt auf dem Server.
OperationContext.Current.Channel.Close();
Leider hat der Client nicht die CommunicationException, sondern die TimeOutException abgefangen! Da nach dem Schließen des Servicekanals keine Ausnahme auftrat, wurde keine Nachricht an den Client zurückgegeben. Nach einer bestimmten Wartezeit kam es zu einer Zeitüberschreitung des Clients und er wurde beendet.
Daher geben wir beim Schließen des Kanals eine TimeSpan an. Dadurch kann der Anruf sofort zurückgegeben werden. Natürlich kann die Anrufrückgabe auch über Channel.Abort erfolgen.
OperationContext.Current.Channel.Close(new TimeSpan(5000));
Geben Sie beim Aufrufen der Close-Methode von IContextChannel die Zeit an, zu der der Sendevorgang vor dem Timeout abgeschlossen sein muss, damit die Nachricht innerhalb der angegebenen Zeit sofort zurückgegeben werden kann, ohne auf das Timeout des Dienstaufrufs warten zu müssen, andernfalls wird der Client definitiv ausgelöst eine TimeOutException-Ausnahme anstelle einer CommunicationException-Ausnahme.
7. Abhilfemaßnahmen
Um gleichzeitig Abhilfemaßnahmen zu ergreifen, wenn im Dienst eine Ausnahme auftritt, haben wir eine neue abstrakte Klasse ServiceBase erstellt und die Implementierungsklasse des Calc-Dienstes davon erben lassen, sodass wir die Kontrolle über die verschiedenen Zustandsübergänge von erhalten können der Dienst. Die ServiceBase-Klasse lautet wie folgt:
öffentliche abstrakte Teilklasse ServiceBase { private IContextChannelchannel = null; protected ServiceBase() {channel = OperationContext.Current.Channelchannel.Opening += new EventHandler(delegate(object sender, EventArgs e) {/* TO DO*/ }) ;channel.Opened += new EventHandler(delegate(object sender, EventArgs e) {/* TO DO*/ }channel.Closing += new EventHandler(delegate(object sender, EventArgs e) {/* TO DO*/ }); channel.Closed += new EventHandler(delegate(object sender, EventArgs e) { Abort(); }); ; } void Open() {/* TO DO*/ } void Close() { /* TO DO*/} void Abort() { channel.Abort( }}
Wie aus dem obigen Code ersichtlich ist, stoppen wir den Dienst sofort, nachdem der Dienstkanal geschlossen wurde, und lassen die Nachricht sofort zurückkehren, selbst wenn der Dienst während des Vorgangs geschlossen wird, ohne die Timeout-Abschlusszeit anzugeben kann trotzdem sofort zurückkehren.
Diesmal hat der Client endlich die CommunicationException abgefangen, wie in der folgenden Abbildung dargestellt:
Warum passiert das?
8. Werfen wir einen Blick auf die Vererbungshierarchie von CommunicationException, von der wir uns inspirieren lassen können.
8.1. Die erste ist die Vererbungshierarchie von FaultException<TDetail>.
8.2, wieder die Vererbungshierarchie von TimeOutException.
9. Wie aus der obigen Abbildung ersichtlich ist, erben TimeOutException und CommunicationException beide von der SystemException-Klasse, während FaultException von CommunicationException erbt und schließlich FaultException<TDetail> von der FaultException-Klasse erbt.
10. Schließlich kamen wir zu dem Schluss, dass die richtige Reihenfolge zum Abfangen von Ausnahmen auf dem Client wie folgt aussehen sollte:
TimeOutException> FaultException<TDetail> > FaultException > CommunicationException > Ausnahme. Es wird dringend empfohlen, dass Entwickler Ausnahmen vom Typ FaultException<TDetail> auslösen und abfangen.
Autor: Lao Mi Quelle: http://www.cnblogs.com/viter/
Das Urheberrecht dieses Artikels liegt beim Autor und bei Blog Park. Ein Nachdruck ist jedoch ohne Zustimmung des Autors gestattet und ein Link zum Originaltext muss an einer offensichtlichen Stelle auf der Artikelseite angebracht werden. die Geltendmachung einer gesetzlichen Haftung bleibt vorbehalten.