How to handle specific HttpClient errors - c#

When the HttpClient throws an exception trying to get a page it returns a HttpRequestException. This exception doesn't really have anything to categorize the error apart from the message so the only way i can see to handle errors is like so:
try
{
HttpResponseMessage response = await client.GetAsync("http://www.example.com/");
// ...
}
catch (HttpRequestException e)
{
if(e.Message == "Name or service not known")
{
HandleNotKnown();
return;
}
if(e.Message == "Some other specific message")
{
HandleOtherError();
return;
}
// ... etc
}
I don't like doing this because I feel like at some point the error text could change in an update and break my code.
Is there a better way to handle specific errors with HttpClient?

The HttpRequestException inherits from Exception and so it has the InnerException property
Gets the Exception instance that caused the current exception.
So check this Exception for more details.

Related

Catch exception in xunit test

Can I catch the exception that appears in the log but not in the test?
I performed the test and it returned the status: OK, but in the log I have:
Unexpected error publishing create package to Kafka. id = 5ec3eb81aa662c8a7c76e5e8. Exception: System.NullReferenceException: Object reference not set to an instance of an object.
How can I catch this exception in the test? I tried to use Try and catch (Exception) but nothing catches.
[Fact]
[DisplayTestMethodName]
public async Task ExceptionTest()
{
try
{
var testRequest= #"{""Test1"":"1234"};
var testRequestResp =
await fixture.PostAsync(testRequest);
Assert.Equal("HttpStatusCode: " + System.Net.HttpStatusCode.OK, "HttpStatusCode: " + testRequestResp.StatusCode);
}
catch (Exception ex)
{
Assert.True(ex == null, "Exception: " + ex.Message);
}
Log
VS log
This means you are handling the NullReferenceException already somewhere in your PostAsync method and still returning status 200. That is a design decision to swallow the error and return "OK" (hopefully you are logging it or something at least).
A different approach would be to return a 500 status instead of 200, to indicate that an internal server error has occurred - then try and address the NullReferenceException.
You may also choose not to swallow the error in you PostAsync method and let it bubble all the way up. In that case, you could use:
var exception = await Assert.ThrowsAsync<NullReferenceException>(() => fixture.PostAsync(testRequest));
(Where testRequest was something you knew would trigger that error)
If getting a NullReferenceException is expected behavior and the request is still "OK" status, then somehow catching it in your test would make no sense.
I want to check that the exception "NullReferenceException" does not occur.
I used your advice:
var exception = await Assert.ThrowsAsync<NullReferenceException>(() => fixture.PostAsync(testRequest));
But I don't catch this exception
Where is the problem?

How to be explicit about NOT throwing an exception?

This might be a broad question, but recently I ahve wondered about the following: In our C# backend we have many places that wrap some code in a try/catch block, specifically calls to external WcF services. Some of these calls are crucial for the application so in the catch block we log the error and rethrow, like:
catch(Exception ex)
{
_logger.Error("Some good error message");
throw ex;
}
On the other hand there are services we allow to fail, but we still want to log the error, so they look like:
catch(Exception ex)
{
_logger.Error("Some good error message");
}
Now reading the code of team members I can not be sure if they forgot to throw or if this is the intended behaviour.
Q: Is there a way, resp. what is the default way, to explicitly NOT rethrow (without including a comment in the code).
I have considered something like this:
catch(Exception ex)
{
_logger.Error("Some good error message");
NotThrowingHereOnPurpose();
}
// ...
// and further below a private method
// ...
private void NotThrowingHereOnPurpose(){}
One approach that may be useful here is to change the way of invoking the code that you explicitly allow to fail in such a way that it does not look like a try/catch block at all.
For example, you could write a helper method that does error reporting, and call it with actions expressed as lambdas:
void InvokeFailSafe(Action action, Action<Exception> onFailure = null) {
try {
action();
} catch (Exception e) {
if (onFailure != null) {
onFailure(e);
}
}
}
Now instead of try/catch you would write this:
InvokeFailSafe(
() => {
... The code that may fail
}
, exception => _logger.Error("Some good error message: {0}", exception)
);
or like this, if you don't want anything logged:
InvokeFailSafe(
() => {
... The code that may fail
}
);
If you code things this way, there would be no doubts about a missing throw statement.
It's an opposite solution to dasblinkenlight's answer. Instead of notifying others that the exception mustn't be rethrown it would say that it must be.
If you only want to log it then use the Error method as usual. Otherwise, you can write an extension method for your logger to log and throw exceptions.
The method would take the catched exception and rethrow it using the ExceptionDispatchInfo class. The ExceptionDispatchInfo is used to rethrow the exception with the original stack trace information and Watson information. It behaves like throw; (without the specified exception).
public static void ErrorAndThrow(this ILogger logger, string message, Exception exception)
{
var exceptionInfo = ExceptionDispatchInfo.Capture(exception);
logger.Error(message);
exceptionInfo.Throw();
}
And use it this way:
try
{
}
catch (Exception ex)
{
// ex would be rethrown here
_logger.ErrorAndThrow("Some good error message", ex);
}
Q: Is there a way, resp. what is the default way, to explicitly NOT
rethrow (without including a comment in the code).
Ideal way would be not to catch a generic exception. Now, to throw or not that entirely depends on your case. You need to understand that Exception handling is used when you know what to do in case an exception occurs. So, only specific exceptions should be handled. Catching exceptions without knowing what you are catching will change the behavior of your application.
Now reading the code of team members I can not be sure if they forgot
to throw or if this is the intended behaviour.
This is something the author of the code can explain to you. But here is a learning to take from this. Your code should be self explanatory. In specific cases where you are unable to express yourself with the code, add a meaningful comment.
You can check this link for better understanding.
I actually found another way that kind of includes what other have suggested here, but uses a built in feature: exception filters. I was free to modify the example given in here to illustrate this:
public void MethodThatFailsSometimes()
{
try {
PerformFailingOperation();
}
catch (Exception e) when (e.LogAndBeCaught())
{
}
}
and then one could have two extension methods on Exception, say LogAndBeCaught and LogAndEscape like so:
public static bool LogAndBeCaught(this Exception e)
{
_logger.Error(#"Following exception was thrown: {e}");
return true;
}
public static bool LogAndEscape(this Exception e)
{
_logger.Error(#"Following exception was thrown: {e}");
return false;
}

Correct way to pass errors back to the calling code

I have a function called connect like so:
public boolean connnect(){
{
..... connecting codde
if(connectionSuccessfull)
{
return true;
}
else
{
return false;
}
}
This is a very basic form of error handling, I want to upgrade this function to handle errors correctly. Such as not just tell me false there was an error, but be able to say, error, Authentication failed, or Time-out error etc.
This information then needs to be sent back up the line to the Caller so it can know what happened.
What is the correct way to go about doing this?
{EDIT}
In my care its quite probable that an exception will occur I would say 50% of the time.
I have come up with this, does it look partially correct?
namespace MobileWebServices.Exceptions
{
//Timeout
public abstract class TimeOutException : Exception
{
}
public class ConnectingTimeOutException : TimeoutException
{
}
public class DissconnectingTimeOutException : TimeoutException
{
}
//Authetntication
public abstract class AuthenticationException : Exception
{
}
public class BadAuthenticationException : AuthenticationException
{
}
}
Something along the lines of:
public void Connect()
{
try
{
//code here to look-up the connection details
if(!ValidateConnectionDetails(details))
throw new InvalidOperationException("The connection details are not valid.");
//code here to establish the connection
if(SomeTestThatShowsWereNotHappyWithTheConnection())
throw new Exception("The connection is bad, for some reason");
}
catch(SocketException se)
{
//We'd only have this block if a socket exception is possible. We might just allow it to pass on up.
throw; // User now gets the exception we got, exactly.
//We might re-throw the error, but from here so the stack-trace goes to here rather than the innards of this method:
throw se;
//Most usefully we might throw a new exception that contains this as an inner exception:
throw new Exception("Connecting failed", se);
//Or even better, we might throw a more well-defined exception, that relates to this operation more specifically, with or without the inner exception, depending on whether that is likely to be useful:
throw new ConnectionException("Some message, or maybe just a default is defined in the constructor");
//OR:
throw new ConnectionException("Some message, or maybe just a default is defined in the constructor", se);
}
catch(Exception ex)
{
//If we get to an exception ourselves that isn't of a particular type we're expecting, we probably shouldn't catch it at all. We might though want to note the exception before re-throwing it, or throw a more specific connection with this as an inner-exception:
Log(ex);
throw;
}
}
Because you're no longer returning a value to indicate success, you could also now return an object that represents the connection you created:
public ConnectionObject Connect()
{
// Much as above, but returning the object before the end of the `try`.
}
Returning values representing failure should only be done if that failure is both likely to happen, and something you expect the calling code to be able to reasonably react to right at the point of calling. This isn't that likely with code to connect since the calling code could be code that e.g. connects and then does an operation, and the code calling that in turn is where the exception (whether from here or the subsequent operation) should be caught - it's the code that ultimately cares about the failing.
In the latter case, then returning a value indicating the failure makes a lot more sense. Here though, I'd probably still consider an exception, because it can encapsulate more information, be used by coders in the normal way they use other .NET methods, and because the calling code is probably not written thinking "try to get the connection and then if it works..." it's written thinking "get the connection and then..." with the error case being exactly that; an error case. (For comparison, a method like int.TryParse() is to answer the question "does this string represent an integer, and if so what is it?" where the method int.Parse() answers the question "what is the integer in this string?" with there not being an integer being an error condition).
To think of it another way. Are you currently using a web-browser to browse the web, or are you using it to try to browse the web? Your internet connection could die on you, stopping you from continuing to read these answers, but you'd consider that a problem in what you were trying to do.
The normal approach is to throw an exception (perhaps of a user-defined type), and then to catch those exceptions at a higher level.
If for some reason you cannot use exceptions, you could instead write a wrapper class that encompassed an error message (which would be null if no error occurred) and the bool result (which would only be relevant if the error message is null).
However, I would recommend using exceptions. (The only issue might be whether or not you need to globalise the error message string in the exception, but the consensus is that you should not.)
Here is a sample on how things should be done :
First use your connect() method to return an object (like a Socket for example).
Return a null one if it fails connecting without throwing an Exception.
In your connect() method try/catch your connecting instructions, and rethrow those catched.
Then in the calling method, catch all the Exceptions that can be thrown, and check if the returned object is null or not.
Here is an example of code using Sockets :
public static Socket connect()
{
Socket s = null;
try
{
IPEndPoint iEP = new IPEndPoint("127.0.0.1", 8080);
s = new Socket(iEP.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
s.Connect(iEP);
if(!s.Connected)
{
return null;
}
}
catch(Exception e)
{
throw e;// Rethrow the Exception to the caller
}
return s;
}
public static void Main(String[] args)
{
Socket mySocket = null;
try
{
mySocket = connect();
}
catch(SocketException e)
{
// TODO - Detailed error about a SocketException
Console.Error.WriteLine("SocketException: " + e.Message + "(" + e.ErrorCode + ")");
}
catch(SecurityException e)
{
// TODO - Detailed error about a SecurityException
Console.Error.WriteLine("SecurityException: " + e.Message);
}
catch(Exception e)
{
// TODO - Detailed error about those Exceptions :
// ArgumentNullException, ObjectDisposedException and InvalidOperationException
Console.Error.WriteLine(e.GetType() + ": " + e.Message);
}
if(mySocket == null)
{
// TODO - Error while initializing the Socket
Console.Error.WriteLine("Error while initializing the Socket");
}
// TODO - Use your Socket here
}
I think the best way is using the try catch exception surrounding your call with the exception you want :
catch(TimeoutException ex)
{
//Do something
}
catch(SqlException ex)
{
//do something
}
//....
catch(Exception ex)
{
//do something
}
Make sure of the order of your catch ( the global Exception in last)

How to get HttpStatusCode from Exception in WebAPI?

Is there anyway we can get HttpStatus code when exception caught? Exceptions could be Bad Request, 408 Request Timeout,419 Authentication Timeout? How to handle this in exception block?
catch (Exception exception)
{
techDisciplines = new TechDisciplines { Status = "Error", Error = exception.Message };
return this.Request.CreateResponse<TechDisciplines>(
HttpStatusCode.BadRequest, techDisciplines);
}
I notice that you're catching a generic Exception. You'd need to catch a more specific exception to get at its unique properties. In this case, try catching HttpException and examining its status code property.
However, if you are authoring a service, you may want to use Request.CreateResponse instead to report error conditions.
http://www.asp.net/web-api/overview/web-api-routing-and-actions/exception-handling has more information
I fell into the same trap when doing error handling in my WebAPI controllers. I did some research on best practices for exception handling and finally ended up with following stuff that works like a charm (hope it will will help :)
try
{
// if (something bad happens in my code)
throw new HttpResponseException(new HttpResponseMessage(HttpStatusCode.BadRequest) { Content = new StringContent("custom error message here") });
}
catch (HttpResponseException)
{
// just rethrows exception to API caller
throw;
}
catch (Exception x)
{
// casts and formats general exceptions HttpResponseException so that it behaves like true Http error response with general status code 500 InternalServerError
throw new HttpResponseException(new HttpResponseMessage(HttpStatusCode.InternalServerError) { Content = new StringContent(x.Message) });
}

Elmah add message to error logged through call to Raise(e)

I'm a bit confused at how to add a message to an error logged programatically with ELMAH.
eg:
public ActionResult DoSomething(int id)
{
try { ... }
catch (Exception e)
{
// I want to include the 'id' param value here, and maybe some
// other stuff, but how?
ErrorSignal.FromCurrentContext().Raise(e);
}
}
It seems all Elmah can do is log the raw exception, how can I also log my own debug info?
You can throw a new Exception setting the original as the inner exception and ELMAH will log the messages for both:
catch(Exception e)
{
Exception ex = new Exception("ID = 1", e);
ErrorSignal.FromCurrentContext().Raise(ex);
}
will show
System.Exception: ID = 1 ---> System.NullReferenceException: Object reference not set to an instance of an object.
I found that I can also do something like:
Elmah.ErrorSignal.FromCurrentContext().Raise(new NotImplementedException("class FbCallback.Page_Load() Request.Url= " + Request.Url));
To log my own messages. Then in when I browse to
http://localhost:5050/elmah.axd
I see my messages as type NotImplementedException.
Not very pretty but works.

Categories

Resources