|
|
Browse by Tags
All Tags » Indigo » Faults (RSS)
-
When using a typed contract, incoming messages on the server are shredded on your behalf to be turned into method calls and parameters. Ordinarily, the particular method call selected for an application messages will have the same parameterized contract as the message. This allows the transformation between messages and parameters to be made with a high degree of fidelity. However, operations also permit fault responses in addition to the normal application response. The parameterized fault contract is going to look nothing like the standard application contract. Therefore, there's really no transformation that will take you from the fault message to the same parameterized contract in a way that makes any sense. The response that comes back from the server is unrepresentable using the standard data structure that the application is expecting to receive for an application response. This is why with a typed contract fault messages have to be expressed as an exceptional condition. Exceptions tend to transform the message with a much lower fidelity to the original content. With an untyped contract, incoming messages on the server are not shredded on your behalf but rather preserved in their entirety. You can think about this as performing the transformation between messages and parameters with perfect fidelity since the parameter is equal to the message. Similarly, any message response, whether it's a fault response or a normal application response, is also going to be representable with perfect fidelity. Both types of responses have the same format with an untyped contract so the application can handle them equally well. This is why with an untyped contract fault messages are preserved as messages. One of the major reasons for using untyped contracts is to have great fidelity with the wire. It wouldn't make sense to force the application to lose that fidelity for a certain class of messages. If you choose to in your application though, you can still run the same exception machinery. For details, read some of the past articles on creating and consuming faults . Next time: Streaming Web Content Read More...
|
-
FaultException supports both an untyped variant, for when you don't have any particularly interesting detail to provide, and a typed variant, for when you do. Don't use a subclass of Exception as the type of a typed FaultException. Here's why. When you use a typed FaultException, you are creating a fault contract between the client and service about data that gets exchanged and a common type system that the two share. By using a CLR exception type, you are unnecessarily forcing that common type system to reflect details of the CLR type system. That type dependency will make it more complicated in the future to move your services and clients to other platforms and possibly even to other versions of the framework. When moving to another version of the framework, you may change the exception profile of your application and start receiving exception types that are more specific or different than the exception types that you received before for a particular error. If you pass those exceptions through to the client, then those platform implementation details are now leaked across the service boundary. Finally, there's no guarantee that the interesting information in a CLR exception will be preserved across the boundary. Most of the interesting contents of exceptions are not serializable. Instead of creating a FaultException with a subclass of Exception, you should define a fault contract that is meaningful for your application or business user. This fault contract can be crafted according to the needs of your service and will remain independent of any particular platform or technology choices that you may need to make later. Next time: Faster Known Types in Orcas Read More...
|
-
How do I create a fault with multiple child nodes for the detail element? All of the overloads of CreateFault take a single argument for detail, which lets me build a tree of nodes but not a forest. The trick here is not to get hung up on trying to make the built-in convenience methods work. The object model for all of the message classes is just a wrapper around a way to interact with XML readers and writers. Notice that MessageFault is an abstract class. You can create your own subclasses to directly work against the underlying reader and writer. Also notice that there are only four methods that you have to override to make a MessageFault: Code, Reason, HasDetail, and OnWriteDetailContents. Code and Reason are parameters that you would have had to pass to CreateFault anyway. If you care about how the contents of the detail element are structured, then you definitely have a detail element. That really just leaves OnWriteDetailContents to implement, which is exactly what you wanted to precisely control the contents of the detail element. class MyMessageFault : MessageFault { FaultCode code; FaultReason reason; public MyMessageFault(FaultCode code, FaultReason reason) { this .code = code; this .reason = reason; } public override FaultCode Code { get { return this .code; } } public override bool HasDetail { get { return true ; } } protected override void OnWriteDetailContents(XmlDictionaryWriter writer) { // You can write whatever XML you want here } public override FaultReason Reason { get { return this .reason; } } } On the reverse side, you'll have exactly the same problem with GetDetail because it too is limited to a single object. In this case though, you have the replacement directly accessible, GetReaderAtDetailContents, and are more likely to already have been using it. Next time: Default ProtectionLevel for Standard Bindings Read More...
|
-
Let's build on a few earlier samples to actually demonstrate a working call context initializer. I'll start with yesterday's skeleton for a call context initializer and behavior . To that skeleton I'll add implementations of BeforeInvoke and AfterInvoke that initialize the operation thread with custom culture information and then clean the thread up once the operation return. class CultureInitializer : ICallContextInitializer { CultureInfo newInfo; public CultureInitializer(CultureInfo newInfo) { this .newInfo = newInfo; } public void AfterInvoke( object correlationState) { Thread.CurrentThread.CurrentCulture = correlationState as CultureInfo; } public object BeforeInvoke(InstanceContext instanceContext, IClientChannel channel, Message message) { CultureInfo oldInfo = Thread.CurrentThread.CurrentCulture; Thread.CurrentThread.CurrentCulture = newInfo; return oldInfo; } } Then, I'll fill out ApplyDispatchBehavior to apply my call context initializer to every operation on the given endpoint. class CultureInitializerBehavior : IEndpointBehavior { CultureInfo newInfo; public CultureInitializerBehavior(CultureInfo newInfo) { this .newInfo = newInfo; } public void AddBindingParameters(ServiceEndpoint endpoint, BindingParameterCollection bindingParameters) { } public void ApplyClientBehavior(ServiceEndpoint endpoint, ClientRuntime clientRuntime) { } public void ApplyDispatchBehavior(ServiceEndpoint endpoint, EndpointDispatcher endpointDispatcher) { foreach (DispatchOperation operation in endpointDispatcher.DispatchRuntime.Operations) { operation.CallContextInitializers.Add( new CultureInitializer(newInfo)); } } public void Validate(ServiceEndpoint endpoint) { } } Finally, I'll take last week's custom fault encoding sample and install my behavior. Notice that the only change at the service level is to add the behavior to the endpoint behavior collection. If I had written the code to apply the behavior in an attribute or configuration file, either of those approaches would have worked as well. [ServiceContract] public interface IMyService { [OperationContract] Message Fail(); } public class MyService : IMyService { public Message Fail() { XmlDocument document = new XmlDocument(); document.LoadXml( "<tag attributeName=\"value\"><moretags>blah</moretags></tag>" ); throw new FaultException<XmlElement>(document.FirstChild as XmlElement); } } public class Program { static void Main( string [] args) { string address = "http://localhost:8000/" Read More...
|
-
How can I directly craft the XML content that goes into a fault detail? Getting control over the detail element doesn't have to mean crafting the fault message yourself. While WCF requires that the fault detail be serializable using a data contract, remember that DataContractSerializer treats XmlElement as a special primitive type. This allows you to construct arbitrary content using XmlElement when your content can be represented as a rooted document. Due to the automatic conversion process of FaultException to a fault message, you don't need to construct a data contract to act as a wrapper. Here's a sample that builds some content in an XmlElement and uses it to construct a fault. I made the method return a Message so that I could look at the response more easily but you can use any contract you want. [ServiceContract] public interface IMyService { [OperationContract] Message Fail(); } public class MyService : IMyService { public Message Fail() { XmlDocument document = new XmlDocument(); XmlElement root = document.CreateElement( "tag" ); root.SetAttribute( "attributeName" , "value" ); XmlElement subtag = document.CreateElement( "moretags" ); subtag.InnerText = "blah" ; root.AppendChild(subtag); throw new FaultException<XmlElement>(root); } } public class Program { static void Main( string [] args) { string address = "http://localhost:8000/" ; BasicHttpBinding binding = new BasicHttpBinding(); ServiceHost host = new ServiceHost( typeof (MyService), new Uri(address)); host.AddServiceEndpoint( typeof (IMyService), binding, "" ); host.Open(); ChannelFactory<IMyService> factory = new ChannelFactory<IMyService>(binding); IMyService proxy = factory.CreateChannel( new EndpointAddress(address)); Message response = proxy.Fail(); Console.WriteLine(response.ToString()); Console.ReadLine(); host.Close(); } } That code produces a fault message that looks like the following. < s:Envelope xmlns:s ="http://schemas.xmlsoap.org/soap/envelope/" > < s:Header /> < s:Body > < s:Fault > < faultcode > s:Client </ faultcode > < faultstring xml:lang ="en-US" > The creator of this fault did not specify a Reason. </ faultstring > < detail > < tag attributeName ="value" > < moretags > blah </ moretags > </ tag > </ detail > </ s:Fault > </ s:Body > </ s:Envelope > Depending on how much hand-crafting you want, XmlDocument lets you simplify the process even further. For Read More...
|
-
When the service sends a fault message with a large detail, my client is unable to read the fault. Changing the standard settings for the maximum message size doesn't help. How can I read large fault messages? Fault messages have their own special quota that can be configured on the client proxy. For changing the settings of a proxy, you should immediately think about using a behavior. Luckily, that happens to work in this case. There is a MaxFaultSize property on the ClientRuntime, which we can get access to by supplying an IEndpointBehavior. public class SetMaxFaultSizeBehavior : IEndpointBehavior { int size; public SetMaxFaultSizeBehavior( int size) { this .size = size; } public void AddBindingParameters(ServiceEndpoint endpoint, BindingParameterCollection bindingParameters) { } public void ApplyClientBehavior(ServiceEndpoint endpoint, ClientRuntime clientRuntime) { clientRuntime.MaxFaultSize = size; } public void ApplyDispatchBehavior(ServiceEndpoint endpoint, EndpointDispatcher endpointDispatcher) { } public void Validate(ServiceEndpoint endpoint) { } } Let's use our new behavior to play with fault sizes. I've got a service that sends back a fault with no content, but we still have to deal with however big the rest of the fault message is. Then, the client will try connecting to the service with different maximum fault sizes to see what sizes work and what sizes don't. [ServiceContract] public interface IService { [OperationContract] void Operation(); } public class Service : IService { public void Operation() { throw new FaultException< string >( "" ); } } class Program { static void Main( string [] args) { Binding binding = new BasicHttpBinding(); string uri = "http://localhost:8000/" ; ServiceHost host = new ServiceHost( typeof (Service)); host.AddServiceEndpoint( typeof (IService), new BasicHttpBinding(), uri); host.Open(); int maxFaultSize = 1; while ( true ) { ChannelFactory<IService> factory = new ChannelFactory<IService>(binding, new EndpointAddress(uri)); factory.Endpoint.Behaviors.Add( new SetMaxFaultSizeBehavior(maxFaultSize)); factory.Open(); IService proxy = factory.CreateChannel(); try { proxy.Operation(); } catch (FaultException fault) { Console.WriteLine( "Received fault with maxFaultSize={0}." , maxFaultSize); break ; } catch (QuotaExceededException exception) { Console.WriteLine( "Exceeded quota with maxFaultSize={0}." , maxFaultSize); } finally { factory.Close(); } maxFaultSize++; } host.Close(); Console.ReadLine(); Read More...
|
-
The code yesterday was meant to motivate a side-discussion on how faults get generated and handled between the server and client proxy. If you tried running that sample, then you would have seen that despite the FaultException being thrown on the service, the service call completes normally. The return value of the service call is a fault message. If you've been writing your contracts with typed messages instead of the raw Message type, then this is the opposite behavior to what you're used to seeing. Using the same pattern for exception handling doesn't work between typed and untyped messages. This is particularly messy when you have a mix of typed and untyped operation contracts on the same service because it requires some duplicated logic for handling errors. However, I think that would be a pretty rare service design. There are four cases that I think are interesting to look at so that you can see the different fault behaviors that could occur. Untyped fault exception with an untyped message contract The basic case from yesterday is to receive a fault message. < s:Envelope xmlns:s ="http://www.w3.org/2003/05/soap-envelope" xmlns:a ="http://www.w3.org/2005/08/addressing" > < s:Header > < a:Action s:mustUnderstand ="1" > http://www.w3.org/2005/08/addressing/soap/fault </ a:Action > < a:RelatesTo > urn:uuid:dd129ffe-a8ff-4a70-ad6f-ad48085e94e8 </ a:RelatesTo > < a:To s:mustUnderstand ="1" > http://www.w3.org/2005/08/addressing/anonymous </ a:To > </ s:Header > < s:Body > < s:Fault > < s:Code > < s:Value > s:Sender </ s:Value > </ s:Code > < s:Reason > < s:Text xml:lang ="en-US" > boo! </ s:Text > </ s:Reason > </ s:Fault > </ s:Body > </ s:Envelope > Typed fault exception with an untyped message contract I'm just changing the FaultException to a FaultException here, although you can have any type you want for the fault detail. This changes the contents of the fault message but not the code path. Note that the action is different in addition to the detail section to match the parameterized type. < s:Envelope xmlns:s ="http://www.w3.org/2003/05/soap-envelope" xmlns:a ="http://www.w3.org/2005/08/addressing" > < s:Header > < a:Action s:mustUnderstand ="1" > http://tempuri.org/IService/VerbStringFault </ a:Action > < a:RelatesTo > urn:uuid:49ee87c7-691f-48c4-86ea-bb172c99294d </ a:RelatesTo > < Read More...
|
-
What does this code print? It seems like both choices are quite reasonable. I'll have some discussion about this tomorrow. [ServiceContract] interface IService { [OperationContract(Action= "foo" )] Message Verb(Message input); } class Service : IService { public Message Verb(Message input) { throw new FaultException( "boo!" ); } } class Program { static void Service() { ServiceHost host = new ServiceHost( typeof (Service), new Uri( "net.tcp://localhost/" )); host.AddServiceEndpoint( typeof (IService), new NetTcpBinding(), "" ); host.Open(); Console.ReadLine(); } static void Main( string [] args) { new Thread( new ThreadStart(Service)).Start(); Binding binding = new NetTcpBinding(); ChannelFactory<IService> factory = new ChannelFactory<IService>(binding, "net.tcp://localhost/" ); IService proxy = factory.CreateChannel(); try { Message response = proxy.Verb(Message.CreateMessage(binding.MessageVersion, "foo" )); Console.WriteLine( "Received message" ); Console.WriteLine(response.ToString()); } catch (FaultException fault) { Console.WriteLine( "Received fault" ); Console.WriteLine(fault.ToString()); } } } Next time: A Trick with Faults (Discussion) Read More...
|
-
What should I set the action parameter to when creating a FaultException? There is indeed a pair of overloads for creating fault exceptions that take an action parameter, although most of the overloads lack this. public FaultException(TDetail detail, FaultReason reason, FaultCode code, string action); public FaultException(TDetail detail, string reason, FaultCode code, string action); What does the action parameter actually do? Well, this may or may not be obvious, but setting the action on the fault exception controls the action that is used when sending the fault message. This is the reason why you can't just make up an action here and expect it to work. The receiver is looking for a particular action to reconstitute the fault message to an exception with the appropriate type. If you break the action here, then your typed FaultException turns into an untyped FaultException. The expected action value for a particular typed FaultException comes from the fault contract. If you just set up the fault contract and don't worry at all about the action when creating fault exceptions, then everything should work. The fault exception will automatically pick up the correct action from the fault contract. The answer then is that you shouldn't set the action parameter at all in most cases. The default fault contract action is generated by combining a number of type strings. For instance, if my service contract is IService, my operation is called Action, and I'm using a typed FaultException<string> instance, then the default fault action is http://tempuri.org/IService/ActionStringFault . Similarly, if I'm instead using a typed FaultException<IList<string>>, then the default fault action is http://tempuri.org/IService/ActionIListOf_StringFault . You can get as crazy as you want and figure out what the expected pattern should be for any type. Want to send an IDictionary<IList<string>, IDictionary<DateTime, string>>? It will be http://tempuri.org/IService/ActionIDictionaryOf_IListOf_String_IDictionaryOf_DateTime_StringFault . Of course, you can explicitly put an action in the fault contract attribute to set this value to anything. Next time: Transport Encryption and Signing Read More...
|
-
I don't know how many people use the code I post, but I frequently stumble across peculiar or interesting behavior while trying to get the snippets working. If the behavior relates to the topic I'm trying to explain, then it goes in the article. If the behavior is something off to the side, then I'll frequently plan to write a future article and end up never getting around to it. Today's article is actually from the IErrorHandler that I showed yesterday although it has nothing at all to do with the problem of changing HTTP status codes. Let's look at that error handler again with the addition of some debugging statements that I was trying to use. class HttpErrorHandler : IErrorHandler { public bool HandleError(Exception error) { Console.WriteLine(OperationContext.Current.IncomingMessageHeaders.To); return false ; } public void ProvideFault(Exception error, MessageVersion version, ref Message fault) { Console.WriteLine(OperationContext.Current.IncomingMessageHeaders.To); if (fault != null ) { HttpResponseMessageProperty properties = new HttpResponseMessageProperty(); properties.StatusCode = HttpStatusCode.PaymentRequired; fault.Properties.Add(HttpResponseMessageProperty.Name, properties); } } } Adding these debugging statements turns out to cause the service to fail in an unexpected way, which I thought was pretty interesting. I was only using ProvideFault last time, but I put the statements in both HandleError and ProvideFault. If you'll recall, ProvideFault was being used to modify the message fault as it was being generated. HandleError controls whether the exception at fault should result in the affected state being torn down. I return false from HandleError because this error handler definitely does nothing to handle the exception. The whole point of the example was to have things fail after all. If you run this code though, the debugging statement in ProvideFault works fine but the same statement in HandleError results in an ObjectDisposedException. By poking around, it turns out that between the time ProvideFault is called and HandleError is called, parts of the current message are already starting to go away. ProvideFault can safely use the OperationContext but that's not true for HandleError. Is there any practical implication of this behavior? Well, if your ability to handle errors depends upon some information in the message, then you're going to have a problem when it comes to HandleError. I don't know of a pleasant way to solve this. The unpleasant Read More...
|
-
Let's pick up where we left off last time with the question… How do I modify the HTTP status code that gets sent back with a fault? It's clear that we need to plug into the fault generation process somehow, but in past articles we've only seen fault handling for channels rather than services. Is there an equivalent for FaultConverter that we can use with our service? Well, partially. There's an IErrorHandler interface that very slightly overlaps the functionality of FaultConverter, but fortunately that's exactly the part we need. IErrorHandler allows us to replace the message faults that get created by the service. We can modify the status code by attaching a message property to the fault for the HTTP response. Here's what that looks like. I'll change the normal internal server error status code to one that indicates that the service requires payment to make the method call. class HttpErrorHandler : IErrorHandler { public bool HandleError(Exception error) { return false ; } public void ProvideFault(Exception error, MessageVersion version, ref Message fault) { if (fault != null ) { HttpResponseMessageProperty properties = new HttpResponseMessageProperty(); properties.StatusCode = HttpStatusCode.PaymentRequired; fault.Properties.Add(HttpResponseMessageProperty.Name, properties); } } } Now, we need some way to attach this error handler to the service. Since this example is using IIS hosting, there are fewer points to hook in as we don't own the service host. I'll create a new server behavior attribute that attaches an IErrorHandler instance to the service. As IErrorHandler interfaces with the service dispatcher, I need to fish out the dispatchers from the service host. class ErrorBehaviorAttribute : Attribute, IServiceBehavior { Type errorHandlerType; public ErrorBehaviorAttribute(Type errorHandlerType) { this .errorHandlerType = errorHandlerType; } public void Validate(ServiceDescription description, ServiceHostBase serviceHostBase) { } public void AddBindingParameters(ServiceDescription description, ServiceHostBase serviceHostBase, Collection<ServiceEndpoint> endpoints, BindingParameterCollection parameters) { } public void ApplyDispatchBehavior(ServiceDescription description, ServiceHostBase serviceHostBase) { IErrorHandler errorHandler; errorHandler = (IErrorHandler)Activator.CreateInstance(errorHandlerType); foreach (ChannelDispatcherBase channelDispatcherBase in serviceHostBase.ChannelDispatchers) { ChannelDispatcher channelDispatcher = channelDispatcherBase Read More...
|
-
Back to errors and faults for a bit with this two part series on modifying the HTTP status code used for fault messages. First, we'll need some background. What happens at the HTTP level when a web service encounters a problem? That's a good question because it's not clear at all from programming the service what's going to happen under the covers. Let's build a service and find out. Here's the simplest web service I could think of that has a slight problem. I'll be hosting this in IIS so there's no other code needed to get going. You can imagine the configuration that goes along with this service, but I'm going to omit any discussion of that because it won't be relevant to anything we have to look at. [ServiceContract] public interface IService { [OperationContract(Action = "*" , ReplyAction = "*" )] Message Action(Message m); } public class Service : IService { public Message Action(Message m) { throw new FaultException( "!" ); } } We can cut all the crud out of the messages by using a POX binding: a text encoder with MessageVersion set to None and a normal HTTP transport. Now, we can run this service and see what happens. I'm just going to telnet to the service address so that we can easily see all of the HTTP headers. HTTP/1.1 500 Internal Server Error Content-Type: application/xml; charset=utf-8 Server: Microsoft-IIS/7.0 X-Powered-By: ASP.NET Date: Tue, 10 Jan 2007 06:25:16 GMT Connection: close Content-Length: 159 < Fault xmlns ="http://schemas.microsoft.com/ws/2005/05/envelope/none" >< Code >< Value > Sender </ Value ></ Code >< Reason >< Text xml:lang ="en-US" > ! </ Text ></ Reason ></ Fault > This shows us that our service fault exception results in an HTTP status code of 500 for the response. The body of the message is something that looks a lot like a SOAP fault, but smaller because we said we weren't going to use SOAP. Inside the fault message you can see the fault elements that we talked about in past articles, and it's clear that we can modify anything inside the fault. It's not clear though what we modify to alter the framing of the HTTP response. That brings us to the actual question for this pair of articles. How do I modify the HTTP status code that gets sent back with a fault? We'll answer that question next time, which is going to require writing a bit more code. Next time: Modifying HTTP Error Codes, Part 2 Read More...
|
-
The last piece of this eleven part series on fault messages covers advice for channel authors that need to define their own set of faults. Everything here assumes that you're writing a protocol channel, that you have interesting failure cases that need to be acted on programmatically, and that your protocol does not overlap an existing protocol, such as security, reliable messaging, or transactions. By now, you should either be familiar with all of the classes involved with faults or going back to read the previous articles in the series. Basics of Failure Creating Faults, Part 1 Creating Faults, Part 2 Creating Faults, Part 3 The Most Distinguished Fault A Historical, Awkwardly Named Fault Consuming Faults, Part 1 Consuming Faults, Part 2 Zen Faults Faults and HTTP Let's start with the basic definition of a SOAP fault. It's mandatory to have a fault action, fault code, and fault reason. The fault detail is optional. The fault action is the first round of filtering performed on faults and so you should define an action that is unique to your protocol. Every fault that you create for the protocol should have this same action. Following this rule helps you and everyone else quickly sort out the faults that you need to handle and let everything else go up to the next protocol layer. The fault code should be unique to each expected type of recovery action. For instance, if you have two faults that you need to programmatically handle in a different fashion, then those faults should have different fault codes. If you have two faults that are semantically the same, then those faults should have the same fault code but different fault reasons. Every fault should have its own descriptive fault reason that explains why the fault occurred and what the user should do. Fault reasons are localizable if you're translating your application into multiple languages. The final piece is the fault detail, which you should only provide if you have some extra information that hasn't been covered by one of the previous parts. Your channel should throw exceptions when an error occurs, following the standard rules for exceptions in a CommunicationObject, such as using subtypes of CommunicationException or TimeoutException. The granularity of new exception subtypes should be similar to the granularity of new fault codes. Your channel then needs to override GetProperty<FaultConverter> to provide a converter that translates back and forth between exceptions and fault messages. Your Read More...
|
-
I left HTTP error codes out of yesterday's post on zen faults because they're representative of a distinct class of out-of-band fault messages. Out-of-band faults map fault information to a transport-specific mechanism that carries the data outside of the normal message payload. Although we don't send a regulation SOAP fault message, there's still a clear concept of a message and the other side doesn't have to rely on intuition to know that a fault took place. In the case of HTTP, the first line of a response contains status information that can be used to signify an error. There is a tradeoff to using this mechanism because SOAP faults are significantly richer than HTTP status codes while HTTP status codes are much more broadly understood by devices and programs. The status codes we care about lay in the 400 and 500 ranges. Codes in the 400 range are used for client errors and codes in the 500 range are used for server errors. Code 400 represents a generic error with the client request with additional definitions for codes 401 through 417. Similarly, code 500 represents a generic error happening on the server with additional definitions for codes 501 through 505. A code 400 error would represent something like an uninterpretably mangled request message. The common code 404 (Not Found) error represents EndpointNotFound while the much less common code 415 error (Unsupported Media Type) represents an InvalidContentType for the SOAP message. A code 500 error would represent something like a catastrophic service error, such as the code for the service can't be compiled. The only other common server error is code 503 (Service Unavailable). Code 503 errors typically represent unavailability due to server load, roughly the equivalent of ServerTooBusy. Next time: Designing New Faults Read More...
|
-
I've been talking about fault messages for a while now, specifically the kind that are sent around as the body contents of a SOAP message. However, some of the most important faults are reported without sending a message at all. In that case, we have to intuit that a fault has occurred based on the other sources that we can observe. I'll cover a special case of these zen faults, faults over HTTP status codes, tomorrow. There are plenty of examples of such faults that don't involved HTTP though. How are faults transmitted without sending messages? And, why do we do this? Throughout this post I'm assuming that we're just talking about faults in the underlying system. There are plenty of ways for applications to zen fault the other side through ungraceful shutdowns or arbitrary behavior. This is especially caused by Abort, which simply disposes of all network resources without bothering to clean up after itself (certain protocol channels, such as transactions, may attempt to salvage the situation but that's another matter). The zen fault that most everyone has probably seen is an EndpointNotFound. We sometimes have to intuit that fault based on a connection being closed or refused. Occasionally, the endpoint has legitimately gone missing. Frequently though, our intuitive guess about the fault is wrong. More likely problems are an error in configuration, the presence of firewalls, or the server simply being too busy to accept the connection in time. All of these situations can make it look like a service isn't running at all. Another common zen fault is the result of a quota being exceeded. Quota faults often manifest themselves as "Remote connection aborted" type errors. The other side has decided that it has spent too many resources on this connection and doesn't want to spare any more sending back a fault message. The client has little or no indication of what went wrong as there's no way to determine why the server closed the connection. This type of fault is basically indistinguishable from an arbitrary call to Abort. In order to diagnose the fault successfully, you need to look at trace logs on the server where notice of the quota exception is recorded. You may be hinted to the presence of a quota fault by the problem occurring reliably at "round" numbers, such as 60 seconds, 65536 bytes, or 10 connections. The last type of common zen fault occurs when there's a fault prior to the caller's identity being verified (for instance, if the identity verification Read More...
|
|
|
|