What is the right time to throw an exception in an API? - c#

I'm building a API for my pet software and I'm in the following situation:
A service that use another service. I have a service that use another service for load a Assembly, should I throw a exception in the service that load a assembly or on the service that use that service?
AssemblyService:
public class AssemblyService : IAssemblyService
{
public Assembly Load(string assemblyName)
{
Assembly assembly;
try
{
assembly = Assembly.Load(assemblyName);
}
catch
{
assembly = null;
}
return assembly;
}
...
}
Service that use AssemblyService:
public class CommandService : ICommandService
{
private readonly IAssemblyService assemblyService;
public CommandService(IAssemblyService assemblyService)
{
this.assemblyService = assemblyService;
}
public CommandOutput Process(string inputCommand, string requestInfo)
{
string commandName = GetAssemblyName(inputCommand);
string args = GetArgs(inputCommand);
Assembly assembly = assemblyService.Load(commandName);
if (assembly == null) throw new UnknownCommandException(commandName);
ICommand command = assemblyService.GetCommand(assembly);
return command.Execute(args, requestInfo);
}
#region Private methods
...
#endregion
}
Should I throw the exception in AssemblyService or CommandService like the above example?
I'm trying to learn how to handle a exception, in the above example the line assembly = Assembly.Load(assemblyName); can throw ArgumentNullException, ArgumentException, FileNotFoundException, FileLoadException and BadImageFormatException. Should I handle all these exceptions?
UnknownCommandException(commandName) is a custom exception.
Other question: Anyone who's using my API could know when a method could throw a exception? I see placing the mouse over any methods of .Net Framework you will see if the method could throw a exception. Could this works with methods of my API?

Your title is about throwing exceptions but you actually seem to be talking about catching exceptions. You should generally not catch exceptions unless you can do something meaningful to rectify the condition that caused the exception to be thrown in the first place, and in that case you should only catch the explicit exception types that you can handle.

There are two things to think about here:
Will the normal flow of the application be abruptly halted to the point where it will no longer work? Exceptions are exactly that - a notification that something exceptional (out of the ordinary, abnormal, etc.) has happened. If it isn't exceptional, don't throw an exception. If the user can continue to use the program without noticing, don't use an exception.
How you comment the method declaration will affect this. There should be some markup tags for the comments that will allow you to explain what exception will be thrown and under what circumstances it will be thrown. They look like this:
/// <exception cref="ExceptionTypeGoesHere"></exception>

I normally try and avoid using exceptions to control the flow of the program. Your program uses an exception to convert it to a result variable and then converts that back to an exception. Why not stick with exceptions all the way? I would change it as follows:
public class AssemblyService : IAssemblyService
{
public Assembly Load(string assemblyName)
{
return Assembly.Load(assemblyName);
}
}
public class CommandService : ICommandService
{
private readonly IAssemblyService assemblyService;
public CommandService(IAssemblyService assemblyService)
{
this.assemblyService = assemblyService;
}
public CommandOutput Process(string inputCommand, string requestInfo)
{
string commandName = GetAssemblyName(inputCommand);
try
{
string args = GetArgs(inputCommand);
Assembly assembly = assemblyService.Load(commandName);
ICommand command = assemblyService.GetCommand(assembly);
return command.Execute(args, requestInfo);
}
catch (Exception ex)
{
//Log original exception or add to inner exception
throw new UnknownCommandException(commandName);
}
}
}

api as the name suggests is the gateway to an application. if an error occurs in the api, it is most useful for the api to tell the consumer why, where and when the error happened i.e. api throws the exception out. it is up to the consumer to catch this and tell its users what to do or if the business logic is defined well the consumer will calculate alternative execution paths. this is my rule of thumb
in the example above the assembly load service should throw the error out. If you handle this in the api, then the consumer will never learn :)
for general guidelines to exception handling look here in Msdn

Related

Returning meaningful error messages from a .NET Core API

