Filtering exceptions in C# 6

There’s a new keyword in C# 6 which can only be used in conjunction with exception handling: when. With when we can put a filter on our catch clauses: catch a certain type of exception, e.g. IOException, but only if a certain condition is true. Otherwise continue with the next catch-clause if any.

Consider the following example:

Read more of this post

Advertisements

Preserving stacktrace information when processing exceptions with C# .NET

Have you ever tried to hunt down a bug and been blocked by an incomplete stacktrace? The stacktrace might point to a place in your code where you threw the exception with the “throw” keyword but there’s no information on where the exception was originally thrown.

This can happen if you process the exception within the catch clause, e.g. log it somewhere and then throw it back to the call stack.

Consider the following simple code where the first method calls the second which calls the next etc. and the last one throws an exception. The first method catches the exception, prints it to the Debug window and throws it:

Read more of this post

Exception handling in async methods in .NET4.5 MVC4 with C#

In this post we’ll take a look at how to handle exceptions that are thrown by actions that are awaited. My previous post already included some exception handling techniques in MVC4 but here we will concentrate on exceptions thrown by await actions. Check my previous 3 posts for the full story behind the code examples shown here.

We will simulate some problems by intentionally throwing an exception in GetResultAsync and GetDataAsync:

public async Task<String> GetDataAsync(CancellationToken ctk)
        {
            StringBuilder dataBuilder = new StringBuilder();
            dataBuilder.Append("Starting GetData on thread id ").Append(Thread.CurrentThread.ManagedThreadId)
                .Append(". ");
            ctk.ThrowIfCancellationRequested();
            await Task.Delay(2000);
            throw new Exception("Something terrible has happened!");
            dataBuilder.Append("Results from the database. ").Append(Environment.NewLine);
            dataBuilder.Append("Finishing GetData on thread id ").Append(Thread.CurrentThread.ManagedThreadId)
                .Append(".");
            return dataBuilder.ToString();
        }
public async Task<String> GetResultAsync(CancellationToken ctk)
        {
            StringBuilder resultBuilder = new StringBuilder();
            resultBuilder.Append("Starting GetResult on thread id ").Append(Thread.CurrentThread.ManagedThreadId)
                .Append(". ");
            ctk.ThrowIfCancellationRequested();
            await Task.Delay(2000);
            throw new Exception("The service is down!");
            resultBuilder.Append("This is the result of a long running calculation. ");
            resultBuilder.Append("Finishing GetResult on thread id ").Append(Thread.CurrentThread.ManagedThreadId)
                .Append(".");
            return resultBuilder.ToString();
        }

Also, increase the timeout value of the Index action so that we do not get a Timeout Exception:

[AsyncTimeout(4000)]
[HandleError(ExceptionType = typeof(TimeoutException), View = "Timeout")]
public async Task<ActionResult> Index(CancellationToken ctk)

Before you run the application change the ‘mode’ attribute of the customErrors element in the web.config to “Off” as we want to see the debug data.

It does not come as a surprise that we run into an exception:

Intentional exception YSOD

If you had worked with the TPL library before then you may have expected an AggregateException that wraps all exceptions encountered during the parallel calls. However, TPL behaves slightly differently in conjunction with the await keyword. It is still an AggregateException that is instantiated behind the scenes but the .NET runtime will only throw the first exception that was encountered during the method execution.

This is good news: we can set up our try-catch structures as usual; we don’t need to worry about inspecting an AggregateException anymore.

View the list of MVC and Web API related posts here.

Timeout exceptions with async/await in .NET4.5 MVC4 with C#

This post will discuss timeouts that occur with await and async in .NET4.5. For clarity on async and await in MVC4 check out my previous two blog posts: Await and async in .NET4.5 and Async controllers and actions in .NET4.5 MVC4

As await operations may involve some seriously long running actions, such as calling a slow web service, it can be a good idea to specify a timeout. We may not want to make the visitor wait 60 seconds just to see an error message afterwards. If your experience tells you that a web service normally responds within 5 seconds at most then it may be pointless waiting 50-60 seconds as you can be sure something has gone wrong. ASP.NET has a default request timeout of 90 seconds – correct me here if I’m wrong – but we can specify other values directly in code with an attribute: AsyncTimeout that takes the timeout value in milliseconds as parameter.

