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

The simplest AOP scenario in C#

By , 29 Sep 2004
 

Introduction

AOP is very interesting, because it addresses some common problems in complex programs. If you just don’t know what AOP is, I suggest you to read an article like [1].

Many different AOP implementations already exist, mainly as open source. Since I’ve seen many programmers, particularly in .NET world, play a little with the existing AOP libraries only to conclude that AOP is too complex to understand and insert in their projects, this article will introduce a simple approach to the base concepts of AOP, sketching the code necessary to build a custom AOP solution.

I don’t want to enter in the flame “AOP != Attributes + Interception” (see for example [2]), but I’m used to think about software fragments only in terms of their usefulness, not if they conform to some theory (ok, I just entered the flame! :-)).

What I want to say is that if everyone must agree that the theory of AOP is really rich and complex (and maybe beautyful because of this), very often what the programmer needs in every day working is something light and quick to handle, that can solve a great part of his/her problems.

I’ll talk about this and more all along the article, while commenting the code.

Interception and ContextBoundObject

Every AOP implementation is based, first of all, on some form of interception: it can be static, dynamic, precompiled, marked with attributes, and who knows how. What we know is that we have to intercept the calls to the methods of certain classes.

In .NET platform, this can be achieved mainly with two approaches: injecting the IL code with the desired redirections (precompiling the code with some instrument or modifying the result of a normal compilation), or basing these classes on the .NET library class ContextBoundObject. Handling bytecode is very difficult, not much evolution-resistant (what about the next release of .NET platform?), and available only to programmers with a lot of free time. Using ContextBoundObject as a base for AOP has been already investigated very deeply [3], and I can only add that is so easy that it’ll be our choice (but certainly limiting ourselves in the capabilities).

The most important concern is performance: while I suggest to read the documentation to understand why it is so slow to use ContextBoundObjects, let’s find some number. It will be very simple: just create a new project and insert for example the following code.

using System;
using System.Windows.Forms;

public class Test //: ContextBoundObject
{
 public void Go()
 {
  int k = 32;
  k *= 2;
 }

 public static void Start()
 {
  Test t = new Test();

  int starttime = Environment.TickCount;
  for (int i = 0; i < 5000000; i++)
   t.Go();
  int endtime = Environment.TickCount;

  MessageBox.Show("Total time is: " + (endtime - starttime).ToString());
 }
}
  

In my test machine executing Test.Start() gives on average a result of 31. Removing the comment I obtain on average 109. This is more than 300% slower, that can look as an incredible cost just to use a CBO. But we have also to think to absolute times: in the above test we made 5,000,000 invocations, that means that each invocation had a call time of 0,022 microseconds. In my opinion, this cost is totally acceptable for the best part of real-world applications: of course, adding services to the interception mechanism will have an impact on these times, and each time I will run again the tests to show you the results. Right now we can state one important thing: as you can see debugging the code over the line that builds an object of type Test, the reference t points to a TransparentProxy, that represents our chance to intercept the method call to the underlying object.

Interception

This part is the easiest: I just stole the code attached to the article [4], to which I must send my credits! This article is really interesting from the point of view of technology, but takes into account a lot of services that we don’t need at all. So, in the end, it’s not true that I just stole the code: I’ve thrown away what I don’t need here, and what remained is a very little bunch of code. I don’t want to explain again the details of the interception chain, and I will spend just a few words on the actors (the code for each is very simple, see the documentation for the details).

AOPAttribute – We need an attribute to mark the CBO, because we must add a dummy property to its context.

    [AttributeUsage(AttributeTargets.Class)]
    public class AOPAttribute : ContextAttribute
    {
        public AOPAttribute() : base("AOPAttribute") {}

        public override void GetPropertiesForNewContext(IConstructionCallMessage ctor)
        {
            if (AOPConfig.Enabled)
                ctor.ContextProperties.Add(new AOPProperty());
        }

        public override bool IsContextOK(Context ctx, 
            IConstructionCallMessage ctorMsg)
        {return false;}
    }

