How do I get an HTTP status code from TTransport exceptions? - c#

I'm using a thrift HttpClient (C#) to make web requests to a web server I've set up, and if that server returns something other than 200 (or 202 I imagine), my request throws a TTransport exception.
I'd like to respond to this exception based on the specific status code returned, but I don't see anything that exposes the status code in the exception's interface. Have I missed something? I know the exception message contains the status code, but I'd rather not have to parse that message to get at the status code.

If the server encounters an processing error, the recommended method is not throwing a HTTP 500. Instead, the server should signal this by means of an exception. Consider the following Thrift IDL:
exception MyProcessingError
{
1: string reason
2: string errorDetails
3: string recommendedAction
}
service FooBar {
void ProcessPayments( 1: double amount; 2: string receiver)
throws (1: MyProcessingError mpe)
}
Similar to args and struct fields, multiple exception types can be declared. The client can catch these exceptions as usual:
try
{
client.ProcessPayments( 47.11, "Dagobert");
}
catch (MyProcessingError e)
{
// process exception
}
Remarks
The server may only throw exceptions that are declared in the IDL for
the particular call.
Furthermore, oneway calls never return any value, thus no
exceptions either.

Related

Passing exception data between two applications

I don't know if this has been already answered or not. But, I am unable to find the example or cause of this problem.
Application 1:
try
{
//Read request and check for the request header element from the soap request
//validating request and salt
...here it might gets failed.
_requestValidationService.ValidateRequest();
}
catch (Exception ex)
{
ex.Data.Add("Exception", "test");
throw ex;
}
Application 2:
catch (Exception ex)
{
string aa = Convert.ToString(ex.Data["Exception"]);
throw ex;
}
I don't know what I am missing here. But aa seems to be always empty and ex.Data.Count is always zero.
I just want to pass one code between two applications without adding new class of an exception.
Note: These two applications are wcf calls.
[EDIT1]
Application 1 validate request is the IDispatchMessageInspector AfterReceiveRequest
Exceptions are not propagated to clients from a WCF service. Instead, a SOAP Fault (assuming you are using SOAP) will be sent to the client.
You can include exception details in the SOAP Fault, but in general it is not recommended to do so in production.
IMHO a better approach is to implement an IErrorHandler that provides the Fault with whatever data you want to send to the client, and also gives you the opportunity to log the exception server-side.
You can then catch FaultException on the client and have access to the data added by your custom error handler.
The exception class is designed by one throw / catch pair. If you should add any additional information to a cached exception, use the inner exception feature by the rethrow technique:
catch (Exception ex)
{
ErrorHandling.WriteError(ex);
var newEx = new MyException("Additional message", ex) // wrap the original exception instance.
newEx.Data.Add("Exception", "test");
throw newEx;
}
After catching the wrapper exception you can find the original exception in the InnerException property. Another advantage that the original and wrapper exceptions contain their own stack trace so it is easier to find location of error source.

Why does HttpResponseException only allow its message to be read async?

I'm writing a unit test method that exercises code that, under the conditions of my test, is expected to throw an HttpResponseException with a specific response message.
The relevant portion of my test method code looks like this:
try
{
MyClassBeingTested.MyWebServiceMethodBeingTested(myParameters);
}
catch (HttpResponseException ex)
{
string errorMessage = await ex.Response.Content.ReadAsStringAsync();
Assert.IsTrue(errorMessage.Contains("My expected error message string"));
return;
}
Assert.Fail("Expected HttpResponseException didn't get thrown");
This code works, and the test passes.
However, I'd like to better understand understand why my code that reads the error message needs to be constructed this way. The HttpResponseException class only provides async access to its message. I therefore needed to get the message via ReadAsStringAsync(), instead of just being able to synchronously get the message by doing something like ex.Response.Content.Message.
I feel like I might be missing something about why the HttpResponseException class works the way it does. What is the reason that HttpResponseException does not provide synchronous access to its response message?
The HttpResponseException class only provides async access to its message.
HttpResponseException provides you synchronous access to the HTTP response message (Response), which provides you synchronous access to its content (Content). The content of an HTTP stream is what is always read asynchronously. In some uses, the content of an HTTP stream is fully existing in-memory by the time it's used; in other uses, the content of an HTTP stream is streamed over the network.
E.g., if you make an HTTP request with HttpCompletionOption.ResponseHeadersRead, then the response content will be streamed, and it's possible to check the status code and raise an exception before the content of the response actually gets to the box your code is running on.

WCF "The given key was not present in the dictionary"

