I'm writing a web service that returns different types of errors.
Each method can return one of the three basic types of errors:
General, InvalidInput, or Non.
In addition to those three possible values, each method can have it's own errors (e.g. for SignIn method - InvalidPassword) - but each method can return only one error.
So for example the SignIn method will be able to return one of the following error types: General, InvalidInput, Non, InvalidPassword.
At first I thought of using enums, but I now think that the error types should implement inheritance because there are the basic three types, and each new method's error types inherit from that.. But I can't really think how. I thought of using a static class - but then it will only have one string static field - and inheritance is irrelevant again...
Another problem with enums is that what the web service's client will get eventually is a meaningless int (through json)
So my question is: What is a good way of conveying the idea that there are three basic possible values, and you can add to those to make a new type of errors?
It would be best if you reconsidered your interfaces.
It is by far better to use exceptions over error codes not only because it is so easy to forget about checking for an error code, but also because it is difficult to maintain them, keep them unique and meaningful.
John Saunders states in a similar thread:
[...] you should throw a SoapException. This will translate more or less directly into a SOAP Fault. A SOAP Fault is the appropriate way to indicate an error with a web service operation for the same reason that Exceptions are better than return status in a normal method - you don't have to check the return status at the point of the call.
Besides throwing a SoapException you may also throw arbitrary exceptions. ASP.NET will wrap these exceptions into a SoapException that gets passed to the client. The client can access the details of the exception in the inner exception of the SoapException.
For further explanations see also:
Handling and Throwing Exceptions in XML Web Services
Related
Referring to What is the correct way to make a custom .NET Exception serializable?
and Are all .NET Exceptions serializable? ...
Why should my exceptions be serializable?
Someone said "it can be considered a bug" if a custom exception defined by a third party library, is not serializable. Why?
Why are exceptions different than other classes in this regard?
Because your exceptions may need to be marshalled between different AppDomains and if they aren't (properly) serializable you will lose precious debugging information. Unlike other classes, you won't have control over whether your exception will be marshalled -- it will.
When I mean "you won't have control" I mean that classes you create generally have a finite space of existence and the existence is well known. If it's a return value and someone tries to call it in a different AppDomain (or on a different machine) they will get a fault and can just say "Don't use it that way." The caller knows they have to convert it into a type that can be serialized (by wrapping the method call). However since exceptions are bubbled up to the very top if not caught they can transcend AppDomain boundaries you didn't even know you had. Your custom application exception 20 levels deep in a different AppDomain might be the exception reported at Main() and nothing along the way is going to convert it into a serializable exception for you.
In addition to Talljoe's answer, your exceptions may be passed across Web Services as well, in this case the exception needs to be serializable/deserializable so it can be turned into XML and transmitted by the Web Service
I think that the default for all classes should be Serializable unless they contain a class that is explicitly not serializable. It's annoying to not be able to transfer a class just because some designer didn't think about it.
The same thing with "Final", all variables should be "Final" by default unless you specifically say that they are "Mutable".
Also, I'm not sure it makes sense to have a variable that is not private.
Oh well, need to design my own language.
But the answer is, you don't know how your exception will be used and they are assumed to be able to be thrown across remote calls.
Another place where objects required to be serializable is Asp.Net Session.
We store last exception in Session and not serializable exceptions needs extra translation to store their details as serializable( specifying original exception as inner doesn't help)
When defining exceptions should you have separate exceptions for every type of error that can occur or a more general exception that can be used for multiple error conditions.
For example lets say that I have a class that processes strings and I want to throw exceptions if a string is not the correct format.
Would I create separate exceptions such as:
StringTooLongException, StringContainsIllegalCharactersException, StringTerminationException
or just create a single exception such as
StringFormatException
and indicate the more specific exception with an error code within the exception?
That depends. Can the receiver of the exception take any useful action depending on the type? Then yes, it would be nice to have different types. If all he can do is show the error message to the user, then different .NET types are not useful and if something has no use, it should not be done.
There are lots of existing "generic" exception types in the .Net framework, e.g., System.IO.IOException covers lots of possible IO errors, and System.Data.SqlClient.SqlException is used for reporting lots of differents types of Sql error, so I would say it is OK to use a more generic exception type, preferably one that already exists (don't reinvent the wheel).
I've noticed that most exception messages don't include instance-specific details like the value that caused the exception. They generally only tell you the "category" of the error.
For example, when attempting to serialize an object with a 3rd. party library, I got a MissingMethodException with message:
"No parameterless constructor defined for this object."
In many cases this is enough, but often (typically during development) a message like
"No parameterless constructor defined for this object of type 'Foo'."
can save a lot of time by directing you straight to the cause of the error.
InvalidArgumentException is another example: it usually tells you the name of the argument but not its value.
This seems to be the case for most framework-raised exceptions, but also for 3rd party libraries.
Is this done on purpose?
Is there a security implication in exposing an internal state like the "faulty" value of a variable?
Two reasons I can think of:
Firstly, maybe the parameter that threw the exception was a value that was a processed form of the one that was passed to the public interface. The value may not make sense without the expense of catching to rethrow a different exception that is going to be the same in most regards anyway.
Secondly, and more importantly, is that there can indeed be a security risk, that can be very hard to second-guess (if I'm writing a general-purpose container, I don't know what contexts it will be used in). We don't want "Credit-Card: 5555444455554444" appearing in an error message if we can help it.
Ultimately, just what debug information is most useful will vary according to the error anyway. If the type, method and (when possible) file and line number isn't enough, it's time to write some debug code that traps just what you do want to know, rather than complaining that it isn't already trapped when next time you might want yet different information (field state of instances can be just as likely to be useful as parameters).
InvalidArgumentException and (per #Ian Nelson) "Key not found in dictionary" both share something in common - there's no guarantee that the framework would be able to find a suitable value to show you - if the key/argument is of any user defined type, and ToString() hasn't been overridden, then you would just get the type name - it's not going to add a lot of value.
Exceptions are mostly meant for a program to consume. Most programs wouldn't know what to do with information about the instance.
The Message property is aimed at human consumption. Other than in a debugging scenario, humans won't know what to make of Foo.
Many exception mechanisms try to serve a hodgepodge of orthogonal purposes by passing a single exception-derived object:
Letting the caller know that various specific things have happened, or that various specific problems exist.
Determining when the exceptional condition is "resolved" so that normal program flow can continue.
Providing an indication of what to tell the user of the program
Providing information which could be logged to allow the owners of a system to identify problems, when a secure log is available
Providing information which could be logged to allow the owners of a system to identify problems, but which would not pose a security risk even if secure logging is not available.
Unfortunately, I'm unaware of any exception mechanism in widespread use which can actually accomplish all five of the above, well.
In Java, you explicitly define what exceptions are thrown using the "throws" keyword. That way, anyone calling your method knows what to catch.
Is there something in C#? If not, how do I know what exceptions to catch, or how do I let others know what exceptions to catch?
Also, if I am defining an interface, is there a way to say "methodX() should throw this exception on error"?
There is nothing equivalent in C#: The Trouble with Checked Exceptions
Other than documentation, there is no way to declare an interface to say "methodX() should throw this exception on error".
C#/.net does not have checked Exceptions, they proved to be less useful in large scale systems than first thought. In a lot of projects the time to maintain the check exception specs was a lot greater than the debugging time saved by having them.
Checked Exceptions seem like a good ideal until you have methods that can take delegates or calls into object you pass in. Take a simple case, the Sort() method on a list can’t know what exceptions it will throw, as it does not know what exceptions the Compar() method on the objects being sorted will throw.
So the spec for the exceptions a method may throw must be able to include information on how exceptions are populated from pass in objects and delegates. No one knows how to do this!
However there are tools that you check if you are catching all exceptions – see Exception Hunter by Red Gate. I personally don’t see much value in these tool, however if you like checked exceptions you may find them useful. ==> Looks like Exception Hunter wasn't too useful, so Redgate discontinued Exception Hunter a long while ago:
This feature is not available in C#. You can make proper XML documentation (3 slashes ///) and state what exceptions are being thrown.
This will be picked up by the IntelliSense mechanism and will be visible for the users of the class/method before they use it.
C# does not support this. (Not that I know anyway).
What you can do is use Xml Comments so that while calling you methods this data will be shown by intellisense.
As far as I'm aware there is no throws declaration in C# you can document your method indicating that it throws an exception but no forced error handling.
C# doesn't support checked exceptions. The language designers consider checked exceptions in the way java uses them a bad idea.
Some workarounds
Let me cite this medium article: It's almost 2020 and yet... Checked exceptions are still a thing
Among the many reasons why it's a bad idea, putting the checked exceptions in the contract (interfaces):
makes it impossible to change the implementation of an interface with a different one which throws different exceptions
exposes implementation details
a change of the checked exceptions of an API interface, makes it necessary to change the whole chain of interfaces in the call stack
For example, imagine that you are implementing a repository based on SQL Server, so you expose all kind of SQL Server specific exceptions. Then you want to move it to MySQL or Cosmos BD. Of course:
the implementation can't be changed to a new one that need to throw different exceptions. Also related to this, if you have different implementations of the storage, you can't just change them by configuration, but you need to have different compilations of the code for each storage backend
this is the explanation for 1: as the interface showed the implementation details (SQL Server exceptions) know you can't just change it
if you need to make the change, prepare to change the interface at all levels, since the API that uses the database up to the lates consumer in the call stack chain.
The articles cited above includes pointers to many explanations to discourage the use of checked exceptions, included this by the creator of C#: The trouble with checked exceptions
This title begs for more explanation.
Basically, I'm rolling an API that wraps a web service in a nice heirarchical model. This model exposes things in the form:
var obj = MyRemoteResource.GetForId(1234, SourceEnum.ThatSource);
ApiConsumerMethod(obj.SomeProperty); //SomeProperty is lazily loaded, and often exposes such lazily loaded properties itself
... etc ...
Where many different RemoteResources* (each with many properties exist). There's really aggresive cacheing going on, and request throttling to prevent inadvertantly DOS'ing the servers (and getting the IP of the caller banned).
I've got all this code working, but I'm not doing much in the way of error handling at the moment. Basically, if the consumer of an API provides an invalid ID, the web server is down, a connection times out, or any other of a plethora of request layer errors occur an exception just percolates up when a property is accessed.
I consider this far less than ideal.
So my question is, how should I wrap these errors up so that it is convenient for a user of this API to manage them?
Some routes I have considered:
Just wrap all exceptions in some API defined ones, and document them as thrown.
Expose a static ErrorHandler class that allows a user to register notification callbacks for specific errors; falling back to the above behavior when no registration has been made for specific errors.**
Null properties on error, and set a LastErrorCode.
Each of these approachs have strengths and weaknesses. I'd appreciate opinons on them, as well as alternatives I haven't thought of.
If it impacts the discussion at all, the platform class throwing these exceptions is WebClient. Furthermore, usage of WebClient is sufficiently abstract that it could easily be replaced with some other download scheme if needed.
*Which is to say, many different classes
**This would be... wierd. But it maps to the global nature of the failure. This is my least favorite idea thus far.
I wouldn't implement fancy error technologies (like events and stuff like this). It's not easy to judge where and how to use exceptions, but this is no reason to implements other stuff.
When you request an object by an id which doesn't exist, what do you have to tell the caller about this? If you just return null, the client knows that it doesn't exist, there is nothing more to say.
Exceptions force the caller to care about it. So they should only be used where the caller is expected to do something special. Exception can provide the information why something didn't work. But if it is an "error" the user could also ignore, an exception is not the best choice.
There are two common alternatives to exceptions.
Use return values which provide information about the result of an action. For instance, logon could return a LogonResult instead of throwing an exception.
Write two methods, one throwing an exception, and one (Try...) returning a boolean. The caller decides if it wants to ignore the "error" or not.
Personally I believe this is entirely dependent on the context of what your API end-user is trying to do. If this is the case, you should let them decide how to handle erors.
Recently when working with CSV files (very error prone) I used an API that allowed you to define the exception behaviour. You could either ignore the error, replace by some default value/action, or pass them off to an event handler.
I really liked this approach of letting the end user decide how to handle internal exceptions, because unless your API is very specific its difficult to preempt all scenarios.
I prefer to have an exception thrown at me when something bad happens. Exceptions are (for me, anyways) the common way to tell that something went wrong, and i find it more intuitive to catch, than to check a return value for null and check another property to see what went wrong..