AOPProperty – The property is needed only to add a message sink.

    public class AOPProperty : IContextProperty, IContributeServerContextSink
    {
        public AOPProperty() {}

        public IMessageSink GetServerContextSink(IMessageSink nextSink)
        {
            IMessageSink logSink = new AOPSink(nextSink);
            return logSink;
        }

        public string Name {get {return "AOP";}}

        public bool IsNewContextOK(Context ctx)
        {
            AOPProperty newContextLogProperty = 
           ctx.GetProperty("AOP") as AOPProperty;
            if (newContextLogProperty == null)
            {
                Debug.Assert(false);
                return false;
            }
            return (true);
        }

        public void Freeze(Context ctx) {}
    }

AOPSink – It’s our custom interceptor. Here we’ll have the chance to process method invocations.

    public class AOPSink : IMessageSink
    {
        private IMessageSink m_NextSink;
        private ObjRef realobject = null;

        public AOPSink(IMessageSink nextSink)
        {this.m_NextSink = nextSink;}

        public IMessageSink NextSink {get {return m_NextSink;}}

        public IMessage SyncProcessMessage(IMessage msg)
        {
            return m_NextSink.SyncProcessMessage(msg);
        }

        public IMessageCtrl AsyncProcessMessage(IMessage msg, 
             IMessageSink replySink)
        {
            throw new NotSupportedException();
        }
    }

AOPBaseClass – Lastly, we don’t want our users to remember the right derivation and the right attribute marking, so we create a base class for all the classes that will be intercepted, and where we group a common service (more on this later, now don’t worry for the SyncProcessMessage function).

    [AOP]
    public class AOPBaseClass : ContextBoundObject
    {
        public AOPBaseClass() {}

        public virtual IMessage SyncProcessMessage(
            IMessageSink sink, IMessage msg)
        {
            AOPControllerInfo cinfo = AOPConfig.GetAssoc(GetType());
            if (cinfo != null && cinfo.controller != null)
            {
                if (cinfo.matcher.IsMatch(msg))
                    return cinfo.controller.SyncProcessMessage(
                        this, sink, msg);
            }

            return sink.SyncProcessMessage(msg);
        }
    }

Why is it so complex to set up an interception infrastructure, if CBOs exist just to be intercepted? Because the service is primarily intended for .NET Remoting and for cross-AppDomain calls. Basically each invocation is translated in an IMessage object, that represent the original request. It’s hence possible to serialize the message to send it for example to another machine, and so on. We don’t need all of this, but since there is no other simplified support, I’ve tried to reduce at a minimum the needed code.

SyncProcessMessage()

The key function in all this part of code is AOPSink.SyncProcessMessage(). Once we set up a class marked with an AOPAttribute, the above code intercepts all method calls translating them in messages and passing them to this function. In the test code above, you can see that the implementation doesn’t do anything but passing the message to the next sink. The result is that all of this code is absolutely invariant: it’s only slower because of the translations in messages. It’s interesting to look at the performance. This is the test class we’ll use from here on for our tests:

    public class TestClass : AOPBaseClass
    {
        private void Output(string s)
        {
            //Console.WriteLine(s);
            MessageBox.Show(s);
        }
        
        public void Test1() { Output("Test1"); }
        public void Test2() { Output("Test2"); }
        public void Test3() { Output("Test3"); }
        public void Go() { Output("Go"); }
    }

Ok, we have some doubtly useful classes, but at least the test class is straightforward: just derive it from AOPBaseClass and you’re done!

The comparison, as usual, is done calling a lot of times a function (say, Test1), commenting and uncommenting the derivation in TestClass. Calling 100,000 times the ‘straight’ class gives us as usual a result of 31, while removing the comment the time goes up to 1,188, always on average. Things are getting a little worse, that’s a big difference; but the absolute time of a method invocation, on average, is 0.012 milliseconds, or about 12 microseconds. While this can start to be a problem for computationally intensive applications, it should still be absolutely bearable for the average application (say 80%?)

Now we have a complete interception mechanism: if you want, you can stop reading this article! You know how much it will cost, and what you do inside the SyncProcessMessage is completely up to your fantasy. For example, you can invoke twice the underlying method, just writing:

    m_NextSink.SyncProcessMessage(msg);
    return m_NextSink.SyncProcessMessage(msg);

Maybe you will lose the first result, but if you can imagine a scenario in which this can be useful (I could give you a hint: suppose you want to modify a database application to write your data toward two different sources at the same time...), you can go for it: I don’t know if this could be possible with available AOP libraries (can someone let me know about this?)

