Click here to Skip to main content
Click here to Skip to main content

Poor Man's Code Injector in C# 3.0 (Exception Handling Scope, Policy, *.* Injection)

, 18 Dec 2007 CPOL
Rate this:
Please Sign up or sign in to vote.
A simple way for implementing code injection in C# 3.0

Introduction

I've been making some WCF services recently and I am now at the point that a uniform exception handling would be needed. Of course, at first I thought of Enterprise Library. Its part is the Exception Handling Application Block, which is a very nice solution; however, I also do not like it because of the same reasons why I do not like Validation Application Block (too complex, hard to use). Or, there is Policy Injection Application Block. This is also a nice one, but you have to work too much to get any results.

If we think about it, these libs are nothing else but code, this code has a scope (validity range) and before and after it we want to inject code, into the same validity range.

EHAB makes a uniform exception code after our code according to certain rules, so we do not have to write handlers in each method. These can be held at one place and EHAB makes the rest.

PIAB will execute certain handlers given code before and after the execution of our code. E.g. validation and authorization before, exception handling and log after.

For this task, the aspect oriented programming was developed too. There are different libs for this too, lot of them are open source.

These are all difficult solutions for the same problem. According to the razor of Ockham, the most simple solution is the correct; that’s why I thought about how to solve this thing in simplest terms, in C# 3.0 for now and forever.

The Idea

There is a very useful construction in C#; there are too few who know how useful it could be in the hands of a coder. This is the anonymous method. Beginning from C# 3.0, the efficiency of this opportunity has increased, and can be entered with lambda syntax too. E.g.:

Func< int, bool > isPositive = v => v > 0;

This is a lambda expression, from which the compiler will generate anonym method, delegate being its type. But there is also an opportunity to give code block:

