I'm using EmbedIO with the Web API module.
I'd like to have an exception handler that will catch all the unhandled exceptions and return a suited HTTP error code according to the exception type. However, it's not clear if this can be achieved.
The class WebModuleBase exposes a property called OnUnhandledException that can be set to an ExceptionHandlerCallback, but when the callback is invoked, the response's status code has already been set to HttpStatusCode.InternalServerError, as stated in the code comments.
This is not convenient since I want to set the response code myself.
WebModuleBase exposes a different property called OnHttpException that can be set to a HttpExceptionHandlerCallback. This can be set to
HttpExceptionHandler.DataResponse(ResponseSerializer.Json) which partially solves the issue.
The main concern now is that the application exceptions must be converted to HttpException in the controllers.
I'd like to throw custom exceptions from the domain code, get them in an exception handler and just return a HTTPException in there, according to the initial exception.
Basically something similar to Exception Filters in ASP.NET Web API.
Here's the code to setup the web server:
var webApiModule = new WebApiModule("/api", ResponseSerializer.Json)
.WithController<MyController>();
webApiModule.OnUnhandledException = ExceptionHandler.DataResponseForException();
webApiModule.OnHttpException = ExceptionHandler.DataResponseForHttpException();
WebServerEmbedded = new EmbedIO.WebServer(
opt => opt
.WithUrlPrefix(url)
.WithMode(HttpListenerMode.EmbedIO))
.WithModule(null, webApiModule);
These are the delegates used for exception handlers:
internal static class ExceptionHandler
{
public static ExceptionHandlerCallback DataResponseForException()
{
return (context, exception) => ResponseSerializer.Json(context, exception.Message);
}
public static HttpExceptionHandlerCallback DataResponseForHttpException()
{
return (context, httpException) => ResponseSerializer.Json(context, httpException.Message);
}
}
Thanks.
Exceptions, as well as HTTP exceptions, are handled by EmbedIO at both module and server level (each nested module group introduces a further level, but that's beyond the point).
The catch clause for HTTP exceptions always comes before the "general-purpose" catch clause, for the obvious reason that HTTP exceptions are exceptions themselves and need to be sorted out. Therefore, if an exception handler throws a HTTP exception, the latter must be handled at an outer level.
In opther words, you can write a module-level exception handler that throws a HTTP exception, then use a server-level HTTP exception handler to generate the appropriate response.
var webApiModule = new WebApiModule("/api", ResponseSerializer.Json)
.WithController<MyController>()
.HandleUnhandledException(ExceptionHandler.DataResponseForException));
WebServerEmbedded = new EmbedIO.WebServer(
opt => opt
.WithUrlPrefix(url)
.WithMode(HttpListenerMode.EmbedIO))
.WithModule(webApiModule)
.HandleHttpException(ExceptionHandler.DataResponseForHttpException);
internal static class ExceptionHandler
{
public static Task DataResponseForException(IHttpContext context, Exception exception)
{
// Replace ANY_VALID_STATUS CODE with, well, any valid status code.
// Of course you can use different status codes according to, for example,
// the type of exception.
throw new HttpException(ANY_VALID_STATUS_CODE, exception.Message);
}
public static Task DataResponseForHttpException(IHttpContext context, IHttpException httpException)
{
context.Response.StatusCode = (int)HttpStatusCode.OK;
return ResponseSerializer.Json(context, httpException.Message);
}
}
EDIT: There's an even simpler way, if you need it for custom exceptions: just have your exceptions implement IHttpException.
Here you can see how IHttpException methods are used by the HTTP exception handling code.
Here is an example of probably the most obscure method, PrepareResponse.
EDIT: I added setting the status code in DataResponseForHttpException.
Related
In my base API controller class constructor, I am populating user permissions based on windows authentication. I am using something like
var ctx = new PrincipalContext(ContextType.Domain, System.Environment.UserDomainName.ToUpper());
var userInfo = UserPrincipal.FindByIdentity(ctx, System.Environment.UserName.ToUpper());
to get user information from AD. The problem is that when the user is locked out the application is failing with 500 since the exception occurs in the constructor. Is there a way to handle the exception of these calls and bubble it up as an Unauthorized exception or something else? I tried to surround it with try catch and throw httpresponse exception with unauthorized but it still bubbles up as 500.
edit #1
There are few more things happening in constructor and when it is failing I do not want to fail with 500. I need to catch the exception and throw something else. Authorization was just an example of one of those few things.
edit #2
To all who write that I should not have any logic in the constructor:
Constructors are used to initialize the object to a valid state. The controller of this part of the application has to have a database connection, user information and some other properties populated because all of the requests are using all this information. If any of those is failing I want to return a different type of the error to the user. In the case of a standard class it would be different type of exceptions (SqlException, DbConnectionException, Some sort of AD Exception). In the case of WebApi I want it to be a different type of the response codes (Unauthorized, Not Implemented (501) etc). Copy pasting the same code to every request in that section of the application represents a maintenance issue.
Since the original exception is wrapped into other exceptions few times the only way I found so far is to have a global exception filter and then navigate through the inner exceptions of the context. Exception till it is null or I didn't reach the exception of the type I am looking for.
namespace SomeWebApi
{
public class GlobalExceptionHandler : ExceptionHandler
{
public override async Task HandleAsync(ExceptionHandlerContext context, CancellationToken cancellationToken)
{
if (context.Exception != null)
{
Exception filteredException = context.Exception;
while (
(filteredException != null)
&&
(filteredException.GetType() != typeof(HttpResponseException)
)
{
filteredException = filteredException.InnerException ;
}
if (
(filteredException != null)
&&
(filteredException != context.Exception)
)
{
var httpResponseException = (HttpResponseException) filteredException;
var response = context.Request.CreateErrorResponse(
httpResponseException.Response.StatusCode,
httpResponseException
);
context.Result = new ResponseMessageResult(response);
}
}
}
}
}
Next I needed to register it in WebApiConfig.Register:
config.Services.Replace(typeof(IExceptionHandler), new GlobalExceptionHandler());
The eseaiest way is to not use user / sesion related logic in controllers constructor.
For authentication You can use attribute filters, for geting user information just create helper class and use it when needed.
edit
one last thing: try to use dependency injection (like structure map) it will force You to make proper changes in constructor and it will make initializing easier. https://www.exceptionnotfound.net/setting-up-dependency-injection-in-web-api-with-structuremap/
Note: this question is regarding elmah.io (https://elmah.io/), the cloud based exception logging service, and not the traditional Elmah .Net library.
I'm using ASP.NET Core and have a simple exception handling middleware.
public class HandleExceptionMiddleware
{
public HandleExceptionMiddleware(RequestDelegate next)
{
Next = next;
}
RequestDelegate Next { get; }
public async Task Invoke(HttpContext httpContext)
{
try
{
await Next(httpContext);
}
catch (Exception ex)
{
await HandleExceptionAsync(httpContext, ex);
}
}
Task HandleExceptionAsync(HttpContext context, Exception ex)
{
var code = HttpStatusCode.InternalServerError;
if (ex is ArgumentException)
code = HttpStatusCode.BadRequest;
var result = JsonConvert.SerializeObject(new { message = ex.Message });
context.Response.ContentType = "application/json";
context.Response.StatusCode = (int)code;
return context.Response.WriteAsync(result);
}
}
This middleware will return the following JSON responses depending on the exceptions that it sees:
For ArgumentException:
HTTP/1.1 400 Bad Request
{"message":""}
For all other exceptions:
HTTP/1.1 500 Internal Server Error
{"message":""}
I'd like elmah.io to log 500 responses and ignore 400 responses (which is the default elmah.io configuration). However, when the exception handler and elmah.io are registered in this order in Startup's Configure hook, nothing gets logged in elmah.io:
app.UseElmahIo("API_KEY", new Guid("LOG_ID"));
app.UseMiddleware<HandleExceptionMiddleware>()
If, however, I change the registration order to the following, everything gets logged (including 400 responses). This makes sense as elmah.io handles the exceptions before HandleExceptionMiddleware gets a chance to change the response:
app.UseMiddleware<HandleExceptionMiddleware>()
app.UseElmahIo("API_KEY", new Guid("LOG_ID"));
What is the best way to configure these services so that elmah.io logs 500 responses and ignores 400 responses?
The only workaround I came up with is to create and register 2 exception handing middlewares instead of just 1. One that registers before and one that registers after elmah.io. It works, but seems a bit ugly:
app.UseMiddleware<HandleInternalExceptionMiddleware>() // set 500 responses (these will have already been logged in elmah.io)
app.UseElmahIo("API_KEY", new Guid("LOG_ID"));
app.UseMiddleware<HandleExternalExceptionMiddleware>() // set 400 responses but ignore exceptions that should return 500 (these won't be logged in elmah.io)
I created a sample project here to demonstrate this behavior:
https://github.com/johnnyoshika/elmah-io-experiment
The correct way to configure elmah.io, is using behavior 2. You want to call the UseElmahIo method after calling other methods dealing with exceptions. This is because a lot of error handling middleware (including your HandleExceptionMiddleware) swallow all exceptions and convert the result to something else. In your case, HandleExceptionMiddleware catches all exceptions and set a new response. In this case, our middleware is never notified about the exception (as you mention as well).
We have a couple of different ways to solve this:
Solution 1
Call UseElmahIo after calling UseMiddleware and add a custom ignore filter to ignore the errors eventually becomming bad requests:
app.UseMiddleware<HandleExceptionMiddleware>();
app.UseElmahIo("API_KEY", new Guid("LOG_ID"), new ElmahIoSettings
{
OnFilter = msg => msg.Type == typeof(ArgumentException).Name
});
The downside of this approach is, that you will need to maintain a set of similar rules in both HandleExceptionMiddleware and in your elmah.io config.
Solution 2
Call UseElmahIo before calling UseMiddleware and specify which status codes to log, even though an exception isn't thrown (swallowed by HandleExceptionMiddleware in this case):
app.UseElmahIo("API_KEY", new Guid("LOG_ID"), new ElmahIoSettings
{
HandledStatusCodesToLog = new List<int> { 404, 500, ... }
});
app.UseMiddleware<HandleExceptionMiddleware>();
The downside if this approach is, that you will need to specify all status codes manually and that the information from the actual exception thrown, isn't available on elmah.io. The reason for this again is, that HandleExceptionMiddleware make it impossible for elmah.io to see that an exception were thrown.
I personally prefer solution 1, since that makes sure that all exceptions are catched, including information like stacktrace and the exception type.
I have an MVC Razor application that uses entity framework 6.0. However, if the DB is down or something, my code starts throwing exceptions at all kinds of random places like when I start evaluating my IEnumerable<T>s and IQueryable<T>s.
The model constructor is generated code that will be overwritten if I modify it which wouldn't help anyway because the constructor doesn't throw exceptions. Instead, the exceptions come in places like this
using (var dataContext = new ArchiveVMADDatabase.ArchiveDatabaseModel())
{
IQueryable<HDeploy> deploys = Helpers.GetProdDeploysFromArchive(dataContext);
var query = getBranchSelectListQuery(deploys);
listItems.AddRange(query);// EXCEPTION IF DB IS DOWN
}
Is there a good way for me to handle this in one place and avoid wrapping nearly 100% of my code in giant try catch blocks? I would really like to have it just return empty sets if it can't talk to the DB.
I'm not sure whether you are working with MVC or Web API, but in Web API one would use Exception Filters to centralize exception handling.
An exception filter is basically a derivative of the ExceptionFilterAttribute that can create a specific response depending on the caught exception:
public class NotImplExceptionFilterAttribute : ExceptionFilterAttribute
{
public override void OnException(HttpActionExecutedContext context)
{
if (context.Exception is NotImplementedException)
{
context.Response = new HttpResponseMessage(HttpStatusCode.NotImplemented);
}
}
}
You don't need to add try {} catch {} blocks anywhere -- Web API triggers the configured exception filters automatically as soon as an exception reaches the outer most layer of your system (i.e. the controller level).
You can activate an exception filter only for specific ApiControllers or globally for every controller.
I am trying to find how to catch all exceptions (raised on the server, not the client) from my ServiceStack services in order to write them to my custom logger (which writes it to the eventlog). Now I am confused what implementation to use. I find postings implementing a custom ServiceRunner which looks rather complicated.
I found in the documentation you can use something like:
public override void Configure(Funq.Container container)
{
this.ServiceExceptionHandler = (req, ex) => { WRITE EXCEPTION TO MY OWN LOGGER };
}
Now I am stuck because this method is not available (there is a collection named ServiceExceptionHandlers, note the 's' at the end).
You need to use the .Add method on the ServiceExceptionHandler because you can setup more than one handler, i.e. if you have multiple loggers. See here for more information.
You need two methods to catch all exceptions. One to catch the exceptions in your service, and one to catch the others. The code below shows how to handle both cases.
public override void Configure(Container container)
{
//Handle Exceptions occurring in Services:
this.ServiceExceptionHandler.Add((httpReq, request, exception) => {
// Log your exceptions here
...
// Call the default exception handler or prepare your own custom response
return DtoUtils.CreateErrorResponse(request, exception);
});
// Handle Unhandled Exceptions occurring outside of Services
// E.g. in Request binding or filters:
this.ExceptionHandler = (req, res, operationName, ex) => {
res.Write("Error: {0}: {1}".Fmt(ex.GetType().Name, ex.Message));
res.EndServiceStackRequest(skipHeaders: true);
};
}
Note:
The reason that ServiceStack is expecting a collection of handlers, and your example code didn't show this, is because that documentation is for v3 (BSD open source version of ServiceStack), the corresponding documentation is here, but you are running ServiceStack v4 (Commercial) where improvements have been made to allow multiple actions to be taken.
Hope this helps.
Assume that I am building an ASP.NET Web API application and it has the following structure:
As you can see from the diagram, the ASP.NET Web API core will talk to domain service layer (e.g. MembershipService class which has methods such as GetUsers, CreateUser, etc.) and my service classes will talk to one or multiple repositories to handle the operations.
It's very obvious that a service operation (such as MembershipService.CreateUser method) would fail for several reasons (unmet conditions, an exception thrown by the repository, etc.) and this is the place where I have the doubts.
Do you think that service classes should handle exceptions and return some sort of result object such as the below one:
public class OperationResult {
public OperationResult(bool isSuccess) : this(isSuccess) {
IsSuccess = isSuccess;
}
public OperationResult(bool isSuccess, Exception exception) : this(isSuccess) {
Exception = exception;
}
public bool IsSuccess { get; private set; }
public Exception IsSuccess { get; private set; }
}
public class OperationResult<TEntity> : OperationResult {
public OperationResult(bool isSuccess)
: base(isSuccess) { }
public OperationResult(bool isSuccess, Exception exception)
: base(isSuccess, exception) { }
public TEntity Entity { get; set; }
}
Or do you think that the service methods shouldn't abstract the exception like that and should throw the exception directly or indirectly (creating a new meaningful exception type specific to operation and put the thrown exception as its inner exception)?
When you are in-process, use exceptions.
I don't see ANY point in avoiding exceptions. Exceptions are there for good reasons, mainly to be used!
Just try to look at the big picture: you are trying to change Exception mechanism with the old fashion way of error checking. This way you'll lose all the merits of Exceptions (like separation of the error-handling and regular code, CallStack, ...) and gain nothing in return.
What I usually do in this situation is to catch the exception in service layer and rewrap it into a custom exception (with the reference to the original exception in the InnerException field).
Taking a page from Microsoft's book, the implementation of the Membership API throws exceptions rather than handling them and returning a result object, so I would consider this a best practice as long as you don't control both the client and the API.
In the case where you do control both the client and the API, it is my personal preference to return a result object or an error message. The reason for this is that I want to log capture detailed information about the source of actual exceptions, but I don't want an exception for everything that could go wrong, such as the password being incorrect.
In this case, a simple error message to the user will be more than sufficient. From real-world experience, recording exceptions to the event log or log file every time a validation error occurs is a major burden on operations personnel that are trying to determine whether or not there is an actual fault occurring or whether it is just a user's typo.