AOP basics

Once solved the technological problems we can go further on to build a useful infrastructure to provide AOP services. The first, classical, steps must deal with pre-processing and post-processing of method invocations.

Here we can leverage our experience and fantasy, and the design I present is of course only one of the possible.

I start by saying that I don’t like attributes that much. They are pretty, easy to write and use but they are intrinsecally static: once you mark with an attribute, you don’t have any chance to modify it. I’ve seen many architectures based on attributes, and each time I wonder if they can be handled properly. Some quick examples, based on the typical AOP examples, are the following: when AOP is used for logging, often we need to log certain classed and not others, maybe sometimes we want to log only starting from some point in time on, and obviously sometimes we need to log for a certain subset of methods and sometimes another, but in the same run of the same application.

From the AOP point of view, we need some sort of control over all of these aspects, and because of this many AOP implementations offer feature-rich languages with which express some or all of these semantics. Of course these implementations must offer some sort of processing of such constructs, such as compilers, precompilers, attribute processers and so on. This seems to me a little overkill, because it’s very difficult to provide a language that can cover all of the needs of heterogeneous applications, or attributes that can be customized in every direction. Lastly, I’ve read a lot of documents in which is stated that is an advantage to be able to group an aspect in a single code point (typically a class), but noone points out that even aspects could need to be architectured: for example, I could want to log method invocations of a class in a manner, and others in others, or even log to a file until a certain condition is met, and from there on throwing exceptions.

I find difficult, in theory and in reality, to be able to create a complex architecture that can react to all of this, without even considering the time that programmers have to spend to learn and practice with such an architecture: remember, we all have deadlines!

When facing the problem of the design, I always start with a simple concept: I think that the best tool with which to model any behaviour is code. Simple as that! This is true for who provide a service AND for who uses that service. Any other kind of solution has the risk (not the certainty, but the risk) of limiting the possibile uses and variants of that service.

Having said all of this, that in some way explains my approach, my goal is to provide a very simple base service, written in a manner that can be immediately comprehensible and above all totally customizable. At the same time, I don’t want to fill original classes with any sort of code, apart from the derivation from the base class, as seen.

The controller

Central to my vision is the controller: simply stated, this is a class that implements the message processing representing method invocations. Its form is very understandable:

    public class AOPBaseController
    {
        public virtual void Begin(object o, IMessage msg) {}
        
        public virtual void End(object o, IMessage msg) {}
        
        public virtual IMessage SyncProcessMessage(object o, 
             IMessageSink sink, IMessage msg)
        {
            Begin(o, msg);
            IMethodReturnMessage returnedMessage = 
(IMethodReturnMessage)sink.SyncProcessMessage(msg);
            if (returnedMessage.Exception != null)
                End(o, msg);
            return returnedMessage;
        }
    }
    

As we can see from the code, it has a virtual function that processes messages in a standard form: before and after the original method invocation it offers the chance to intercept such events (by calling two other, void, virtual functions). Any of these functions is virtual. Maybe usually you will want to implement in a derived class only the Begin() and End() functions, or maybe you want to reimplement the whole interceptions totally, depending on your needs (maybe because you want to handle some sort of return type in the Begin() and End() functions).

As usual, I pay a lot of attention to not being obstrusive at all: any service offered can be tailored or even substituted at pleasure. We also need a way to associate a controller to a class: the simple solution could be the classical attribute, but I’ve already said that I consider it a simplified solution. What if I want to exploit different interception control in two different runs of the application? We need to separate even this service, and I provide another very simple class just for this.

    public class AOPConfig
    {
        // <Type, AOPControllerInfo>
        private static Hashtable associations = new Hashtable();

        public static bool Enabled = true;

        public static void SetAssoc(Type classtype,
             Type controllertype, IMessageMatcher matcher)
        {
            ConstructorInfo ci = controllertype.GetConstructor(Type.EmptyTypes);
            AOPBaseController controller = (AOPBaseController)ci.Invoke(null);
            associations[classtype] = new AOPControllerInfo(controller, matcher);
        }

        public static AOPControllerInfo GetAssoc(Type classtype)
        {
            return (AOPControllerInfo)associations[classtype];
        }
    }

