Exception not caught when thrown by RESTSharp - c#

I'm using RestSharp to communicate with a REST-Server and wrote a small wrapper function for the call
private T Get<T>(string restAdress) where T : new()
{
try
{
// throw new Exception(); // This one is caught
IRestClient restClient = new RestClient(settings.Value.HostToConnect).UseSerializer(new JsonNetSerializer()); // (1)
RestRequest restRequest = new RestRequest(restAdress);
IRestResponse<T> result = restClient.Get<T>(restRequest); // (2)
return result.Data;
}
catch (Exception e) // debugger wont stop here
{
// debugger wont stop here too
// code within this block is not executed
}
return null; // (3)
}
Since I want to use the Newtonsoft-Attributes I give in a custom (de)serializer (1).
public class JsonNetSerializer : IRestSerializer
{
public string Serialize(object obj) =>
JsonConvert.SerializeObject(obj);
public string Serialize(RestSharp.Parameter bodyParameter) =>
JsonConvert.SerializeObject(bodyParameter.Value);
public T Deserialize<T>(IRestResponse response) =>
JsonConvert.DeserializeObject<T>(response.Content); // (4)
public string[] SupportedContentTypes { get; } =
{
"application/json", "text/json", "text/x-json", "text/javascript", "*+json"
};
public string ContentType { get; set; } = "application/json";
public DataFormat DataFormat { get; } = DataFormat.Json;
}
When calling the REST service and trying to get the result (2) an Exception is thrown if the deserialization fails (4). But the Exception is not caught by the try-catch block. I tried to debug but after throwing the debugger goes on in line (3), the catch and the logging withing the catch is never executed. The debugger won't even stop at the catch (Exception e) it goes straight from (4) to (3).
(Sorry for not english, the title of the window says "Exception User-Unhandled")
Can anyone explain this behaviour to me?

Whats happening here is an interesting setting of the debugger, another example would be this closed bug report. When the debugger reaches the point the exception is thrown it will break, causing the behaviour you experienced.
If you uncheck the exception setting "Break when this exception type is user-unhandled" in the dialog, you should be able to reach your catch block, as the debugger no longer breaks the execution as soon as the specified exception is thrown.
In your case you find that option under "Ausnahmeeinstellungen".

I am maintaining RestSharp, so I hope I can answer this.
RestSharp doesn't throw on deserialisation by default. If you look at the code, deserialisation happens in the private IRestResponse<T> Deserialize<T>(IRestRequest request, IRestResponse raw) method of RestClient.
When RestSharp can't deserialise the response, it creates an error response. You get the response status set to Error and the exception is put into the ErrorException property of the response object, along with the exception message that gets to the ErrorMessage of the response.
It is still possible to tell RestSharp to throw on deserialisation if you assign the FailOnDeserialization property of the RestClient instance to true.

Related

C# cannot catch Exception from within anonymous Action

I have an application in which I execute requests on a seperate thread while a waiting form is displayed. This is done using a Request class which executes an Action object.
Now of course i have some error-handling logic, which seems to catch errors twice, and i cannot figure why.
This is the code inside the Request class:
public virtual Tuple<string, string> ExecuteInternal()
{
ReturnValue<string> rv = new ReturnValue<string>();
try
{
Executor.Invoke(rv);
Response = rv.Value;
return new Tuple<string, string>("Success", Response);
}
catch (Exception ex)
{
//-----------this gets triggered and correctly returns the "Failure" Tuple
return new Tuple<string, string>("Failure", ex.ToString());
}
}
This is the code responsible for executing the requests one after another:
new Thread(() =>
{
foreach (Request request in Requests)
{
string response = "";
try
{
Tuple<string, string> result = request.ExecuteInternal();
string status = result.Item1;
response = result.Item2;
UpdateStatus(request, status);
}
catch (Exception ex)
{
//-------------------somehow this part gets also triggered
request.Response = ex.ToString() + "\n\n\n" + response;
UpdateStatus(request, "Failure2");
}
}
}).Start();
Now if i have an Exception inside the "Executor" which is an Action, eg.
Executor = () => { throw new Exception(); };
, the error handler inside the Request class returns a "Failure" tuple, so the exception handler works. BUT the exception handler inside the Thread also catches the same Exception somehow, and i cannot figure out why.
I fixed it, the "UpdateStatus" method was causing some issues.
It is supposed to call another Action inside the Request responsible for error handling in a user-friendly way, but due to a typo that variable was not getting initialized. It works properly now :)
I debugged everything line by line and traced it down that way. The exception was rethrown, since the error handler was not initialized as said above.
(This is a quite big project i 'inherited' and am still getting used to...)

