December 6, 2010

Exception data evolved

As detailed in my earlier post about exception signatures I and my colleagues take exceptions from our production servers seriously. In addition to grouping them by signatures (which helps a lot and makes triage much more pleasant) and logging them in our internal bug tracking software we also try to add relevant debug information whenever we throw an exception.

The BCL team in their infinite wisdom added the Exception.Data property. This property is simply an IDictionary which allows storing key and value pairs of any type. By default this is an empty collection which means you don’t have to worry about it being null.

Typical usage

public void LogonUser(string username, string password, string domain)
{
    try
    {
        DataStore.LogOnUser(username, password, domain);
    }
    catch (Exception exc)
    {
        var ae = new ApplicationException("Underlying logon failed, see InnerException", exc);
                
        ae.Data["username"] = username;
        ae.Data["domain"] = domain;

        throw ae;
    }
}

When the exception reaches our internal trac site it might look something like the image below (in our case the data dictionary will actually be added as a comment but you get the point).

example-data

This has proven to be is incredibly useful for debugging purposes but it is a bit tedious to actually write the code. Storing the exception in a variable just to get access to the data property just didn’t feel right to me and writing the same boilerplate .Data[“xyz”] = xyz was just boring.

Step 1 – The AddData extension method.

I started off by creating an extension method for System.Exception called AddData. AddData looks a bit like this (very simplified, see the end of the post for the real deal)

public static Exception AddData(this Exception exception, string key, object value)
{
    exception.Data.Add(key, value);
// whohoo, chaining! return exception; }

This allowed me to save a few keystrokes over the first method and I would end up with something like this instead

catch(...) {
    throw new ApplicationException("Underlying logon failed, see InnerException", exc)
        .AddData("username", username)
        .AddData("domain", domain);
}

It might not look like much but it sure helps when you want to add debug data to an already existing exception, it saves you from having to store the reference and so on but it still doesn’t solve the problem with having to write the argument names twice. This isn’t only a nuisance when writing the code; it’s very easy for the key and value to get out of sync if you’re doing refactoring since refactoring tools will only change the variable name, not the key.

My ideal solution would be something like this

catch(...) {
    throw new ApplicationException("Underlying logon failed, see InnerException", exc)
        .AddData(username)
        .AddData(domain);
}

And have the AddData method automatically infer the proper key name but since that’s not possible I had to find another way.

Step 2 – Taking a cue from ASP.NET MVC

We continued using the AddData extension method above for a couple of weeks before it dawned on me that I could use anonymous types to skip the parameter name duplication. Anonymous types have the great ability of being able to “infer” property names when initialized.

var x = new { username = username, password = password }
// Is the same as
var x = new { username, password }

With this in mind I wrote an AddData extension method which accepts a single object and then uses reflection to iterate over all properties and adds their property names and values into the exception data dictionary.  This allowed me to rewrite my code yet again.

catch(...) {
    throw new ApplicationException("Underlying data store logon failed, see InnerException", exc)
        .AddData(new { username, password });
}

Neat, isn’t it? This is the exact same technique that ASP.NET MVC uses for route-declarations, attributes in html helpers and more.

Reflection? Isn’t that horribly slow

Not like in the olden days. It comes with a cost but you shouldn’t be too worried since you’re probably not throwing exception often enough for it to matter anyway (and if you are, then you have bigger problems).

Teh codez

using System;
using System.ComponentModel;
using System.Diagnostics;

namespace freakcode.Extensions
{
    /// 
    /// Extension methods related to instances of System.Exception and inherited objects.
    /// 
    public static class ExceptionExtensions
    {
        /// 
        /// Adds the supplied debug data to the exceptions data dictionary and returns
        /// the exception allowing chaining.
        /// 
        /// The exception type, you should not need to specify this explicitly
        /// The exception.
        /// The key of the debug value to be inserted into the exceptions data dictionary.
        /// The value to be inserted into the exceptions data dictionary.
        /// key is null
        /// An element with the same key already exists in the Data dictionary
        public static T AddData<T>(this T exception, string key, object value) where T : Exception
        {
            if (exception == null)
                throw new ArgumentNullException("exception");

            if (key == null)
                throw new ArgumentNullException("key");

            /* Key or value is not serializable (or key is null). The default internal structure which
             * implements the IDictionary is going to throw an exception in Add() so instead of 
             * throwing another exception while preparing to throw the first one we silently ignore the
             * error. Unless we're building in debug mode that is, then we'll fail. */
            if (value != null && !value.GetType().IsSerializable)
            {
                Debug.Fail("Attempt to add non-serializable value to exception data");
            }
            else
            {
                exception.Data.Add(key, value);
            }

            return exception;
        }

        /// 
        /// Adds the each property name and value from the supplied object to the exceptions data dictionary and returns
        /// the exception allowing chaining.
        /// 
        /// The exception type, you should not need to specify this explicitly
        /// The exception.
        /// An object from where properties will be read and added to the exception debug data collection.
        /// key is null
        /// An element with the same key already exists in the Data dictionary
        public static T AddData<T>(this T exception, object values) where T : Exception
        {
            if (values == null)
            {
                // Some really nasty things can happen if you start throwing exceptions in the middle
                // of throwing exceptions so unless we're in debug more we'll just silently ignore it.
                Debug.Fail("Argument 'values' was null!");
            }
            else
            {
                foreach (PropertyDescriptor descriptor in TypeDescriptor.GetProperties(values))
                    exception.AddData(descriptor.Name, descriptor.GetValue(values));
            }
            
            return exception;
        }
    }
}
kick it on DotNetKicks.com

Licensing information

30 comments:

  1. Fantastic idea, great solution to this problem

    ReplyDelete
  2. Excellent stuff!

    And, to take it one step further so that you can do this:

    exception.Throw("Your description here", new { username, password });

    Use this extension:

    public static ApplicationException Throw(this T exception, string message, object values = null) where T : Exception
    {
    Contract.Requires(exception != null);

    var newEx = new ApplicationException(message, exception);
    if (values != null)
    newEx.AddData(values);
    return newEx;
    }

    ReplyDelete
  3. Very, very clever indeed!

    ReplyDelete
  4. for beginners like me need a lot of reading and searching for information on various blogs. and articles that you share a very nice and inspires me .

    ReplyDelete
  5. يعتبر موقعنا واحد من المواقع الكبري النمتخصصة للكثير من خدمات صيانة يونيون اير تعتبر صيانة يونيون اير من اشهر الصيانات الموجودة لذلك تستطيع الان التعرف على الكثير من الاعمال والصيانات من على موقعنا

    ReplyDelete
  6. شركة الاخلاص والامانة تعتبر الشركة الكبري فى تقديم الكثير والكثير من خدمات نقل عفش الطائف احصل معناعلى الكثير من افضل خدمات وخصومات نقل الاثاث الطائف باسعار مميزة جدا الى الجميع لدينا اعمال متميزة وخصومات رائعة

    ReplyDelete
  7. يعتبر موقعنا الافضل فى خدمات شركة امن وحراسة شركتنا شركة الحارس الخاص الشركة الكبري المتخصصة للكثير من الخدمات الامينة شركة امنية والاعمال المتميزة التى نقدمها اليكم

    ReplyDelete
  8. اكبر شركه صيانه فى الشرق االوسط هى صيانه جليم جاز التى بها الكثير والعديد من الصيانات م اقسام صيانات مختلفه وبجميع الطرق التى تناسبك من خلال صيانه على اعلى مستوى من الجوده الحديثه التى لم تكن لدى شركات اخرى التى من خلال تقنيات حديثه وبافضل قطع غيار اصليه باستبدال قطع الغيار التالفه اتصل بنا الان

    ReplyDelete

  9. شركة الاخلاص والامان علي اعلي جودة في مصر الان مع نقل عفش الطائف بيد متخصصين ومتميزين استمتع بجميع اعمال الشركة من خلال موقعنا المتميزه علي اعلي مستوي استمتع بكفاءه عالية ومتطورة مع نقل اثاث الطائف في المملكة وبيد خبراء النقل .


    http://www.نقل-عفش-مكة.com/%d9%86%d9%82%d9%84-%d8%b9%d9%81%d8%b4-%d8%a7%d9%84%d8%b7%d8%a7%d8%a6%d9%81-2/

    ReplyDelete
  10. الان سوف تجد الكثير من الاعمال الحديثة والمتميزه شركة تنظيف خزانات بمكة علي اعلي مستوي سوف تحصل علي اعمال متطورة لدي الشركة الان استمتع بالكثير من الخدمات المتميزه والمتطورة في العمل مع تنظيف خزانات بمكة باقل الاسعار وافضل الامكانيات الحديثة .
    http://www.el3nod.com/1/company-tanks-isolation-cleaning-mecca

    ReplyDelete
  11. الان الوكيل المعتمد توكيل كريازى الذى يعد من افضبل التوكيلات لدى الاجهزه الكهربائيه التى دجميعها تعتمد عليها من ثقه وتميز وخبرات سابقه وعديده فى صيانه الاجهزه الكهربائيه ايا كان بها من وجود خبرات عديده من الفنين والاداريين فى صيانه الاجهزه

    ReplyDelete
  12. تتوفر فروع مراكز صيانة كاريير المعتمدة في جميع انحاء و محافظات جمهورية مصر العربية حتى يتمكن عملاؤنا من الوصول الينا في اي وقت ممكن .

    ReplyDelete
  13. احصل علي افضل العروض والخدمات المقدمه من فريق عمل صيانه يونيون اير التي توفر افضل الخدمات لعملائها من حيث تركيب وصيانة جميع انواع الاجهزه الكهربائية المنزلية وباقل الاسعار .

    ReplyDelete
  14. يمكنكم الآن التواصل مع أكبر دار مسنين بمصر الجديدة
    للحصول علي أفضل مستوي خدمات فهم أهم دار مسنين بالمعادي
    و يقدموا خدمة مميزة حيث يضم مركز و دار مسنين بمدينة نصر
    أفضل الأطباء المتخصصون لعلاج كبار السن .

    للتواصل الآن عبر :-
    http://www.careolder.com/%d8%af%d8%a7%d8%b1-%d9%85%d8%b3%d9%86%d9%8a%d9%86-%d9%85%d8%b5%d8%b1-%d8%a7%d9%84%d8%ac%d8%af%d9%8a%d8%af%d8%a9-%d9%85%d8%af%d9%8a%d9%86%d8%a9-%d9%86%d8%b5%d8%b1-%d9%85%d8%b9%d8%a7%d8%af%d9%8a/

    ReplyDelete
  15. الان من خلال اقوي شركات مكافحة الحشرات الشركة الفرنسية في مصر تستطيع ان تحصل علي اقوي مكافحة للحشرات عن طريق افضل شركات ابادة الحشرات والقضاء عليها نهائيا في جميع انحاء جمهورية مصر العربية

    تواصلوا معنا الان من خلال موقعنا علي الانترنت:-
    http://www.anti-insects.com

    ReplyDelete
  16. زور موقعنا الاول والحصرى لدليل تجهيزات مطاعم لدينا كل ما يخص المطاعم ومعداتها لدينا احدث توكيلات يمكنك الان الاعتماد علينا لحصولك على تجهيزات فنادق لدينا كل شركات التى تعمل فى مجال صناعة كل ادوات المائدة فقط زور موقعنا الان لتعرف كل ماهو جديد لددينا

    http://www.hotel-restaurant-eg.com/

    ReplyDelete
  17. تقدم شركة امن وحراسة افضل طرق الحمايه للمتتلكات والشركات والفلل على يد امهر العاملين فى مجال الحراسه والتامين الشخصى فهناك وسائل واساليب اتصال دائم بين الحارسين وبين الشخص الذين يقومون بحراسته فقط انت معنا فى امان تام
    http://www.guards-security.com/

    ReplyDelete
  18. احصل علي افضل الخدمات المقدمة من شركة اسفلت اليتي اصبحت من اكبر الشركات بالمملكة الرعبية السعودية التي تعمل علي مقاولات عامة لسفلتة الطرق وتنفيذ اضخم المشورعات .

    ReplyDelete
  19. كثير من الناس الذين يعانون من خشونة في المفاصل والام في االعظام ويحتاجون دائما الي علاج طبيعي يذهبون الي العلاج في التشيك بسبب احتوائها علي ينابيع مياه مختلفة تتناسب مع جميع الحالات

    ReplyDelete
  20. يتوافر لدي مركز توكيل كاريير فريق صيانة مدرب علي مستوي عالي من الكفاءة والدقة في تصليح كافة الاعطال الممكن تواجدها في التكيفات والناتجة عن الاستخدام الخاطئ
    http://www.carriermaintenance.com/

    ReplyDelete
  21. يتوافر لدي مركز صيانة جولدي خدمة متميزة وهي الصيانة الدورية للاجهزة الكهربائية كل فترة وهذه الفترة تتحدد بناء علي الحالة المتواجد عليها الاجهزة وما تحتاجه من صيانة
    https://www.almyaa.com/Goldi-Maintenance/

    ReplyDelete
  22. يعمل مركز صيانة شارب علي الانتشار وفتح فروع كثيرة في عدد كبير من المحافظات لسهولة التواصل اليه دائما وايضا يتميز مركز صيانة جولدي بتوفيرة لجميع قطع الغيار الممكن الاحتياج اليها ليصبح الجهاز يعمل كانه جديد

    ReplyDelete
  23. يقوم مركز صيانة جروندنج بصيانة الاعطال باسرع وقت ممكن دون الحاجه الى انتظار فلا استغناء عنه فى اى منزل الان فقط نريد كسب ثقه عملائنا تواصلوا معنا عند ايجاد اى عطل خاص
    باجهزتكم وسوف يتم اصلاحه فى الحال فى خدمتكم على مدار اليوم
    http://www.maintenanceg.com/Grundig-Agent-Egypt.html

    ReplyDelete