(I do not delve now with the AOPControllerInfo class, the IMessageMatcher interface and the exception handling)

With these static functions we are free to read the associations from an XML file, or asking them to another service, or even, like we do in the sample code, set them in code at the start of the application.

    AOPConfig.SetAssoc(typeof(TestClass), typeof(TestClassController), null);

With these base classes, it’s very easy to write a simple controller:

    public class TestClassController : AOPBaseController
    {
        private void Output(string s)
        {
            //Console.WriteLine(s);
            MessageBox.Show(s);
        }

        public override void Begin(object o, IMessage msg) { Output("Begin"); }
        public override void End(object o, IMessage msg) { Output("End"); }
    }

This sample doesn’t redefine SyncProcessMessage, but intercepts every call to the underlying class to provide pre and post processing. You will notice that every function receives as parameters an object and a message: you can correctly imagine that the first is the underlying object and the second the message representing the method invocation. In the first draft I tried to translate the message in a more readable structure, but in the end I left it untouched: it’ll be enough to read the documentation to understand what you can find in it. The important thing is that in the controller we have all the possible information about the current method invocation, that let us be able to customize totally the behaviour of the interception itself.

Sink revisited

Passing the underlying object around has requested some investigation, but it could be possible with a little variant of the custom sink, that is:

    public class AOPSink : IMessageSink
    {
        private IMessageSink m_NextSink;
        private ObjRef realobject = null;

        public AOPSink(IMessageSink nextSink)
        {this.m_NextSink = nextSink;}

        public IMessageSink NextSink {get {return m_NextSink;}}

        public IMessage SyncProcessMessage(IMessage msg)
        {
    IMethodMessage methodMessage = (IMethodMessage)msg;

            if (methodMessage.MethodName == ".ctor")
            {
                IMethodReturnMessage ret = 
(IMethodReturnMessage)m_NextSink.SyncProcessMessage(msg);
                realobject = (ObjRef)ret.ReturnValue;
                return ret;
            }
            else
            {
                AOPBaseClass obj = 
     (AOPBaseClass)RemotingServices.Unmarshal(realobject);
                return obj.SyncProcessMessage(m_NextSink, msg);
            }
        }

        public IMessageCtrl AsyncProcessMessage(IMessage msg, 
               IMessageSink replySink)
        {
            throw new NotSupportedException();
        }
    }
    

In the message processing we have to intercept the constructor invocation, and save for future use in the sink itself the reference to the just constructed object. See ‘Limits’ below for (evident) limitations of this solution. From now on, every time the sink intercepts an invocation it passes this reference down the chain. This also implies that for each underlying object there are a different attribute, a different property and a different sink. I consider the situation at this point another ‘good’ solution: from now on the programmer is free to create his/her own solution, building on these base classes and redefining every aspect of the provided services.

Message Filtering

We can provide another base service that’s common to AOP implementations: the chance to select which method invocation to filter. This can be done in many ways, even if our test code consider only a pattern matching on the method name. What is important, as always, is to clearly separate this further aspect and to provide the chance to modify dynamically the filtering. I created a simple interface that doesn’t need to be explained:

    public interface IMessageMatcher
    {
        bool IsMatch(IMessage msg);
    }
    

An object implementing this interface can be registered with the controller, and at runtime every intercepted message, apart from the constructor, will be matched against this function in the AOPBaseClass. This is the example matcher in the code:

    public class RegExMethNameMatcher : IMessageMatcher
    {
        private Regex r = null;

        public RegExMethNameMatcher() : this("") {}
        public RegExMethNameMatcher(string filter)
        {r = new Regex(filter);}

        public bool IsMatch(IMessage msg)
        {
            if (msg is IMethodMessage)
                return r.IsMatch(MethodMessageUtil.GetMethodName(
                         (IMethodMessage)msg));
            return false;
        }
    }

I've put this class in the base library because is of common use: it's very typical to filter methods by their name. A regular expression is used to control if the current method invocation is to be filtered in or out. If you build it with an empty string it will always return true.

Again, feel free to let run your fantasy, imagining for example that you can implement a matcher that can react dynamically to external conditions to filter different kind of functions (for example, only properties or only methods). Of course this is a false filter, in the sense that the sink will in every case intercept all method invocations, but this can be very useful to make code more readable, relieving pre and post processing code from looking for the right methods to process.

Minimalia

There are other little details I didn’t explain until now. For example, AOPConfig offers a simple boolean (Enabled) that you can use to block the interception service. Again, this is a false blocking because I tried to give the application the original performance, but it looks impossible from code. Moreover, the sink is able to react even to asynchronous method invocations, but this is beyond the scope of this article. To conclude, I added a class obtained from the source code already credited [4] that provides an utility to obtain useful information from the message, MethodMessageUtil. For the rest, browse and debug at least once the code line by line and you will understand better than words how all of this behaves. If you have any kind of problems, feel free to ask me: I don’t know if I’ll be able to answer, but I promise I’ll try!

Sample code

I wrote and actually use a version of this code in C# 2.0 Beta, so using generics and other new characteristic of the language. I rewrote it in C# 1.X (I hope not too simplified!) version so that more users can run and quickly understand it. There is no error and exception handling, only code core. The only point that needed to be considered, and it is in the sample code, is that the underlying method invocation can raise an exception. The base controller version of the interception framework can see it, and in the sample code simply doesn’t call the End() processing. In real world applications, you will want to design a reasonable handling code for this case.

Limits

I'm not trying to fool you: this is not the perfect solution. It may have some good points, but also bad points. A real AOP library is still by far a solution much much better than mine, no point on this. Here the bad part goes:

- Performance. In the end, my tests show that in typical scenarios you can lose at worst 0,030 microseconds for each intercepted call (if you use a typical nowadays PC). I don't take into account what I do in the interception code: this cost is only for the infrastructure, and you spend it for each method invocation in an intercepted class, even if you don't do anything or filter out the call. It means also that you need some 33,000 calls to lose one whole second. If it's too much for you, only you know. There is a little trick to commute an application between intercepted mode and non intercepted: adding an intermediate class in the chain from your classes to AOPBaseClass.

    public class AOPCommutingClass : AOPBaseClass
    {
    }
 

If you derive all of your classes from this one, it'll be enough to comment out the derivation here to have a 'normal' program again (only a bit cluttered by the AOP classes you don't use anymore).

  • Memory. Sincerely, I don't bother for this problem anymore, but you have to know that ContextBoundObjects consume memory; the property, the sink, and so on, each one consumes memory.
  • Capabilities. While it can be reasonable enough that you are not able to intercept static functions, maybe you didn't notice you can't intercept constructors, or better, you have to change my design. But usually this shouldn't be a problem, because your application objects (natural candidates for interception) should be instantiated by some class factory with some method (that can be intercepted): try to think about this...

References