In addition to the AsyncTimeout attribute you’ll also need to supply an additional parameter of type CancellationToken to the async action. This parameter can be used by the long running services to check if the user has requested a cancellation. The CancellationToken has an IsCancellationRequested property which provides exactly this type of information. In our example we’ll pass this token to the service calls and use it to throw an exception if the request has been cancelled. As our services are not real service calls, there is no clean-up work to do but imagine that if an IO operation is interrupted by a user then the cancellation token can throw an exception and you can clean up all open resources or roll back the database operations in a catch clause.

You can read more about cancellation tokens on MSDN: Cancellation token on MSDN

Update service methods:

public async Task<String> GetDataAsync(CancellationToken ctk)
        {
            StringBuilder dataBuilder = new StringBuilder();
            dataBuilder.Append("Starting GetData on thread id ").Append(Thread.CurrentThread.ManagedThreadId)
                .Append(". ");
            ctk.ThrowIfCancellationRequested();
            await Task.Delay(2000);
            dataBuilder.Append("Results from the database. ").Append(Environment.NewLine);
            dataBuilder.Append("Finishing GetData on thread id ").Append(Thread.CurrentThread.ManagedThreadId)
                .Append(".");
            return dataBuilder.ToString();
        }
public async Task<String> GetResultAsync(CancellationToken ctk)
        {
            StringBuilder resultBuilder = new StringBuilder();
            resultBuilder.Append("Starting GetResult on thread id ").Append(Thread.CurrentThread.ManagedThreadId)
                .Append(". ");
            ctk.ThrowIfCancellationRequested();
            await Task.Delay(2000);
            resultBuilder.Append("This is the result of a long running calculation. ");
            resultBuilder.Append("Finishing GetResult on thread id ").Append(Thread.CurrentThread.ManagedThreadId)
                .Append(".");
            return resultBuilder.ToString();
        }

We know that the Index() action needs about 2 seconds to complete so let’s try something more aggressive to see what happens:

[AsyncTimeout(1000)]
        public async Task<ActionResult> Index(CancellationToken ctk)
        {
            DateTime startDate = DateTime.UtcNow;

            HomePageViewModel viewModel = new HomePageViewModel();
            viewModel.AddMessage(string.Concat("Starting Action on thread id ", Thread.CurrentThread.ManagedThreadId));
            CalculationService calcService = new CalculationService();
            DatabaseService dataService = new DatabaseService();

            Task<String> calculationResultTask = calcService.GetResultAsync(ctk);
            Task<String> databaseResultTask = dataService.GetDataAsync(ctk);

            await Task.WhenAll(calculationResultTask, databaseResultTask);

            viewModel.AddMessage(calculationResultTask.Result);
            viewModel.AddMessage(databaseResultTask.Result);

            DateTime endDate = DateTime.UtcNow;
            TimeSpan diff = endDate - startDate;

            viewModel.AddMessage(string.Concat("Finishing Action on thread id ", Thread.CurrentThread.ManagedThreadId));
            viewModel.AddMessage(string.Concat("Action processing time: ", diff.TotalSeconds));
            return View(viewModel);
        }

It is no surprise that we get a timout exception upon running the application:

Timeout YSOD

The yellow screen of death is great for debugging but not so nice in a production environment. To turn on custom error messages you must change web.config: locate the customErrors tag under system.web and change the mode attribute to “On” for the production environment. If your web.config does not have this tag then add it:

<system.web>
    <customErrors mode="On"></customErrors>

There is a default view in the Shared folder within Views called Error.cshtml. After modifying the web.config file the user will be redirected to that view upon an unhandled exception:

Error.cshtml screen

You can of course create custom views for errors and then specify which error view to show using attributes. Example:

[AsyncTimeout(1000)]
        [HandleError(ExceptionType = typeof(TimeoutException), View = "Timeout")]
        public async Task<ActionResult> Index(CancellationToken ctk)

This way you can specify error views for specific types of unhandled exceptions.

The next post will look at exception handling in async methods.

View the list of MVC and Web API related posts here.

ultimatemindsettoday

A great WordPress.com site

Elliot Balynn's Blog

A directory of wonderful thoughts

Softwarearchitektur in der Praxis

Wissenswertes zu Webentwicklung, Domain-Driven Design und Microservices

Technology Talks

on Microsoft technologies, Web, Android and others

Software Engineering

Web development

Disparate Opinions

Various tidbits

chsakell's Blog

WEB APPLICATION DEVELOPMENT BEST PRACTICES WITH MICROSOFT STACK & ANGULAR

Cyber Matters

Bite-size insight on Cyber Security for the not too technical.

Guru N Guns's

OneSolution To dOTnET.

Johnny Zraiby

Measuring programming progress by lines of code is like measuring aircraft building progress by weight.

%d bloggers like this: