Fault Assembler
Dieses Dokument beschreibt das Erstellen und Einbinden von sogenannten Fault Assemblern auf Serviceebene. Durch die Verwendung von WCF-Diensten, müssen geworfene Ausnahmen in die für den Dienst definierten Fehlerverträge gewandelt werden (Muster Fehlervertrag). Diese Konvertierung wird servicespezifisch über einen Fault Assembler realisiert.
Implementierung
Der Klassenname besteht aus dem Dienstnamen und dem Postfix FaultAssembler
(Service: BuchService
=> Fault Assembler: BuchServiceFaultAssembler
).
Fault Assembler implementieren die Schnittstelle IFaultAssembler
und sind für jeden WCF-Dienst zu erstellen.
Es gibt dabei folgende vorhandene FaultAssembler:
Schleupen.CS.PI.Framework.Services.ErrorHandling.UnhandledFaultAssembler
Schleupen.CS.PI.Framework.Services.ErrorHandling.ValidationFaultAssembler
IdempotentOperationPendingFaultAssembler.IdempotentOperationPendingFaultAssembler
In der Methode CanAssemble()
wird angegeben, ob eine Ausnahme, die im Servercode aufgetreten ist, durch den Konverter konvertiert werden kann. Ist dies der Fall, wird die zweite methode ToDataContract()
aufgerufen. Dort wird dann die Umwandlung in eine FaultException
vorgenommen.
Das folgende Beispiel zeigt die Implementierung eines Fault Assemblers für einen BuchService
. Mit diesem wird die Ausnahme BuchNotFoundException
in den entsprechenden Fehlervertrag BuchNichtVorhandenFaultContract
konvertiert.
public class BuchEntityServiceFaultAssembler : IFaultAssembler { private readonly UnhandledFaultAssembler<UnhandledFaultContract> unhandeledFaultAssembler = new UnhandledFaultAssembler<UnhandledFaultContract>(); public bool CanAssemble(Exception exception) { if (exception is BuchNotFoundException) { return true; } return unhandeledFaultAssembler.CanAssemble(exception); } [SuppressMessage("Microsoft.Globalization", "CA1304:SpecifyCultureInfo", MessageId = "System.ServiceModel.FaultReason.#ctor(System.String)")] public FaultException ToDataContract(Exception exception) { var buchNotFoundException = exception as BuchNotFoundException; if (buchNotFoundException != null) { BuchNichtVorhandenFaultContract fault = new BuchNichtVorhandenFaultContract(); fault.BuchId = buchNotFoundException.BuchId.ToString(); return new FaultException<BuchNichtVorhandenFaultContract>(fault); } return unhandeledFaultAssembler.ToDataContract(exception); } }
Um den Assembler an den Dienst zu binden, muss dieser mit dem Attribut [ErrorHandlerBehavior(typeof(BuchServiceFaultAssembler))]
versehen werden.
[ErrorHandlerBehavior(typeof(BuchEntityServiceFaultAssembler))] public sealed class BuchService : IBuchService { // ... }
Es können mehrere FaultAssembler im ErrorHandlerBehavior eingetragen werden.
Bei Verwendung des UnhandledFaultAssembler
, muss dieser als letzter Eintrag in der Parameterliste angegeben werden, da dieser für CanAssemble()
immer true zurückgibt, wodurch spezielle Assembler übergangen würden.
Über die sogenannte GenericServiceTestBase
kann dies sichergestellt werden, indem die Eigenschaft PerformServiceImplementationHasErrorHandlerBehaviorAttributeTest
auf true
gesetzt wird.
Im Standard sollte der Anschluss wie folg aussehen:
[ServiceBehavior(IncludeExceptionDetailInFaults = true)] [ErrorHandlerBehavior( typeof(IdempotentOperationPendingFaultAssembler<IdempotentOperationPendingFaultContract>), typeof(ValidationFaultAssembler), typeof(UnhandledFaultAssembler<UnhandledFaultContract>))] [SuppressMessage("Microsoft.Naming", "CA1724:TypeNamesShouldNotMatchNamespaces", Justification = "Schnittstelle wird von Kamoto so generiert.")] public class BuecherAusleihenActivityService : IBuecherAusleihenActivityService { }