[1] - Aspect Oriented Programming / Aspect Oriented Software Design – Marc Clifton (http://www.codeproject.com/gen/design/aop.asp)

[2] - Ted Neward's Personal Weblog (http://www.neward.net/ted/weblog/index.jsp?date=20030107)

[3] – Many argue, and with a lot of good reasons, against the use of ContextBoundObject as a base for AOP. Google for contextboundobject aop to see why.

[4] – Build an AOP.NET Extensible Business Component using ContextBoundModel (http://www.codeproject.com/dotnet/ContextBoundModel.asp)

[5] – Decouple Components by Injecting Custom Services into Your Object's Interception Chain (http://msdn.microsoft.com/msdnmag/issues/03/03/ContextsinNET/default.aspx)

[6] – Aspect-Oriented Programming Enables Better Code Encapsulation and Reuse (http://msdn.microsoft.com/msdnmag/issues/02/03/AOP)

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here

About the Author

Andrea Bioli
Web Developer
Italy Italy
Member
Frog Software srl is an Italy based training and consulting company, specialized in .NET technologies. It's available in-house and in-place all over southern Europe.
Andrea Bioli is the founder, and has more than ten years of experience in C/C++ design and programming on large projects.
Since .NET launch, Frog Software has focused exclusively on this technology.
http://www.frogsoftware.it (in italian)

Sign Up to vote   Poor Excellent
Add a reason or comment to your vote: x
Votes of 3 or less require a comment

Comments and Discussions

 
You must Sign In to use this message board.
Search this forum  
    Spacing  Noise  Layout  Per page   
QuestionCalls from one method to another is not getting interceptedmemberjoygk23 Aug '11 - 21:06 
My scenario is like below.The Test1 is getting intercepted properly.But not the Test2(). It intercepts if we call Test2() independently. Can you please suggest me how to log the method calls with in method?
 
public void Test1()
{
    Output("Test1");
    Test2();
}
Thanks in advance.
Joymon
GeneralSystem.Runtime.Remoting.RemotingExceptionmemberHaroldBalta11 May '10 - 6:33 
Hi there,
 
must say very good work. But i encountered a problem: I receive after some time of running my app with AOP an Exception:
 
A first chance exception of type 'System.Runtime.Remoting.RemotingException' occurred in mscorlib.dll
 
Additional information: Object '/9314f842_f3e9_4522_aeda_7ab675ea5118/3xx5csbzg_kszcgywata69rs_314.rem' has been disconnected or does not exist at the server.
 
Here is the exception stack:
 
Server stack trace:
at System.Runtime.Remoting.Channels.ChannelServices.CheckDisconnectedOrCreateWellKnownObject(IMessage msg)
at System.Runtime.Remoting.Channels.ChannelServices.SyncDispatchMessage(IMessage msg)
 
Exception rethrown at [0]:
at System.Threading.Thread.InternalCrossContextCallback(Context ctx, IntPtr ctxID, Int32 appDomainID, InternalCrossContextDelegate ftnToCall, Object[] args)
at System.Threading.Thread.InternalCrossContextCallback(Context ctx, InternalCrossContextDelegate ftnToCall, Object[] args)
at System.Runtime.Remoting.Channels.CrossContextChannel.SyncProcessMessage(IMessage reqMsg)
 
Exception rethrown at [1]:
at System.Runtime.Remoting.Proxies.RealProxy.HandleReturnMessage(IMessage reqMsg, IMessage retMsg)
at System.Runtime.Remoting.Proxies.RealProxy.PrivateInvoke(MessageData& msgData, Int32 type)
at TestLibrary.CompositionTest.ExecuteTest()
at WhitboxTestWizard.RunningTestThread.Run() in [...]RunningTestThread.cs:line 84
 
Greetings,
 
Christoph Moissl
GeneralVery nicemembermikeperetz5 Sep '09 - 7:18 
Nice work.
 
"There are only 10 types of people in the world: Those who understand binary, and those who don't"
More articles on my blog

GeneralGood Job !membergpgemini4 Jul '09 - 4:21 
And thank you for the simple running sample code.
Too bad Generics are not supported.
 
Anyone knows a solution with similar simplicity that supports Generics ?
Questionhow to intercept recursive calls?memberSaeed Alg28 Apr '08 - 4:35 
I have an interceptor and i want intercept recursive calls (wich are will be happend in the same object) what should i do?
any help!
 
Saeed Amiri

QuestionCalling a method from within a AOPBaseControllermemberKevin Kinnett31 Jul '07 - 7:17 
If you call a method from inside a class that inherits from AOPBaseController, SyncProcessMessage is never called?
 
I am trying to use this mechanism state verification of the pre and post state of a method, which would be equally as true when a method is called from both inside and outside the class.
 
Any ideas? By the way, i really liked the article, i think it gives a great intro in the way ContextBoundObject works.
QuestionContextBoundObject with Generics Throws Exceptionmemberivantorresjmz30 Aug '06 - 17:00 
Hi,
 
I have a ContexBoundObject with generics that implements some tracing aspect, but when I use some of this objects on Windows Forms it throws the following exception: Generic-ContexBoundObjects not supported on the Initialize method of the Form. ????
 
HELP!
 
Greetings,
Ivan
AnswerRe: ContextBoundObject with Generics Throws ExceptionmemberMohammad Reza Jooyandeh2 Feb '08 - 23:21 
The problem you have, has no relation with windows forms, all in all contexboundobject does not support in current frameworks. you should solve your problem in another way.
Generalaborting method executionmembercre_Active26 Feb '06 - 2:34 
Hi,
Great article.
I have implemented (before a finding your article) a somewhat less flexible aop solution for my application which has only one aspect whose scope is to validate a method call against a license manager class my app uses. The application has several 'plugins' all in the same assembly and users can purchase any combination of licenses to activate the desired functionality.
 
So i have the plumbing all in place and am intercepting the methods decorated with my attributes but here is my problem:
 
If it turns out a user does not have a valid license for a specific feature i need to abort the method from executing , but i cannot find any way to do so from within my custom sink short of throwing an exception.
 
It becomes even uglier because to catch that exception i have to either surround the original method call with a try catch block (which removes any benefit of using aop here in the first place) or rely on the Application.ThreadException last chance handler to handle the exception which is a very ugly solution at best.
 
Do you have any insight into the matter?
GeneralNot in the webmemberIsta2 Dec '05 - 6:04 
Every ntice it doesn't work in ASP.NET
 
Anyone know why?
 
I'm not an expert yet, but I play one at work. Yeah and here too.
GeneralAccess to calling objectmemberDewyDewhirst24 Aug '05 - 13:00 
Hi, thanks for all the code samples.
 
I am trying to understand AOP and see if I can make use of it, which I am sure I can, in my project.
 
In the pre-processing and post-processing (Begin/End) functions, is there anyway to get access to the orginal object? As in the object that the method was called from? And can properties and methods be safely changed on this??
 
Thanks
Dewy
GeneralRe: Access to calling objectmemberandreabioli28 Aug '05 - 4:24 
Of course yes! Smile | :) Look (and step into) the code, you will see that Begin/End functions ALREADY contain a parameter (the first) that represents the current object the function is called into.
Apart from this, what happens if you call whatever function on that object is that you start another (recursive) call interception on the same object: maybe this is just what you want, maybe not... Smile | :)
Andrea Bioli
QuestionRe: Access to calling objectmemberSaeed Alg28 Apr '08 - 4:18 
how can I intercept recursive calls???
 
Saeed Amiri

GeneralStrange, I have quite differnet performance test resultssussAlexander Pinsker22 Aug '05 - 0:15 
Thanks for the interesting article.

Recently I did a test of how interception affects performance of the code and got quite a different results (slowdown by ~ 1000 times and about 20 microseconds per intercepted call). The difference is that I defined a full chain of context attribute, context property and a message sink (all of a no-op style) rather than just derived tested class from CBO.


Here my timing results & code.
 
Thanks,
Alexander Pinsker
GeneralRe: Strange, I have quite differnet performance test resultsmemberandreabioli28 Aug '05 - 4:17 
Hi Alexander,
I don't have now the time to compare the codes and test the performance, but yes, you do a lot more than me, so it's normal that your code performs worse than mine (and we could open a philosophic discussion on the two approaches... Smile | :) ).
At the same time, your timings are A LOT worse than mine: I would never expect them... When I have some spare time I will do a sharp comparison, and will post the results. Thanks for your work!
Andrea Bioli
GeneralCastle.DynamicProxysussS3an7 Apr '05 - 4:58 
To get around some of the drawbacks of the "ContextBoundObject" AOP approach, take a look at DynamicProxy at http:\\www.castleproject.org
GeneralVery interestingmemberNemanja Trifunovic30 Sep '04 - 5:15 
5 from me.
 
However, I must add that I believe the best way to add AOP support to an OOP language is to extend it to support AOP directly. Good examples for this are AspectJ[^] and AspectC++[^] (our fellow CP-an Daniel Lohmann seems to be an active developer of this one).
 


My programming blahblahblah blog. If you ever find anything useful here, please let me know to remove it.
GeneralRe: Very interestingmemberAndrea Bioli30 Sep '04 - 5:34 
Sure! I hope to have pointed out that I'm not talking about 'real' AOP. Consider this a funny game, but a game from which it's possible to get some good idea...
 
------------
Andrea Bioli
Frog Software srl
http://www.frogsoftware.it (in italian)
GeneralRe: Very interestingsussAnonymous7 Mar '05 - 13:31 
first enema

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

Permalink | Advertise | Privacy | Mobile
Web04 | 2.6.130516.1 | Last Updated 30 Sep 2004
Article Copyright 2004 by Andrea Bioli
Everything else Copyright © CodeProject, 1999-2013
Terms of Use
Layout: fixed | fluid