Scenario
I have a .NET Core 2.2 web API with an exception handling middleware. Whenever an exception occurs in the application (inside the MVC layer) it gets caught by the exception middleware and returned as an internal server error back to the frontend and logged to kibana.
The problem
This is all fine and well when things go wrong, but sometimes I want to notify the calling application of specifically what went wrong. I.e., "Could not find record in database!" or "Failed to convert this to that!"
My Solution
I've used application Exceptions (not great - I know) to piggy back off the error middleware to return this to the frontend. This has been working fine, but has created a lot of noise around the code by having to throw a whole bunch of exceptions. I'm not satisfied with this approach and convinced that there must be a better solution.
My application architecture: I'm following a traditional n-tier application layout being services (business logic) and repositories (DAL) all speaking to each other. I would preferably like to elegantly bubble up any issues back to the user in any of these layers.
I've been thinking about this for a while now and am not sure what the best way to go about it is. Any advice would be appreciated.
I use a kind of the operation result pattern (non-official pattern).
The principle is to return a new Type containing:
Whether the operation was a success.
The result of the operation if was successful.
Details about the Exception that caused the failure.
Consider the following class:
public class OperationResult
{
protected OperationResult()
{
this.Success = true;
}
protected OperationResult(string message)
{
this.Success = false;
this.FailureMessage = message;
}
protected OperationResult(Exception ex)
{
this.Success = false;
this.Exception = ex;
}
public bool Success { get; protected set; }
public string FailureMessage { get; protected set; }
public Exception Exception { get; protected set; }
public static OperationResult SuccessResult()
{
return new OperationResult();
}
public static OperationResult FailureResult(string message)
{
return new OperationResult(message);
}
public static OperationResult ExceptionResult(Exception ex)
{
return new OperationResult(ex);
}
public bool IsException()
{
return this.Exception != null;
}
}
Then you could easily adapt OperationResult or create a class that inherits from OperationResult, but uses a generic type parameter.
Some examples:
The Operation Result Pattern — A Simple Guide
Error Handling in SOLID C# .NET – The Operation Result Approach
As per the Microsoft's standards, it is ideal to use ProblemDetails object in case of 4xx/5xx exceptions -
Following is the customised RequestDelegate method which you can use in ApiExceptionHandler to handle exceptions.
public async Task RequestDelegate(HttpContext context)
{
var exception = context.Features.Get<IExceptionHandlerFeature>().Error;
var problemDetails = new ProblemDetails
{
Title = "An unexpected error occurred!",
Status = GetStatusCode(exception),
Detail = _env.IsDevelopment() ? exception.Message : "An unexpected error occurred!",
Instance = $"{Environment.MachineName}:{context.TraceIdentifier}:{Guid.NewGuid()}"
};
_logger.LogError($"Exception thrown. StatusCode: {problemDetails.Status}. Instance: {problemDetails.Instance}", exception);
context.Response.StatusCode = problemDetails.Status.Value;
context.Response.WriteJson(problemDetails, "application/problem + json");
await Task.CompletedTask;
}

Detailed exception logging on wcf

Lately I am working on exception logging module of a WCF service. Unfortunately the service hasn't been introduced with unit tests, therefore there are many unexpected exceptions occurring. And so far I have accomplished to get the exceptions with interceptor aproach, by implementing IErrorHandler interface and tying it to the service interface with IServiceBehaviour. I liked this functionality very much actually. But it brought me into a next step of desire of getting the details of exception. Like on which line did the exception occurred?
I can satisfy this desire by 2 ways in my mind:
By having a variable for keeping track of the lines I've passed through successfully, and including it in the exception thrown.
By catching exceptions from all lines seperately.
But both approaches seem very lousy to me. I am wondering is there a known design pattern or a tool to achive this goal?
In my opinion you might try using logging, such as log4net. Then you can find out where is and what happened. Exception object not always contains the stack info, because of "inlining", that occur during optimization etc.
include the PDB files for your service and the line numbers will be included in exception.ToString()
The way we have solved this problem is twofold:
Our services are dumb wrappers around commands. So when a service method is entered it delegates its work to a command.
We wrap every command call in a logging proxy that is responsible for logging input, output and errors and executing the command.
For example:
public FooServiceModel GetFoo(int fooId)
{
return new ILogged<GetFooCommand>().Target.Execute(fooId);
}
This delegates execution of the command to ILogged which:
Logs the command name
Logs the command parameters
Logs the execution result
Logs any exceptions
It also does some other stuff to link up the client request with the server call using custom message headers so that a call can be completely debugged from client to server and back. This is incredibly useful and allows us to diagnose even complex problems off site.
We use the Castle.Core dynamic proxy to implement ILogged with an interceptor that looks something like this (ILog is a log4net logger):
public class LoggingInterceptor : IInterceptor
{
public LoggingInterceptor([NotNull] object target, [NotNull] ILog logger)
{
if (target == null)
{
throw new ArgumentNullException("target");
}
if (logger == null)
{
throw new ArgumentNullException("logger");
}
this.Target = target;
this.Logger = logger;
}
public object Target { get; set; }
public ILog Logger { get; set; }
public void Intercept(IInvocation invocation)
{
try
{
this.Logger.Debug(invocation);
invocation.ReturnValue = invocation.Method.Invoke(
this.Target, invocation.Arguments);
this.Logger.Debug("Invocation return value:");
this.Logger.Debug(invocation.ReturnValue);
}
catch (TargetInvocationException ex)
{
this.Logger.Error("Unable to execute invocation", ex);
if (ex.InnerException != null)
{
throw ex.InnerException;
}
throw;
}
}
}
The invocation itself is rendered by a custom log4net object renderer:
public class InvocationRenderer : IObjectRenderer
{
public void RenderObject(RendererMap rendererMap, object obj, TextWriter writer)
{
var invocation = (IInvocation)obj;
var builder = new StringBuilder();
builder.AppendFormat(
"Invoking Method: {0} --> '{1}' with parameters (",
invocation.Method.DeclaringType != null
? invocation.Method.DeclaringType.FullName : "{Unknown Type}",
invocation.Method);
var parameters = invocation.Method
.GetParameters()
.Zip(invocation.Arguments, (p, a) => new { Parameter = p, Argument = a })
.ToArray();
var index = 0;
foreach (var parameter in parameters)
{
builder.AppendFormat(
"{0}: {1}",
parameter.Parameter.Name,
rendererMap.FindAndRender(parameter.Argument));
if (++index < parameters.Length)
{
builder.Append(", ");
}
}
builder.Append(")");
writer.Write(builder.ToString());
}
}
Hopefully that will give you some ideas on how to tackle this problem.

[ExpectedException(typeof(AnExceptionBaseException))]

I wrote a unit test in such a way that it should throw AnException or AnotherException, both deriving from AnExceptionBaseException. I then proceeded to add an ExpectedExceptionAttribute for the base exception, only to find that my test will still be marked as failed.
Test Name: Call_Should_Throw_If_Device_Is_Not_Ready Test
...
Result Message: Test method
DiskManagementTests.DiskFreeSpaceTests.Call_Should_Throw_If_Device_Is_Not_Ready
threw exception System.IO.FileNotFoundException, but exception
System.IO.IOException was expected. Exception message:
System.IO.FileNotFoundException: The device is not ready. (Exception
from HRESULT: 0x80070015)
This seems like a reasonable design decision because, in this particular case, the exception is generated from an HRESULT return code. That makes it nearly impossible to determine which exception will be thrown. At least not without copying the code logic from the unit that my test is supposed to ...test.
My code (I believe this can throw either FileNotFound or DirectoryNotFound):
[TestMethod]
[ExpectedException(typeof(IOException))]
public void Call_Should_Throw_If_Device_Is_Not_Ready()
{
foreach (DriveInfo drive in DriveInfo.GetDrives().Where(drive => !drive.IsReady))
{
DiskFreeSpace diskFreeSpace = DiskManagement.GetDiskFreeSpace(drive.RootDirectory.FullName);
Assert.Fail("API call did not fail even though the drive reports that it is not ready.");
}
Assert.Inconclusive("All drives were ready. Try testing with an empty disc drive.");
}
Do I need to reconsider the way I write unit tests?
EDIT
This scenario is supported after all. All it really took was setting AllowDerivedTypes to true.
[TestMethod]
[ExpectedException(typeof(IOException), AllowDerivedTypes = true)]
public void Call_Should_Throw_If_Device_Is_Not_Ready()
{
// ...
}
You can create your own ExpectedException attribute that will check if the thrown exception inherites the Exception defined in the attribute.
public sealed class MyExpectedException : ExpectedExceptionBaseAttribute
{
private Type _expectedExceptionBaseType;
public MyExpectedException(Type expectedExceptionType)
{
_expectedExceptionBaseType = expectedExceptionType;
}
protected override void Verify(Exception exception)
{
Assert.IsNotNull(exception);
Assert.IsTrue(exception.GetType().IsInstanceOfType(typeof(_expectedExceptionBaseType)) ||
exception.GetType().IsSubclassOf(typeof(_expectedExceptionBaseType)));
}
}
and change the attribute to your test:
[MyExpectedException(typeof(IOException))]