Creating 2 Exceptions in a Finally Block

I have the following code:
finally
{
if (!isDnsSet)
{
var exception = new Exception(<DNS-INFORMATION>);
localLog.TraceException(exception);
throw exception;
}
}
As it stands, this exception throws too much information to the user that is not particularly needed for them to see. I want to be able to log exception using my localLog class but also throw another exception with a more concise message.
I was thinking to just create another exception with the shortened message and still log the original, more verbose one using my class.
Is there a more elegant way of doing this or would I just do something like:
var shortException = new Exception(<short and sweet message>);
var longException = new Exception(<not so short and sweet but still useful for other devs>);
localLog.TraceException(longException);
throw shortException;
I think a cleaner method would be to make the longer exception an inner exception:
finally
{
if (!isDnsSet)
{
var innerException = new Exception(<not so short and sweet but still useful for other devs>);
var exception = new Exception(<short and sweet message>, innerException);
localLog.TraceException(exception);
throw exception;
}
}
That way you have consistency between the exception that's thrown and the exception that's logged, making diagnosis easier.
One approach is to create a custom exception that carries both a long and a short message. Users who get the exception outside your library would access the short message through Exception's Message property, while your TraceException method would access the long version through an additional property provided by your custom exception:
public class DetailedException : Exception {
public string DetailedMessage { get; }
public DetailedException(string longMessage, string shortMessage) : base(shortMessage) {
DetailedMessage = longMessage;
}
}
Inside TraceException method:
var message = (exception as DetailedException)?.DetailedMessage ?? exception.Message;
Couldn't the exception handler receive and process the longException and, as part of its function, throw the shortException?

How do I determine what is the issue with a 500 error on a HttpClient.PostAsJsonAsync call?

I am making a call to a Web API that I wrote. I am working through the bugs on both sides and am getting a 500 error. I want to see that is in that error message to see what might be the problem. How do I find that?
using (var client = new HttpClient())
{
var fooURL = Url.RouteUrl("PayrollApi", new { httproute = string.Empty, controller = "LeaveRequest" }, Request.Url.Scheme);
var repsonse = client.PostAsJsonAsync(fooURL, leaveRequest).Result;
}
I don't see where that text might be stored so I can figure out what other bugs need to be fixed. How do I get that text?
Update: something I didn't clarify. I put a breakpoint on the WebAPI I am calling and the break point is never hit. However, when I call it from Poster, I hit the break point. The URL is correct.
public HttpResponseMessage Post([FromBody]LeaveRequest value)
{
if (ModelState.IsValid)
{
// code here
}
}
I was able to make a change to get the error message:
var repsonse = client.PostAsJsonAsync(fooURL, leaveRequest).Result.Content.ReadAsStringAsync();
instead of
var repsonse = client.PostAsJsonAsync(fooURL, leaveRequest).Result;
I was then able to see my error and fix it.
I am making a call to a Web API that I wrote. I want to see that is
in that error message to see what might be the problem.
You might want to put the code you have in PayrollApi.LeaveRequest in a try-catch block, something like:
public HttpResponseMessage LeaveRequest()
{
try {
// do something here
}
catch(Exception ex) {
// this try-catch block can be temporary
// just to catch that 500-error (or any unexpected error)
// you would not normally have this code-block
var badResponse = request.CreateResponse(HttpStatusCode.BadRequest);
badResponse.ReasonPhrase = "include ex.StackTrace here just for debugging";
}
}
Then make a call inside a try-catch block to capture that extra error:
using (var client = new HttpClient())
{
// rest of your code goes here
try
{
var repsonse = client.PostAsJsonAsync(fooURL, leaveRequest).Result;
}
catch(HttpRequestException httpEx)
{
// determine error here by inspecting httpEx.Message
}
}
httpEx.Message can have this message:
Response status code does not indicate success: 500
({stack_trace_goes_here}).

