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.
Related
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.
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.
The application architecture is: MVVM[Views -> ViewModels] -> Repositories -> API.
The API layer can throw a TokenExpiredException exception, which we ultimately want to handle at the UI layer (by showing a message box and redirecting to login).
Today, our VMs interact with the repositories like so:
SomeCommand {
await _repo.DoSomethingAsync();
}
My question is on finding a good pattern to handle this exception from the API layer. I can think of 3 approaches:
1) Wrap every repository call in a BaseViewModel method that takes care of catching and handling this view model-agnostic exception.
SomeCommand {
await base.RepoRequest(() => _repo.DoSomethingAsync());
}
where BaseViewModel would have:
RepoRequest(action) {
try { action() }
catch (TokenExpiredException) {
// show message box
// redirect
}
any other exception, such as a validation error, would be handled in the VM. The problem I see here is that it's too easy to forget to use this pattern. I might call the repository directly somewhere and miss handling the exception.
2) Every VM catches this exception
SomeCommand {
try { await _repo.DoSomethingAsync(); }
catch (InvalidUsernameException) { ... }
catch (TokenExpiredException) {
// show message box
// redirect
}
Not really different from 1), same issues and requires more code duplication.
3) Using an event aggregator to publish a message from the API layer to the BaseViewModel.
ApiRequest {
var response = await _httpClient.ExecuteAsync<..>(...);
if (response.ErrorId == "InvalidUsername")
throw new InvalidUsernameException();
else if (response.ErrorId == "TokenExpired")
EventAggregator.Publish(new TokenExpiredException());
}
and BaseViewModel
onMessage(TokenExpiredException e) {
// show message box
// redirect
}
This has the advantage of leaving all VMs (but the base) free of wiring up.
Disadvantage is that I'm hesitant to use an event aggregator 1) at all 2) at the API layer.
We are using mvvm-light and this would mean referencing those libraries in our deeper layers just for the Messenger (its event aggregator).
Does anyone have a suggestion as to how to cleanly implement this functionality?
I had to figure out the same problem, but I was using WCF with the castle wcf facility, this helped me, because the facility already had point of extension for intercepting the calls. So I just created my custom AbstractWcfPolicy and intercepted all the exception that I want to manage.
With the same idea you can think about using a proxy class, based on castle dynamic proxy, in that way your call will remain await _repo.DoSomethingAsync(); but under the wood your ExceptionInterceptor will intercept all the exception and do whatever you want:
[Serializable]
public class Interceptor : IInterceptor
{
public void Intercept(IInvocation invocation)
{
Console.WriteLine("Before target call");
try
{
invocation.Proceed();
}
catch(Exception)
{
Console.WriteLine("Target threw an exception!");
throw;
}
finally
{
Console.WriteLine("After target call");
}
}
}
Then you can throw back some of the exceptions you might want to throw anyway, for some of the exception or all, you could also implement a publish-subscribe (a global message broker, the messenger in MVVM Light) mechanism where you push the exception, and then in any point of your application you can subscribe to those errors and do something (log, show the error to the user in an unobtrusive way, etc...).
In my services all exposed methods have:
try
{
// the method core is written here
}
catch(Exception ex)
{
Log.Append(ex);
}
It's boring and ugly to repeat it over and over again. Is there any way to avoid that? Is there a better way to keep the service working even if exceptions occur and keep sending the exception details to the Log class?
Try AOP. This is the most widely-used selling point of AOP.
Also, see this discussion here on SO.
You could set up a generic error handling method for all uncaught exceptions like so:
AppDomain.CurrentDomain.UnhandledException += new UnhandledExceptionEventHandler(UnhandledException);
Depending on what went wrong, you may not be able to recover from the error... but this should hopefully give you some idea of what what went wrong. If it gets to the point where your application code hasn't handled the exception gracefully, this method could attempt to reinitialize the service to a known working state.
I came up with a semi-solution right now. I can refactor the code:
public TResult ExecuteAndLogOnError(Func<TResult> func)
{
try
{
return func();
}
catch(Exception ex)
{
// logging ...
}
}
And then you can call it on each method:
return ExecuteAndLogOnError(() =>
{
// method core goes here..
});
Which is 4 lines shorter than the original scenario.
In such cases I always use centralized error handlers.
In WCF it is very easy. Some more details:
http://www.haveyougotwoods.com/archive/2009/06/24/creating-a-global-error-handler-in-wcf.aspx
Basically, you just implement the IServiceBehavior interface and then provide your own error handler. That is the best way to do this because you don't have to write any code that handles fatal exceptions (I mean exceptions that you can only log and you don't know what to do about them) in your methods.
If all your doing is logging then just log the error at a later stage... No need to log the error early. If you do more than log the error, well then you're gonna need the try..catch anyway. And if you swallow exceptions (IE. just log them and then go on as if nothings happened) then maybe you're doing it wrong...
I once used something like the Template Function Pattern to resolve a problem like this. I had a base class that did something like:
public void Execute()
{
try
{
ExecuteImplementation();
}
catch (Exception ex)
{
// Log ex
}
}
public abstract void ExecuteImplementation();
There was one derived class per web service operation. The derived classes each implemented ExecuteImplementation.
The web service operations did:
[WebMethod]
public Result WebOperation(Request request)
{
WebOperationClass instance = new WebOperationClass(request);
instance.Execute();
return instance.Result;
}
Exception filters would be good for this. Alas, .NET supports them through MSIL, C++/CLI, VB.NET, but not C#.
If all you're doing in your catch is logging the exception, you could maybe just use a custom error page and let ELMAH log all your uncaught exceptions.
A previous poster brought up AOP (Aspecte-Oriented Programming).
I use PostSharp for basic logging traces/exceptions.
It's quite easy to use and setup.
Check out this link and watch the tutorial.
http://www.sharpcrafters.com/postsharp
--crap it is no longer open source ... anyways you can grab Postsharp1.5 and mess around with it to see if it is something you are interested in it.
I am also in no way affiliated with PostSharp. I'm just a user.
I have a website built in C#.NET that tends to produce a fairly steady stream of SQL timeouts from various user controls and I want to easily pop some code in to catch all unhandled exceptions and send them to something that can log them and display a friendly message to the user.
How do I, through minimal effort, catch all unhandled exceptions?
this question seems to say it's impossible, but that doesn't make sense to me (and it's about .NET 1.1 in windows apps):
All unhandled exceptions finally passed through Application_Error in global.asax. So, to give general exception message or do logging operations, see Application_Error.
If you need to catch exeptions in all threads the best aproach is to implement UnhandledExceptionModule and add it to you application look here
for an example
Use the Application_Error method in your Global.asax file. Inside your Application_Error method implementation call Server.GetLastError(), log the details of the exception returned by Server.GetLastError() however you wish.
e.g.
void Application_Error(object sender, EventArgs e)
{
// Code that runs when an unhandled error occurs
log4net.ILog log = log4net.LogManager.GetLogger(typeof(object));
using (log4net.NDC.Push(this.User.Identity.Name))
{
log.Fatal("Unhandled Exception", Server.GetLastError());
}
}
Don't pay too much attention to the log4net stuff, Server.GetLastError() is the most useful bit, log the details however you prefer.
The ELMAH project sounds worth a try, its list of features include:
ELMAH (Error Logging Modules and
Handlers) is an application-wide error
logging facility that is completely
pluggable. It can be dynamically added
to a running ASP.NET web application,
or even all ASP.NET web applications
on a machine, without any need for
re-compilation or re-deployment.
Logging of nearly all unhandled exceptions.
A web page to remotely view the entire log of recoded exceptions.
A web page to remotely view the full details of any one logged
exception.
In many cases, you can review the original yellow screen of death that
ASP.NET generated for a given
exception, even with customErrors mode
turned off.
An e-mail notification of each error at the time it occurs.
An RSS feed of the last 15 errors from the log.
A number of backing storage implementations for the log
More on using ELMAH from dotnetslackers
You can subscribe to the AppDomain.CurrentDomain.UnhandledException event.
It's probably important to note that you are not supposed to catch unhandled exceptions. If you are having SQL timeout issues, you should specifically catch those.
Do you mean handling it in all threads, including ones created by third-party code? Within "known" threads just catch Exception at the top of the stack.
I'd recommend looking at log4net and seeing if that's suitable for the logging part of the question.
If using .net 2.0 framework, I use the built in Health Monitoring services. There's a nice article describing this method here: https://web.archive.org/web/20210305134220/https://aspnet.4guysfromrolla.com/articles/031407-1.aspx
If you're stuck with the 1.0 framework, I would use ELMAH:
http://msdn.microsoft.com/en-us/library/aa479332.aspx
hope this helps
There are 2 parts to this problem handling & identifying.
Identifying
This is what you do when the exception is finally caught, not necessarily where it is thrown. So the exception at that stage must have enough context information for you to idenitfy what the problem was
Handling
For handling, you can
a) add a HttpModeule. See
http://www.eggheadcafe.com/articles/20060305.asp
I would suggest this approach only when there is absolutely no context informaatn available and there might be issuus wiih IIS/aspnet, In short for catastrophic situations
b) Create a abstract class called AbstractBasePage which derives from Page class and have all your codebehind classes derive from AbstractBasePage
The AbstractBasePage can implement that Page.Error delegate so that all exceptions which percolate up through the n-tier architecture can be caught here(and possibly logged)
I would suggest this cause for the kind of exceptions you are talking about (SQlException) there is enough context information for you to identify that it was a timeout and take possible action. This action might include redirecting user to a custom error page with appropriate message for each different kind of exception (Sql, webservice, async call timeouts etc).
Thanks
RVZ
One short answer is to use (Anonymous) delegate methods with common handling code when the delegate is invoked.
Background: If you have targeted the weak points, or have some boilerplate error handling code you need to universally apply to a particular class of problem, and you don't want to write the same try..catch for every invocation location, (such as updating a specific control on every page, etc).
Case study: A pain point is web forms and saving data to the database. We have a control that displays the saved status to the user, and we wanted to have common error handling code as well as common display without copy-pasting-reuse in every page. Also, each page did it's own thing in it's own way, so the only really common part of the code was the error handling and display.
Now, before being slammed, this is no replacement for a data-access layer and data access code. That's all still assumed to exist, good n-tier separation, etc. This code is UI-layer specific to allow us to write clean UI code and not repeat ourselves. We're big believers in not quashing exceptions, but certain exceptions shouldn't necessitate the user getting a generic error page and losing their work. There will be sql timeouts, servers go down, deadlocks, etc.
A Solution: The way we did it was to pass an anonymous delegate to a method on a custom control and essentially inject the try block using anonymous delegates.
// normal form code.
private void Save()
{
// you can do stuff before and after. normal scoping rules apply
saveControl.InvokeSave(
delegate
{
// everywhere the save control is used, this code is different
// but the class of errors and the stage we are catching them at
// is the same
DataContext.SomeStoredProcedure();
DataContext.SomeOtherStoredProcedure();
DataContext.SubmitChanges();
});
}
The SaveControl itself has the method like:
public delegate void SaveControlDelegate();
public void InvokeSave(SaveControlDelegate saveControlDelegate)
{
// I've changed the code from our code.
// You'll have to make up your own logic.
// this just gives an idea of common handling.
retryButton.Visible = false;
try
{
saveControlDelegate.Invoke();
}
catch (SqlTimeoutException ex)
{
// perform other logic here.
statusLabel.Text = "The server took too long to respond.";
retryButton.Visible = true;
LogSqlTimeoutOnSave(ex);
}
// catch other exceptions as necessary. i.e.
// detect deadlocks
catch (Exception ex)
{
statusLabel.Text = "An unknown Error occurred";
LogGenericExceptionOnSave(ex);
}
SetSavedStatus();
}
There are other ways to achieve this (e.g. common base class, intefaces), but in our case this had the best fit.
This isn't a replacement to a great tool such as Elmah for logging all unhandled exceptions. This is a targeted approach to handling certain exceptions in a standard manner.
Timeout errors typically occur if you are not forcefully closing your sqlconnections.
so if you had a
try {
conn.Open();
cmd.ExecuteReader();
conn.Close();
} catch (SqlException ex) {
//do whatever
}
If anything goes wrong with that ExecuteReader your connection will not be closed. Always add a finally block.
try {
conn.Open();
cmd.ExecuteReader();
conn.Close();
} catch (SqlException ex) {
//do whatever
} finally {
if(conn.State != ConnectionState.Closed)
conn.Close();
}
This is old question, but the best method (for me) is not listed here. So here we are:
ExceptionFilterAttribute is nice and easy solution for me. Source: http://weblogs.asp.net/fredriknormen/asp-net-web-api-exception-handling.
public class ExceptionHandlingAttribute : ExceptionFilterAttribute
{
public override void OnException(HttpActionExecutedContext context)
{
var exception = context.Exception;
if(exception is SqlTimeoutException)
{
//do some handling for this type of exception
}
}
}
And attach it to f.e. HomeController:
[ExceptionHandling]
public class HomeController: Controller
{
}