catch all unhandled exceptions in ASP.NET Web Api

How do I catch all unhandled exceptions that occur in ASP.NET Web Api so that I can log them?
So far I have tried:
Create and register an ExceptionHandlingAttribute
Implement an Application_Error method in Global.asax.cs
Subscribe to AppDomain.CurrentDomain.UnhandledException
Subscribe to TaskScheduler.UnobservedTaskException
The ExceptionHandlingAttribute successfully handles exceptions that are thrown within controller action methods and action filters, but other exceptions are not handled, for example:
Exceptions thrown when an IQueryable returned by an action method fails to execute
Exceptions thrown by a message handler (i.e. HttpConfiguration.MessageHandlers)
Exceptions thrown when creating a controller instance
Basically, if an exception is going to cause a 500 Internal Server Error to be returned to the client, I want it logged. Implementing Application_Error did this job well in Web Forms and MVC - what can I use in Web Api?
This is now possible with WebAPI 2.1 (see the What's New):
Create one or more implementations of IExceptionLogger. For example:
public class TraceExceptionLogger : ExceptionLogger
{
public override void Log(ExceptionLoggerContext context)
{
Trace.TraceError(context.ExceptionContext.Exception.ToString());
}
}
Then register with your application's HttpConfiguration, inside a config callback like so:
config.Services.Add(typeof(IExceptionLogger), new TraceExceptionLogger());
or directly:
GlobalConfiguration.Configuration.Services.Add(typeof(IExceptionLogger), new TraceExceptionLogger());
To answer my own question, this isn't possible!
Handling all exceptions that cause internal server errors seems like a basic capability Web API should have, so I have put in a request with Microsoft for a Global error handler for Web API:
https://aspnetwebstack.codeplex.com/workitem/1001
If you agree, go to that link and vote for it!
In the meantime, the excellent article ASP.NET Web API Exception Handling shows a few different ways to catch a few different categories of error. It's more complicated than it should be, and it doesn't catch all interal server errors, but it's the best approach available today.
Update: Global error handling is now implemented and available in the nightly builds! It will be released in ASP.NET MVC v5.1. Here's how it will work: https://aspnetwebstack.codeplex.com/wikipage?title=Global%20Error%20Handling
The Yuval's answer is for customizing responses to unhandled exceptions caught by Web API, not for logging, as noted on the linked page. Refer to the When to Use section on the page for details. The logger is always called but the handler is called only when a response can be sent. In short, use the logger to log and the handler to customize the response.
By the way, I am using assembly v5.2.3 and the ExceptionHandler class does not have the HandleCore method. The equivalent, I think, is Handle. However, simply subclassing ExceptionHandler (as in Yuval's answer) does not work. In my case, I have to implement IExceptionHandler as follows.
internal class OopsExceptionHandler : IExceptionHandler
{
private readonly IExceptionHandler _innerHandler;
public OopsExceptionHandler (IExceptionHandler innerHandler)
{
if (innerHandler == null)
throw new ArgumentNullException(nameof(innerHandler));
_innerHandler = innerHandler;
}
public IExceptionHandler InnerHandler
{
get { return _innerHandler; }
}
public Task HandleAsync(ExceptionHandlerContext context, CancellationToken cancellationToken)
{
Handle(context);
return Task.FromResult<object>(null);
}
public void Handle(ExceptionHandlerContext context)
{
// Create your own custom result here...
// In dev, you might want to null out the result
// to display the YSOD.
// context.Result = null;
context.Result = new InternalServerErrorResult(context.Request);
}
}
Note that, unlike the logger, you register your handler by replacing the default handler, not adding.
config.Services.Replace(typeof(IExceptionHandler),
new OopsExceptionHandler(config.Services.GetExceptionHandler()));
You can also create a global exception handler by implementing the IExceptionHandler interface (or inherit the ExceptionHandler base class). It will be the last to be called in the execution chain, after all registered IExceptionLogger:
The IExceptionHandler handles all unhandled exceptions from all
controllers. This is the last in the list. If an exception occurs, the
IExceptionLogger will be called first, then the controller
ExceptionFilters and if still unhandled, the IExceptionHandler
implementation.
public class OopsExceptionHandler : ExceptionHandler
{
public override void HandleCore(ExceptionHandlerContext context)
{
context.Result = new TextPlainErrorResult
{
Request = context.ExceptionContext.Request,
Content = "Oops! Sorry! Something went wrong."
};
}
private class TextPlainErrorResult : IHttpActionResult
{
public HttpRequestMessage Request { get; set; }
public string Content { get; set; }
public Task<HttpResponseMessage> ExecuteAsync(CancellationToken cancellationToken)
{
HttpResponseMessage response =
new HttpResponseMessage(HttpStatusCode.InternalServerError);
response.Content = new StringContent(Content);
response.RequestMessage = Request;
return Task.FromResult(response);
}
}
}
More on that here.
You may have existing try-catch blocks that you're not aware of.
I thought my new global.asax.Application_Error method wasn't being consistently called for unhandled exceptions in our legacy code.
Then I found a few try-catch blocks in the middle of the call stack that called Response.Write on the Exception text. That was it. Dumped the text on the screen then killed the exception stone dead.
So the exceptions were being handled, but the handling was doing nothing useful. Once I removed those try-catch blocks the exceptions propagated to the Application_Error method as expected.

Custom exception class to alert errors and log

I am writting an API for some data manipulation these days and I have faced a question that I cannot answer myself :D
I have made an exception class that extends the .net Application Exception class because I want to add some functionality there to be executed everytime the API throws an exception.
For example I want to alert the error message and stacktrace via sms and email and I want to log the inner exception via Log4net. I don't know if this is a good aproach to use with the custom exception class or if I overused the meaning of the custom exceptions.
I have read this article about how to extend the Exception in c#
so here we go with my example of code :
public class CustomExceptionClass : Exception
{
/// <summary>
/// I use custom functionality here everytime this exception occures
/// </summary>
/// <param name="errorMessage">error message</param>
/// <param name="innerEx">Inner exception that cause this exception</param>
public MyCustomException(string errorMessage, Exception innerEx) : base(errorMessage, innerEx)
{
//log exception
_log.ErrorFormat(errorMessage, innerEx);
//alert via sms and email
AlertMailer.SendAlertMessage(errorMessage, innerEx, innerEx.Message);
}
}
I think that doing logging and alerting by throwing a custom exception is a valid technique.
However, you shouldn't do the logging and alerting in the exception constructor. Instead you should catch the custom exception in all entry-points to your API and do the logging and alerting in the catch block. For example:
void MyApiFunction()
{
try
{
// do data manipulation
}
catch(MyCustomException ex)
{
_log.ErrorFormat(ex.ErrorMessage, ex.InnerEx);
AlertMailer.SendAlertMessage(ex.ErrorMessage, ex.InnerEx);
}
}
I would recomend you to use AOP instead.
PostSharp exception handling
Custom exceptions should be used to define different types of exception.
Exceptions from the database
Exceptions from file io
Exceptions from web services
They should be very simple, and contain no other logic than assigning variables. Why? Because if the exception constructor throws another exception you are going to have a hard time tracing it.
The ways i handle those exceptions are:
AOP (Spring.NET)
Specific try/catches
The global exception handler
In a program
namespace ConsoleApplication1 {
class Program {
static void Main(string[] args) {
try {
//do something
} catch(Exception e) {
//log error
}
}
}
}
Or in a web site
public class ApplicationErrorModule : IHttpModule {
public void Init(HttpApplication context) {
context.Error += new EventHandler(context_Error);
}
private void context_Error(object sender, EventArgs e) {
//log error
}
}
Heavy treatments like logging and sending an email don't belong in the constructor of the exception. You should instead handle the exception using AOP as #petro suggested, or in a catch statement.

Categories