How to catch a web service exception

How do you catch exceptions from a Web Service that is returning a custom object?
I've seen this post but it doesn't seem to show how to get the exception that was thrown by the service.
I can pull the SOAP Exception, but I want to be able to get the original exception that the web service returned. I've looked at the variables that are set at this time and can't seem to see the exception anywhere, I just see:
"Server was unable to process request. ---> Exception of type
'RestoreCommon.ConsignmentNotFoundException' was thrown."
try
{
Consignment cons = WebServiceRequest.Instance.Service
.getConsignmentDetails(txtConsignmentNumber.Text);
lblReceiverName.Text = cons.Receiver.Name;
}
catch (ConsignmentNotFoundException)
{
MessageBox.Show("Consignment could not be found!");
}
Is this possible?
In short, no.
Web services will always throw SOAP fault. In your code,
MessageBox meant to be used in Windows forms and nowhere else.
You can throw this exception and in the client application, you will have to handle a SOAP fault.
Edit: If you do not want to send exceptions across to the client, this what you could do:
class BaseResponse
{
public bool HasErrors
{
get;
set;
}
public Collection<String> Errors
{
get;
set;
}
}
Each WebMethod response must inherit from this class. Now, this is how your WebMethod blocks would look like:
public ConcreteResponse SomeWebMethod()
{
ConcreteResponse response = new ConcreteResponse();
try
{
// Processing here
}
catch (Exception exception)
{
// Log the actual exception details somewhere
// Replace the exception with user friendly message
response.HasErrors = true;
response.Errors = new Collection<string>();
response.Errors[0] = exception.Message;
}
finally
{
// Clean ups here
}
return response;
}
This is just an example. You may need to write proper exception handling code rather than simply using generic catch block.
Note: This will take care of exceptions occurring in your application only. Any exceptions occurring during communication between client and service, will still be thrown to the client application.

SoapHeaderException was unhandled when calling web service

An exception occurs on line
ModifyProfileResp resp = BFGlobal.modifyProfile(req);
INTERNAL_ERROR, SoapHeaderException was unhandled
Error: System.Exception._COMPlusExceptionCode -532462766,
This code basically updates the users information on a web service through a call I made.
public ModifyProfileResp ModifyProfile(string n_homeTelephone)
{
try
{
// Get Login Resp
LoginResp loginResp = LoginToBetfair("username", "password");
// Make a BFGS instance
BFGlobal = new BFGlobalService();
// Set up the request in [req]
ModifyProfileReq req = new ModifyProfileReq();
req.header = new APIRequestHeader();
req.header.sessionToken = loginResp.header.sessionToken;
req.homeTelephone = n_homeTelephone;
// Set up the response in [resp]
// Here is where Im getting thrown an exception..
ModifyProfileResp resp = BFGlobal.modifyProfile(req); // <-- Here Im getting thrown an exception
// return [resp] - which is the response from the call
// Just trying to print out errror codes
string mec = resp.minorErrorCode.ToString();
string ec = resp.errorCode.ToString();
return resp;
}
catch (Exception)
{
throw;
}
Pretty straightforward, make the request header, call the response, pass in the req and I should get some data back, but I keep getting thrown a exception on this line.
Any ideas on how to go about this?
First,
don't do this:
catch (Exception)
{
throw;
}
It's pointless. If you don't have the catch the exception will automatically get thrown up a level, which is what you're doing with throw. Further, if you can't do something with the exception (like retry the request) you're probably better off letting the exception bubble up.
Second, try something like this:
catch (SoapHeaderException ex)
{
Debug.WriteLine(ex.Message);
}
This will catch the specific exception that you're dealing with. Further, set a breakpoint here on the Debug statement. You can then browse the details of the exception. You'll be able to see the stacktrace, inner exceptions and any other data that the thrower of the SoapHeaderException might want you to see.
This information can often be useful when you're debugging, for example, it could say "You forgot to initialize the flux capacitor."
You're seeing an exception from the remote web service.
SoapHeaderException Class
The exception that is thrown when an XML Web service method is called over SOAP and an exception occurs during processing of the SOAP header.
Likely you're not setting up your headers as the remote service requires. Try to acquire help from the remote side.
Try viewing the .InnerException for more details.

Categories