I'm getting this error even though I'm not using a Dictionary, and what's weird is that it's when I call the service.
wsSoapClient client = null;
try
{
client = new wsSoapClient();
}
catch (Exception ex)
{
// - Error in the web.config
}
try
{
SendData sendData = new SendData();
sendData.finishDate = myVar.FinishDate;
sendData.startDate = myVar.StartDate;
// - Other fields
// - This lines throw the error below
ClientResult result = client.FinishCourse(sendData);
}
catch (Exception ex)
{
// - Message: The given key was not present in the dictionary.
}
The stack trace:
StackTrace: at System.Collections.Generic.Dictionary``2.get_Item(TKey key)
at Project.Model.CourseService.FinishCourse(XmlNode node)
The service is up to date, and I couldn't find info on this anywhere else. There's two similar questions on SO but they are about Silverlight and I couldn't figure a relation between this (regular C# WCF calling a service) and the solutions.
What causes this and how do I fix it?
(Edit) More Info: The binding is a basicHttpBinding, http only.
Edit²: The WSDL.
Edit³: Found the issue. Apparently, there was already another error (a value larger than the field allows), the service was returning an error but for some reason, WCF didn't take that as error and didn't threw the exception, and I'm guessing it tried to proceed normally, causing this dictionary error since the XML is not what is was expecting.
Assuming your service method is not the one throwing the exception, then it might be the case with the deserialization of the soap message (i.e request object) that happens on the service side.
Check your code(or wsdl) for SendData and see if there are non nullable properties which you are not setting in the request object i.e. sendData object. Missing required properties might cause issues during deserialization.
Posting the code of SendData and\or FinishCourse service method would be great in analyzing the possible issue.

Capturing SOAP faults and handling exceptions

I am consuming a web services. Some methods throw exception when i invoked, because the parameters are invalid values, for example. I want to handle the exceptions but it don't contains any data information, only the message "Bad Request". This is my http response:
try
{
var data = client.SomeMethod(4);
}
catch (Exception exception)
{
// exception.Message = Bad Request
// exception don't contains any more data information
}
How can I capture the other information
You can catch the exception with FaultException when the http status code is 2xx or 5xx, not 4xx. You can catch the http status code 4xx with System.ServiceModel.ProtocolException and then get the stream from the InnerException and parse it or get the FaultException from this stream. See http://blogs.msdn.com/b/nathana/archive/2011/03/31/deciphering-a-soap-fault-with-a-400-status-code.aspx for more details.
I'm assuming this is a WCF web service? You are catching to wide of an exception. Try with a FaultException<TDetail>.
Typical deployed services use the FaultContractAttribute to formally specify all SOAP faults that a client can expect to receive in the normal course of an operation. Error information in a FaultContractAttribute appears as a FaultException (where the typeparameter is the serializable error object specified in the operation's FaultContractAttribute) when it arrives at a client application. The FaultContractAttribute can be used to specify SOAP faults for both two-way service methods and for asynchronous method pairs.
Because FaultException is both a FaultException and therefore a CommunicationException, to catch specified SOAP faults make sure you catch the FaultException types prior to the FaultException and CommunicationException types or handle the specified exceptions in one of those exception handlers.
You can use try-catch like below. Then you can access other information. You have to find the "TDetail". It provides by the web service.
catch(FaultException<TDetail> ex)
{
ex.Code.ToString();
ex.Reason.ToString();
}
Other way.
FaultException faultException = (FaultException)ex;
MessageFault msgFault = faultException.CreateMessageFault();
XmlElement elm = msgFault.GetDetail<XmlElement>();

Invalid request handling in OData

Im writing an OData webservice with C# and I need some advice on how to handle invalid requests? An example of an error would be if a customer requested a service on an item they no longer own. I would idealy like to report back to the customer exactly why it is invalid as there are multiple possible reasons.
Many thanks
I would recommend using FaultContracts as part of the OperationContract. You can define them just like DataContracts, and handle exceptions just like a custom exception.
[OperationContract]
[FaultContract(typeof(ItemNotOwned))]
Item GetItem(int ItemId);
You would define ItemNotOwned as a seperate contract definition.
Check it out on MSDN: http://msdn.microsoft.com/en-us/library/ms733841.aspx#Y323
Just throw an exception with the message containing that information. The exception will be serialized to the response sent to the client. If you don't care about the response status code, any exception will do and the client will recieve 500 (Internal Server Error). If you want a specific status code throw an instance of DataServiceException.
Look at using QueryInterceptors and ChangeInterceptors
http://robbincremers.me/2012/01/24/wcf-rest-service-with-odata-and-entity-framework-with-client-context-custom-operations-and-operation-interceptors/

Categories