Func< int, string > listOf = v =>
{
  string result = null;
  for (int i = 0; i < v; i++)
  {
    result = i == 0 ? i.ToString() : string.Format("{0}, {1}", result, i.ToString();
  }
  return result;
} 

So, we do have a much shorter and more simple criss-cross instead of the long syntax:

delegate (string arg1, int arg2, ..., FooNs.FooClass argn) { ... } 

Why is this anonym method so interesting? Let’s see how it works:

class MyClass
{
  // 1. object context from the class

  Func< int, bool > MyMethod(int arg1, int arg2)
  {
    // 2. object context from the class, together with the given arguments

    Func< int, bool > anonim = (/*implicitly typed int*/ argOfAninom) =>
    {
       // 3. context from the anonym method, together with the 
       // given arguments for this anonim method
       return true.
    }

    return anonim;
  }
} 

Using anywhere, in any context, the anonym method in the example will access the context on the creation places 1, 2, and 3., especially it will stay part of the call-validity scope of MyMethod!

If we give some recursion to that, we have a scope list which is built on each other and managed totally by CLR. We can also use this for catching exceptions, being also the code stack valid through the whole call list!

The Solution

Knowing these, to implement a simple code injection is not a difficult task. We only need one structure:

public struct Scope
{
    public delegate Chain Chain(Chain code);
     
    public delegate void Block(); 
    
    public Scope(params Chain[] codes)
    {
        this.code = null;
        if (codes != null)
        {
            foreach (Chain code in codes)
            {
                AddCode(code);
            }
        }
    }

    public Scope(params Scope[] others)
    {
        this.code = null;
        if (others != null)
        {
            foreach (Scope other in others)
            {
                AddCode(other.code);
            }
        }
    } 
    
    Chain code; 
    
    private static Chain BlockToChain(Block code)
    {
        return c =>
        {
            code();
            return null;
        };
    } 
    
    private void AddCode(Chain otherCode)
    {
        if (otherCode != null)
        {
            Chain thisCode = this.code;
            if (thisCode == null)
            {
                this.code = otherCode;
            }
            else
            {
                this.code = (c) => otherCode(thisCode(c)); // Chain of anonym delegates.
            }
        }
    } 
    
    public Block Begin
    {
        set
        {
            if (value == null) throw new ArgumentNullException("value");
            if (code != null)
            {
                code(BlockToChain(value))(null); // Calling chain of delegates
            }
        }
    } 
    
    public static Scope operator +(Scope scope1, Scope scope2)
    {
        Scope result = new Scope(scope1);
        result.AddCode(scope2.code);
        return result;
    } 
    
    public static Scope operator +(Scope scope, Chain code)
    {
        Scope result = new Scope(scope);
        result.AddCode(code);
        return result;
    } 
    
    public static implicit operator Scope(Chain code)
    {
        return new Scope(code);
    } 
    
    public static implicit operator Chain(Scope scope)
    {
        return scope.code;
    }
}

The soul of it is a delegate-construction which refers to itself. On that ground, we are able to create the anonym method calling link. This little structure can be considered as a compiler, it can be combined with other Scope structures or Chain handler methods (see the constructor and the operators).

Using the Code

It is very simple. Let’s see how to define exception handling scopes. It is useful to classify the exceptions according to functions, to grade them into classes and to write handlers for these classes.

E.g. argument exception handling:

static Scope.Chain ArgumentExceptionScope(Scope.Chain upperNode)
{
    return (chainNode) =>
    {
        try
        {
            upperNode(null);
        }
        catch (ArgumentNullException ex)
        {
            if (echo) Console.WriteLine("Argument '{0}' is null.", ex.ParamName);
        }
        catch (ArgumentException ex)
        {
            if (echo) Console.WriteLine("Argument '{0}' is invalid.", ex.ParamName);
        }
        return null;
    };
} 

Exception handler for operations error:

static Scope.Chain InvalidOpertaionExceptionScope(Scope.Chain upperNode)
{
    return (chainNode) =>
    {
        try
        {
            upperNode(null);
        }
        catch (InvalidOperationException)
        {
            if (echo) Console.WriteLine("Invalid operation.");
        }
        return null;
    };
}

General exception handler:

static Scope.Chain ExceptionScope(Scope.Chain upperNode)
{
    return (chainNode) =>
    {
        try
        {
            upperNode(null);
        }
        catch (Exception ex)
        {
            if (echo) Console.WriteLine("Unhandled '{0}' exception: {1}", 
					ex.GetType().Name, ex.Message);
        }
        return null;
    };
} 

And so on. These are static methods, but this is not a condition, they can also belong to a class-instance. The essence of the idea is that the upperNode(null); means the code to be decorated and we can write any code to it in the handler (e.g. TransactionScope), the thing will be injected here. The upperNode() call parameter is of course null and also the return of the anonym, because the chainNode parameter and the return value are only ballasts, the essence is the calling of the anonym method.

The handler sees the environment where we have defined, that is why it is simple to create a logger built upon it:

public class Logger
{
    public Logger(string name)
    {
        Enabled = true;
        Name = name;
        logScope = new Scope(Log);
    } 
    
    public bool Enabled { get; set; } 
    
    public string Name { get; private set; } 
    
    Scope logScope; 
    
    public Scope LogScope
    {
        get { return logScope; }
    } 
    
    Scope.Chain Log(Scope.Chain upperNode)
    {
        if (Enabled) 
            return DoLog(upperNode); 
        else
            return ln => { upperNode(null); return null; };
    } 
    
    private Scope.Chain DoLog(Scope.Chain upperNode)
    {
        return node =>
        {
            Console.WriteLine(">LOG --- Entering: {0} ---", Name);
            try
            {
                upperNode(null);
            }
            catch (Exception ex)
            {
                Console.WriteLine(">LOG --- Exception caught: {0} ---", 
						ex.GetType().Name);
                throw ex;
            }
            Console.WriteLine(">LOG --- Leaving: {0} ---", Name);
            return null;
        };
    }
}

All right, we have a lot of handlers which can be created and are running simply; how to use those? Simply: let’s build up a (or more) Scope structure with operators:

Scope scope = new Scope();
scope += logger.LogScope;
scope += ArgumentExceptionScope;
scope += InvalidOpertaionExceptionScope;
scope += ExceptionScope; 

Or with the constructor:

scope = new Scope(logger.LogScope, 
            new Scope(ArgumentExceptionScope, InvalidOpertaionExceptionScope), 
            ExceptionScope); 

The scope builds up from inside to outside, so the handler given at last will circle the whole with its code. It does not matter if we build this from a ready or complex scope or from a handler, it will run and the “bubble”-rule from inside to outside will be valid.

It is very flexible, because some parts of it can be driven from that context where we have created them. In this example, logging can be switched on or off via the logger object in those scopes where this instance is there (logger Enabled). But we can drive the handlers with every kind of complex business rule. It is much more flexible than AOP and EntLib, because these are own systems, no kind of interfaces need to be implemented, nothing will be wired before and the CLR will arrange everything for us.

Nothing left but to run our code in a given scope (to inject). Nothing is more easy:

myCoolScope.Begin = () =>
{
   // Do stuff 
   
   // throw errors
   throw new Exception("Something went really wrong out there!");
}; 

We can do it in any method, the code will be injected into the environment defined by myCoolScope, can be logged, exceptions will be handled, policy handling can be defined and so on. It can be seen from the code of Scope that the code after Begin will be executed at once (property set): this scope after Begin construction has to be imagined like a normal using block!

There is one difference to using: in the Scope Begin code, you cannot simply return from the method with “return”, but this is also not a big problem. It is enough to keep up a local variable for this purpose:

private static void GetSomeValueTest()
{
    Console.WriteLine("\nGetSomeValueTest()");
    int v = 0;
    Console.WriteLine("Value is {0}.", v);
    v = GetSomeValueFromInjectedCode(v);
    Console.WriteLine("Value is {0}.", v);
} 

private static int GetSomeValueFromInjectedCode(int fromValue)
{
    fullScope.Begin = () =>
    {
        fromValue = fromValue + 1978;
    };
    return fromValue;
} 

The HandlerBase

I have also drawn a handler abstract base, to make life easier:

public sealed class ScopeExceptionEventArg : EventArgs
{
    public Exception Exception { get; internal set; }

    public bool Handled { get; set; }
}

public abstract class HandlerBase
{
    public HandlerBase()
    {
        scope = new Scope(ScopeMethod);
        Enabled = true;
    }
    
    Scope scope;

    // The Scope structure for compiling scopes:
    public Scope Scope
    {
        get { return scope; }
    }

    public static implicit operator Scope(HandlerBase handler)
    {
        if (handler == null) return new Scope();
        return handler.scope;
    }

    bool inFlag;

    public bool Enabled { get; set; } // Can be enabled or disabled

    // There are events also:
    
    public event EventHandler EnterScope;

    public event EventHandler LeaveScope;

    public event EventHandler< ScopeExceptionEventArg > ScopeException;


    Scope.Chain ScopeMethod(Scope.Chain code)
    {
        if (inFlag || !Enabled) return (p) => { code(null); return null; };

        return (p) => 
        {
            inFlag = true;
            try
            {
                OnEnterScope(EventArgs.Empty);
                this.code = code;
                Call();
            }
            finally
            {
                OnLeaveScope(EventArgs.Empty);
                inFlag = false;
            }
            return null; 
        };
    }

    Scope.Chain code;

    // Injected code called as a virtual method
    protected virtual void Call()
    {
        if (code != null)
        {
            try
            {
                code(null);
            }
            catch (Exception ex)
            {
                ScopeExceptionEventArg e = new ScopeExceptionEventArg { Exception = ex };
                OnScopeException(e);
                if (!e.Handled) throw ex;
            }
            finally
            {
                code = null;
            }
        }
    }

    // Event handler methods are virtual also
    
    protected virtual void OnEnterScope(EventArgs e)
    {
        EventHandler handler = EnterScope;
        if (handler != null) handler(this, e);
    }

    protected virtual void OnLeaveScope(EventArgs e)
    {
        EventHandler handler = LeaveScope;
        if (handler != null) handler(this, e);
    }

    protected virtual void OnScopeException(ScopeExceptionEventArg e)
    {
        EventHandler< ScopeExceptionEventArg > handler = ScopeException;
        if (handler != null) handler(this, e);
    }
}

This way we can create a logger (or anything else) much easier:

public class LoggerScope : HandlerBase
{
    public LoggerScope() : base() { }

    public string Message { get; set; }

    protected override void OnEnterScope(EventArgs e)
    {
        base.OnEnterScope(e);
        if (!string.IsNullOrEmpty(Message))
        {
            Console.WriteLine(">LOG --- Entering: {0} ---", Message);
        }
    }

    protected override void OnLeaveScope(EventArgs e)
    {
        base.OnLeaveScope(e);
        if (!string.IsNullOrEmpty(Message))
        {
            Console.WriteLine(">LOG --- Leaving: {0} ---", Message);
            Message = null;
        }
    }

    protected override void OnScopeException(ScopeExceptionEventArg e)
    {
        base.OnScopeException(e);
        if (!string.IsNullOrEmpty(Message))
        {
            Console.WriteLine(">LOG --- Exception caught: {0}, 
		Type: {1}  ---", Message, e.Exception.GetType().Name);
        }
    }
}

Or a profiler:

public class ProfilerScope : HandlerBase
{
    DateTime start;

    public TimeSpan EllapsedTime
    {
        get;
        private set;
    }

    protected override void OnEnterScope(EventArgs e)
    {
        base.OnEnterScope(e);
        start = DateTime.Now;
        EllapsedTime = TimeSpan.Zero;
    }

    protected override void OnLeaveScope(EventArgs e)
    {
        EllapsedTime = DateTime.Now - start;
        base.OnLeaveScope(e);
    }
}

And you can build a scope from those:

LoggerScope logger = new LoggerScope();
ProfilerScope profiler = new ProfilerScope();
Scope scope = new Scope(profiler.Scope, logger.Scope);

// ...

scope.Begin = () => // profiled and logged
{
 // Do stuff.
}

// ...

// Turn off logger for this call:
logger.Enabled = false;
scope.Begin = () =>
{
 // Do stuff.
}

// And so on. The scope can be handled with proper handler classes.

I have attached a test project so you can see how easy and efficient this is. In the test program, the exception handling is not much slower with this method than with ad hoc handler writing (it's about delegate calls), but much more faster and simpler than EHAB.

A Real Life Example

To show an example: I have an entity manager service. In its business logic, exceptions can happen. E.g. we want to move a city to a region, which belongs to another country than the city was – this creates an exception, because it is wrong, this cannot be done. These exceptions are defined by the business logic, these are standard CLR exceptions. But, these do not cross the SOAP communication, these have to be converted to compatible SOAP fault messages. The woodman-method would be if I slapped catching and converting the exceptions into the code of the façade. This is not good, it would be the task of the business logic to do this – it is its competence. Maybe I could write a WCF handler which executes this work automatically, but the problem with that would be that I could not test the libs without WCF, statically attached.

So I have written a Scope handler to the business logic, which from the façade can create the proper scope:

public class DataExceptionConvertHandler : HandlerBase
{
    protected override void Call()
    {
        try
        {
            base.Call();
        }

        catch (NameStoreItemNotFoundExcepton ex)
        {
            throw new FaultException< NameStoreItemNotFoundFault >
                (new NameStoreItemNotFoundFault { NameStoreItemID = ex.ID }, ex.Message);
        }

        catch (NameStoreItemIsUnremovableExcepton ex)
        {
            throw new FaultException< NameStoreItemIsUnremovableFault >
                (new NameStoreItemIsUnremovableFault 
			{ NameStoreItemID = ex.ID }, ex.Message);
        }

        catch (RegionNotFoundExcepton ex)
        {
            throw new FaultException< RegionNotFoundFault >
                (new RegionNotFoundFault { RegionUID = ex.EnitityUID, 
		CountryCode = GeoUtils.GetCountryCodeOfLCID(ex.LCID) }, ex.Message);
        }

        catch (RegionIsUnremovableExcepton ex)
        {
            throw new FaultException< RegionIsUnremovableFault >
                (new RegionIsUnremovableFault { RegionUID = ex.EnitityUID });
        }

        catch (SettlementNotFoundException ex)
        {
            throw new FaultException< SettlementNotFoundFault >
                (new SettlementNotFoundFault { SettlementUID = ex.EnitityUID });
        }

        catch (SettlementIsUnremovableException ex)
        {
            throw new FaultException< SettlementIsUnremovableFault >
                (new SettlementIsUnremovableFault { SettlementUID = ex.EnitityUID });
        }
    }
}

Everyone is in the right place, it is transparent, fast and easy to maintain. And this is how the service-façade looks like (now only this converting scope is available in this example):

public partial class PartnerManagementService : IPartnerManagement
{
    public PartnerManagementService()
    {
        facadeScope = new DataExceptionConvertHandler();
    }
    
    #region Scopes 
    
    Scope facadeScope; 
    
    #endregion
     
    #region Validation 
    
    private static void ValidateWithNeutralLocale(object request)
    {
        // I have a C 3.0 lambda based validator also. This will be my second post. ;)
    }
     
    private static void Validate(object request)
    {
        // ...
    }
    
    #endregion
} 
public partial class PartnerManagementService
{
    public NACENamesResponse GetNACENames(NACENamesRequest request)
    {
        NACENamesResponse response = null; 
        facadeScope.Begin = () =>
        {
            ValidateWithNeutralLocale(request); 
            INACEManager man = DataManagerFactory.CreateNACEManager();
            List< NACENameModel > list = man.GetByLCID
		(request.International.GetNeutralCulture().LCID);
            response = new NACENamesResponse
            {
                SectorNames = list.ToArray()
            };
        }; 
        return response;
    } 
    
    public NACENameResponse GetNACEName(NACENameRequest request)
    {
        NACENameResponse response = null; 
        facadeScope.Begin = () =>
        {
            ValidateWithNeutralLocale(request); 
            INACEManager man = DataManagerFactory.CreateNACEManager();
            response = new NACENameResponse
            {
                NACENameValue = man.GetName(request.NACECode, 
		request.International.GetNeutralCulture().LCID)
            };
        }; 
        return response;
    } 
    
    public void DefineNACEName(DefineNACENameRequest request)
    {
        facadeScope.Begin = () =>
        {
            ValidateWithNeutralLocale(request); 
            INACEManager man = DataManagerFactory.CreateNACEManager();
            man.DefineName(request.NACEName, 
		request.International.GetNeutralCulture().LCID);
        };
    } 
    
    public void UndefineNACEName(UndefineNACENameRequest request)
    {
        facadeScope.Begin = () =>
        {
            ValidateWithNeutralLocale(request); 
            INACEManager man = DataManagerFactory.CreateNACEManager();
            man.UndefineName(request.NACECode, 
		request.International.GetNeutralCulture().LCID);
        };
    }
} 

So, this is how the poor man's code injector looks like in C# 3.0. Use it in good health!

History

  • 18. Dec. 2007 - First version

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

Share

About the Author

Gabor Mezo
Architect 3GM Ltd.
Hungary Hungary
ex CAD MVP, MCPD 4.0

Comments and Discussions

 
GeneralMy vote of 5 PinmemberPhilip Liebscher24-Jan-11 10:39 
GeneralWhy does the delegate slow execution down? [modified] Pinmemberitemplate9-Jul-09 23:33 
GeneralRe: Why does the delegate slow execution down? Pinmemberunbornchikken19-Jul-09 4:28 
GeneralRe: Why does the delegate slow execution down? Pinmemberitemplate2-Aug-09 22:46 
GeneralVery good Pinmemberquizug22-Sep-08 23:39 
GeneralRe: Very good [modified] Pinmemberquizug22-Sep-08 23:40 
GeneralRe: Very good Pinmemberunbornchikken24-Feb-09 11:01 
Generalnice, but reads like Yoda-speak PinmemberSteveMets26-Dec-07 4:01 
GeneralRe: nice, but reads like Yoda-speak Pinmemberunbornchikken7-Jan-08 7:35 
GeneralClever PinmemberRoger J18-Dec-07 23:11 
GeneralVery nice PinmemberRichard Hein18-Dec-07 15:45 
GeneralRe: Very nice Pinmemberunbornchikken18-Dec-07 15:54 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Terms of Use | Mobile
Web03 | 2.8.141223.1 | Last Updated 18 Dec 2007
Article Copyright 2007 by Gabor Mezo
Everything else Copyright © CodeProject, 1999-2014
Layout: fixed | fluid