Introduction
Component-Based Object Extender (CBO Extender)
is an object extensibility framework. It is a general-purpose tool for adding functionality to objects by attaching behaviors to interface methods of the objects at runtime.
The dynamic type of .NET 4 simplifies the definition of behaviors and makes programming with CBO Extender more flexible. In this article, I discuss how the dynamic type
in C# is used to define behaviors and add them to objects with CBO Extender.
Background
CBO Extender adds functionality to objects at runtime without involving design changes of components. With CBO Extender, you define a set of aspect methods to represent
behaviors based on your business or system requirements. Then, you can attach the methods to objects as needed in your application. The application development
and maintenance are made easier by putting concerns into individual methods and applying them to objects at runtime. There are several articles that discuss
how to add functionality like logging, security checking, sorting, and transaction management to applications using CBO Extender. Please see Application
Development With Component-Based Object Extender and Transaction Management With Component-Based Object Extender for details.
.NET 4 supports the dynamic
type, which enables operations to bypass compile-time type checking
and be resolved at runtime. Since CBO Extender is a runtime tool for object extensibility, using the dynamic
type can significantly simplify programming and make
aspect methods much more flexible and powerful.
CBOExtender 1.2 introduces the dynamic
type into aspect methods and can be downloaded as a NuGet package. You can also download the source code,
latest updates, and more examples at http://centurytechs.com/CBOExtender.html.
To install CBOExtender to your project from Visual Studio 2010, click Tools->Library Package Manager->Manage NuGet Packages... to open the Manage NuGet Packages dialog.
Type in CBOExtender as shown.

You probably need to install NuGet for Visual Studio 2010 before you can download the package.
The following discussions assume that you have read the above articles by following the links and have a basic understanding of what problems the CBO Extender tries
to solve and how to solve them.
Use the Code
In the following sections, I discuss how to define an aspect method with the dynamic
type. Then, I present two different approaches for attaching the aspect to an object.
The two approaches are: using CreateProxy2
and using ChainAspect2
. Most of the code is from the example application in the download.
Define Aspect
First and foremost, the dynamic
type makes the definition of an aspect method significantly simpler. The following example defines an aspect method
for adding a command to a transaction without using the dynamic
type.
public static void JoinSqlTransaction(AspectContext ctx, object[] parameters)
{
try
{
if (parameters != null && parameters[0] is IDbTransaction)
{
(ctx.Target as ISqlOperation).Command.Transaction =
parameters[0] as SqlTransaction;
return;
}
}
catch (Exception ex)
{
throw new Exception("Failed to join transaction!", ex);
}
}
With the dynamic
type, the aspect method is rewritten as follows. Both parameter
and Target
are dynamic
types.
public static void JoinSqlTransaction(AspectContext2 ctx, dynamic parameter)
{
try
{
ctx.Target.Command.Transaction = parameter;
return;
}
catch (Exception ex)
{
throw new Exception("Failed to join transaction!", ex);
}
}
As you see, runtime type checking code is no longer needed. The types are resolved at runtime when the method is called in your application.
The difference between AspectContext2
and AspectContext
is that the AspectContext2
has a Target
of dynamic
type while AspectContext
has a Target
of object
type.
Furthermore, the method with dynamic
type is not limited to parameter
as SqlTransaction
, and Target
as ISqlOperation
. Any type of object can be passed to parameter
and Target
can reference to any type of object as long
as the implementation of the types makes the statement ctx.Target.Command.Transaction = parameter;
work when it is executed. For example, you may call
this method somewhere in your application by passing an OracleTransaction
object to parameter
with Target
as IOracleOperation
presuming that you have defined OracleTransaction
and IOracleOperation
and implemented
the Target
's type properly so that the runtime can resolve the types and execute the statement ctx.Target.Command.Transaction = parameter;
.
The corresponding delegate for the aspect method with the dynamic
type is DecorationDelegate2
, which is defined as follows:
public delegate void DecorationDelegate2(AspectContext2 ctx, dynamic dynPara);
public class AspectContext2
{
public dynamic Target { get; set; }
public IMethodCallMessage CallCtx { get; set; }
public AspectContext2(object target, IMethodCallMessage callCtx)
{
Target = target;
CallCtx = callCtx;
}
}
Any method with the signature defined by the delegate can be encapsulated in an instance of the delegate.
Use CreateProxy2
The CreateProxy2
method of the ObjectProxyFactory
class can be used to associate aspects to an object and has the following signature:
public static T CreateProxy2<T>(object target,
String[] arrMethods, Decoration2 preAspect, Decoration2 postAspect)
Decoration2
encapsulates a DecorationDelegate2
object and a dynamic
object, and has a constructor with the following signature:
public Decoration2(DecorationDelegate2 aspectHandler, dynamic parameter)
The following code shows how CreateProxy2
is used to add the join transaction aspect to an object o
.
ObjectProxyFactory.CreateProxy2<IOrder>(
o,
new string[] { "InsertOrder" },
new Decoration2(AppConcerns.JoinSqlTransaction, transaction),
null
)
o
is the target object whose type should implement the interface IOrder
. The target type should also implement an interface
ISqlOperation
to ensure that the JoinSqlTransaction
does not throw an exception at runtime. The second argument indicates only the method
InsertOrder
of the target should be decorated with the aspects specified in the rest of the arguments (preAspect
- the preprocessing decoration,
postAspect
- the postprocessing decoration). The preprocessing decoration consists of a delegate object for the
JoinSqlTransaction
method and a dynamic type object transaction
. No postprocessing decoration is specified for this case.
Basically, the above code lays down the logic that adds the command associated with the target to the transaction
at runtime prior to calling
the InsertOrder
method of the objet o
.
Use ChainAspect2
If you use some kind of IoC container, you probably want to use the ChainAspect2
method of AOPContainer
to associate aspects to an object. ChainAspect2
has the following signature:
public static V ChainAspect2<T, V>(T target, string methods,
Decoration2 preDeco, Decoration2 postDeco) where T : V
The following code shows how ChainAspect2
is used to add the join transaction aspect to an object o
.
AOPContainer.ChainAspect2<IOrder, IOrder>(
o,
"InsertOrder",
new Decoration2(AppConcerns.JoinSqlTransaction, transaction),
null
)
Conclusion
In addition to the benefits of CBO Extender presented in the article Component-Based
Object Extender, the CBO Extender combined with the dynamic
type makes object extending much easier and more flexible.
Note: This article only shows how the dynamic
type is used to define aspects and how the aspects are added to objects. You may need to download the source code
to understand how they fit in the context of an application. The source code rewrites the example in the article Transaction Management
With Component-Based Object Extender using the dynamic
type.