Sorry for spamming but I have had a few posts stuck in my head for a few weeks and I am sitting at my desk in a position I have resigned waiting out my time. Obviously I will not be receiving any new projects and all old projects are on wait of other resources = Bored Greg.
Continuing with the dynamic proxy I created a DSL for runtime based aspect assignment.
One thing that I did which was a bit different than anything I had seen done before was that I allowed attributes to map aspects.
In the assignment language you can say
Assign to Attribute
or
Assign to Method Level Attribute
or
Assign to Class Level Attribute
The first statement will assign an aspect to any method that has the attribute defined at either it's method level or at the class level that contains it.
The second statement will assign an aspect to any method that specifically declares the attributte at it's method level
The last statement will assign an aspect to any method that has the attribute declared at the class level.
One can also add an optional Having clause where you can access the public properties of the attribute
i.e. Having RoleType=“Admin“ and UseSecurity=true
This simply allows you to filter the assignment.
This addition was invaluable to my dynamic proxy and IMHO really helps bridge the gap between aspect based code and attribute based code. The gives me the big pro of having a simple code based declarative method of defining a behavior and at the same time it keeps me from having to pay the penalty of going through reflections (and a special handling object) in order to process the attributes.
There are some pitfalls to this methodology, one of the largest is that since the metadata is defined as an attribute a re-compile is required to change it. I am at this point leaving it to the developer to decide when it is good to use the attribute and when it is bad :)
What is really nice about this is it allows me to define “Types“ of join points via the use of attributes. In other words this allows me to group method types which are similar points to simplify my aspect assignment (1 line instead of hundreds or thousands). It also allows me to go and refactor those places that were using attribute based programming to use aspects instead quite easily :D
Anyone else have any thoughts on this?
Greg
In the creation of my dynamic proxy I ran into some “interesting” fringe conditions....
I started off as all do needing a very simple interceptor generator, this is btw very easily done if anyone is thinking about attempting it. I later decided to add mixin support which was a bit more interesting. That said lets get into some background information to help explain the issues.
Mixins for those who are not aware involves the dynamic aggregation (either at compile, link, or runtime) of multiple objects. When I first did mixins I only supported interface/implementor pairs (I'll explain why after the example). Here's a basic hand done example of what occurs when we are implementing an interface/implementor pair.
public class BasicClass {
public virtual int Method() {
Console.WriteLine("BasicClass:Method");
return -1;
}
public BasicClass() {}
}
public interface IBar {
void Go();
}
Our implementer
public class BarImplementer : IBar {
public void Go() {
Console.WriteLine(“BarImplementer::Go”);
}
}
and finally the aggregation class that would be generated to show the “mixin“ behavior
public class BasicClassWithIBarProxy : BasicClass, IBar //inherit from our subject and add interface {
private BasicClass m_Subject; //encapulate our subject
private BarImplementer m_Bar; //encapsulate our implementer
//override method and broker the call to our subject.
public override int Method() {
Console.WriteLine("BasicClassProxy:Method");
return m_Subject.Method();
}
public void Go() { //needed for IBar
m_Implementer.Go();
}
//allow our subject to be given to us upon construction
public BasicClassProxy(BasicClass _Subject, BarImplementer _BarImplementer) {
m_Subject = _Subject;
}
}
To make this generic one could say that my dynamic proxy generation went through the following steps
-
Iteratre through interface implementor pairs
-
Add interface to class declaration
-
add parameter to constructor
-
encapsulate the class
-
iterate through the methods of the interface adding method redirection to encapsulated implementor
-
iterate through each event creating a quick handler that bubbles the event
As one can see the generated class is simply a proxy of BasicClass that also aggregates IBar passing the method calls off to an implementor object who knows how to handle the calls received for IBar. You will notice that in this case I am not passing context, I did this for simplicity of the example the real server does pass context information to the implementor. This is a wonderful way of performing my aggregations but as I knew would happen I ran into a case where the code that I needed to aggregate was not mine nor did it support an interface. I at this point decided to support multiple base class base aggregation.
I am quite sure the astute reader just thought “wait this is a single inheritance based environment“. Well actually the very astute reader probably knows that there are numerous simulated multiple inheritance patterns available :) I chose to use David Esparza-Guerrero's pattern listed here http://www.codeproject.com/csharp/smip.asp to do my simulated multiple inheritance. To make a long read short (though I recommend reading it)... it uses implicit operations to allow for the simulation. Note that this aggregation based method only supports public contract MI not true MI within the object itself (although with a bit of hacking with reflections to avoid scope issues ... actually just no ... don't do that :))
Using such a methodology becomes a _bit_ more interesting as we are not assured to be successful every time! The major culprit here is public variables (the astute reader may also point out that non-virtual methods also are a problem). Public variables are a nightmare because there is no way of intercepting them to pass through the call to the subject object. While its quite easy to say “use properties“ it is more difficult in practice when you do not necesarily know what you will be operating nor will you control everything you operate on. Due to this I decided to take a best stab at it.
The first bit that I added was detection if the subject classes had public variables, this helped alot by throwing them out immediately I would allow the base (primary subject) to have public variables but not the mixins ...
And finally ...
We are to my fringe cases!
What if multiple classes have public variables?
Barf an error
What if the base class did NOT have public variables but one of the mixins did?
Well I supported it, my code at this point will actually change out the subject to be the mixin that has public variables and will treat the original class to be proxied as if _it_ were a mixin, externally the behaviors are the same.
What if the classes have non-virtual methods?
Well I just complain about it I still generate the class but I generate messages ...
I would love to hear some general thoughts from other people who have dealt with the same issue and their methods of handling this.
Cheers,
Greg
I few days ago I made a post about the possible coupling I saw within master pages as compared to a dynamic control based parent. This is due to the child defining the container where it resides on the parent. Perhaps I was not clear enough of about my thoughts so I am going to try to explain them a bit further.
Using any form of dynamic control placement (master pages or parent loading and placing dynamic controls) one uses metadata in order to figure out how to layout the screen, in other words there is metadata defining that in screen x there are 4 controls and where each of the 4 controls should be placed. This metadata is where the coupling enters into play with master pages.
Master pages take the metadata associating the control with it's parent and place it into the child, that is the metadata associating the control to its parent and the control are bound together. This can be seen in looking at any basic master page as the child defines the container within its parent where it should be placed.
In a more classic parent-> child relationship the metadata needed by the parent to determine control placement is not bound to the child. In this methodology the child and the metadata live independently of each other, you can freely change the metadata without touching the controls or the controls without touching the metadata.
While this offers some great functionality (like being able to change out the parent and metadata while leaving the children oblivious to the change) it also has some questions which should be looked at.
Is the relationship between an html control host parent and a html control a relationship that should be strongly coupled? What are the advantages/disadvantages to strongly coupling this relationship.
The main advantage that I see is the fact that the master pages are an intrinsically simpler solution that is available to everyone. I might even go so far as to say that the master page concept could pass the “mother test” that is I could explain the concept to her and as she nods her head like she usually does when I drop into techno babble, she could also easily grasp the concept and could probably write a web page that uses it with under a week of training (she has never written a line of code in her life).
Another advantage may lie in the coupling between the controls and their containers. This is one of those things where the contrasting it to dynamic control placement really depends upon your actual implementation of control placement. Many times we create controls which are of different types, an example of this can be seen in a side bar advertisement control. If the dynamic control placement based system that we are comparing master pages to does not support the distinction between various control types then this coupling can actually be seen as an advantage for the master pages methodology. This is because although there is a coupling between the parent and the child that coupling also very specifically defines the control as being of the right type to be placed within the parent container.
Now before you get too excited about this, this is also a disadvantage. Scratching your head yet? Since the master page is coupled directly to the container it can not possibly be ona more generic level than a container. Lets propose a layout where there are 2 containers of the same size with interchangable content. The content would not be interchangable even though in reality they are. There is no way for me to define a type of container which would allow me to define that certain types of controls (i.e. ones that support a 200px x 300 px display) are valid within certain types of containers (say those that are 200px by 300px). If you have created a dynamic control system for a large scale system (or many small scale systems as the code is 100% reusable) you have most likely supported this type of operation.
I don't want people to misunderstand me and believe my thoughts to be negative on master pages. My thoughts are that they are a wonderful addition in 2.0 and will help countless developers. This is definately a case where the 80/20 rule applies and this is a feature that is targetted at the 80. I would say that their methodology is extremely simple and understandable while providing a good method of supporting templating. I believe that master pages have met every design requirement that they had during development. My arguement is that the design requirements do not have enterprise development in mind, they are geared towards the 80% who were not even using dynamic control placement prior to 2.0 many of whom don't even use code behinds.
If you are reading this and you are on an enterprise class development team take a serious look at this coupling before placing any of these items into your system. Many would say that the “try it out” approach is better, I can't disagree strongly enough. The process of refactorring your code away from master pages back to the well known dynamic control placement methodology is a nightmare, you will most likely be faced with a choice of either
- Keep it the way it is, leave it as a bastard child
- Pretty much rework the entire front end of your app
We all know the problems with option 1. Option 2 isn't a whole lot better. Better to just stay away while you can :)
Cheers,
Greg