Have you seen code fragment like this? I mean there are lot of interfaces that provide stringly-typed access to some of the internals of the entity. This particular code fragment could be seen a lot in EPiServer Relate+ product code samples.
var instance = new SampleType();
instance.SetAttributeValue("ThisIsTheAttribute", value);
Accessing something that’s not pretty strong enough could be very easy and fast. Not a big deal – just type in attribute name and value.
Here goes why I don’t like interfaces like these:
- When you will margin for a grammar error when typing attribute name – that could be discovered only during runtime.
- You cannot use static code analysis tools. Like to search for all attribute usages.
- You cannot use some of the refactoring tools –> like rename attribute name.
- You can easily change type of the attribute and forget about code that uses that, effect –> runtime error.
- Use cannot leverage all the power of Visual Studio (for instance to provide Intellisense over available attributes)
So as we see – there a lot more troubles around stringly-typed interfaces than benefit you gain.
We are going to change this in this blog post.
First of all we would need to define client API – that’s how we are going to use our strongly-typed interface to talk to your stringly friend.
I would like to see following things in client API:
- There should be an object that would describe structure of the stringly-typed object. Like enumerating all the properties that we would like to have access to. I would call it – a metadata object.
- There should be an easy way to convert stringly-typed object into this metadata object.
- Metadata object will be used to talk to stringly-typed object via strongly-typed metadata object.
I would see client API and some code snippets as following:
var instance = new SampleType();
var metadata = instance.AsAttributeExtendable<SampleAttributeMetadata>();
metadata.SampleAttribute = value;
Metadata class could be described like this:
public class SampleAttributeMetadata
{
public object SampleAttribute { get; set; }
}
This metadata object is just an object that will provide us strongly-typed access later on.
First things first.
To convert stringly-typed object into some more meaningful instance we would need something “attachable” to original object. Extension methods will come to rescue today.
So we are able to write static method that will attach to original object and behave as instance method for that object. No matter which is your original object (for sake of integrity I’ll use EPiServer Relate+ ‘IAttributeExtendableEntity’ interface).
public static T AsAttributeExtendable<T>(this IAttributeExtendableEntity entity) where T : class, new()
This means that we are defining extension method for objects that implement ‘IAttributeExtendableEntity’ interface (those are almost all entities in EPiServer Relate+). This ‘IAttributeExtendableEntity’ interface provides stringly-typed access to attributes that you can set or get.
Generic type parameter T – that will be our metadata object class.
Next –> we need to somehow take a control over the metadata object that as given away to the caller of the extension method defined earlier.
For this reason one of the most easiest way to accomplish this is to use some sort of interceptor infrastructure. What interceptor does? Idea behind the interceptor is that client who got back the metadata object thinks (an result object really looks alike) that object that was given back is of defined metadata object type. And so do all code analysis tools (therefore Intellisense is available) and compiler as well.
Actually using interceptors we are giving back fake metadata object that has lot of injections in it in order to for us to gain control over the further client’s interaction with the object.
One of my favorite library to accomplish this is ‘Castle project’. Pretty easy to use and straightforward.
So what we need is to create a fake metadata object with our injections to control what’s going after we return the object. In order to get this done we need to define our interceptor and return a class proxy created using this interceptor.
So the code for AsAttributeExtendable() method is like this:
public static T AsAttributeExtendable<T>(this IAttributeExtendableEntity entity) where T : class, new()
{
if (entity == null)
{
throw new ArgumentNullException("entity");
}
var interceptor = new DefaultInterceptor<T>(entity);
var gen = new ProxyGenerator();
var options = new ProxyGenerationOptions(new ProxyGenerationHook());
var proxy = gen.CreateClassProxy<T>(options, interceptor);
return proxy;
}
UPDATE:
NB! Lessons learned! Actually it’s not quite a good idea to create proxy generator, generation hook and class proxy on each request. Just got through support ticket on memory leak and huge memory consumption. Which ended-up with lot of dynamically generated assemblies loaded into application domain and lot other stuff.
A better solution is reuse ‘ProxyGenerator’ class instance and cache generated class proxies for particular types.
First of all need to define static instance of the proxy generator class and store where cached class proxy instances will be stored.
private static readonly ProxyGenerator gen = new ProxyGenerator();
private static readonly ProxyGenerationOptions options = new ProxyGenerationOptions(new ProxyGenerationHook());
private static readonly ConditionalWeakTable<IAttributeExtendableEntity, object> table =
new ConditionalWeakTable<IAttributeExtendableEntity, object>();
Then we can implement updated method to generate class proxy for particular class of particular type:
public static T AsAttributeExtendable<T>(this IAttributeExtendableEntity entity) where T : class, new()
{
if (entity == null)
{
throw new ArgumentNullException("entity");
}
object classProxyCached;
// try to find already created class proxy from the cache
// this is required to increase speed a bit and not to create new class proxy for the same class more than once
table.TryGetValue(entity, out classProxyCached);
if (classProxyCached == null)
{
classProxyCached = GenerateClassProxy<T>(entity);
table.Add(entity, classProxyCached);
}
return classProxyCached as T;
}
And proxy generation method remains almost unchanged:
private static T GenerateClassProxy<T>(IAttributeExtendableEntity entity) where T : class, new()
{
var interceptor = new DefaultInterceptor<T>(entity);
var options = new ProxyGenerationOptions(new ProxyGenerationHook());
var proxy = gen.CreateClassProxy<T>(options, interceptor);
return proxy;
}
Let’s spilt them up into smaller pieces:
- DefaultInterceptor – this is the class that will contain the logic that will be called if client code will try to access something that we marked as interceptable in class ProxyGenerationHook class.
- ProxyGenerationHook – class that describes what is going to be intercepted and what should be passed to the underlying intercepted object.
Let’s look at hook class (it should implement ‘IProxyGenerationHook’ interface):
public class ProxyGenerationHook : IProxyGenerationHook
{
public void MethodsInspected()
{
}
public void NonProxyableMemberNotification(Type type, MemberInfo memberInfo)
{
throw new InvalidOperationException(string.Format("Property named '{0}' for type '{1}' is not marked as virtual.",
memberInfo.GetProperty().Name,
type));
}
public bool ShouldInterceptMethod(Type type, MethodInfo methodInfo)
{
// we are interested only in properties for now
return methodInfo.Name.StartsWith("get_", StringComparison.Ordinal)
|| methodInfo.Name.StartsWith("set_", StringComparison.Ordinal);
}
}
This hook is instructing Castle dynamic proxy generation engine that interceptor will intercept *only* properties (setters and getters). Btw, properties are compiled into methods anyway. This particular hook logic of course can be modified and adjusted to meet precise requirements.
Otherwise (method NonProxyableMemberNotification()) will be called if some of the metadata object members could not be intercepted. This is particular useful for error checking. NB! What Castle actually does is that behind the scene another object is created that *inherits* from our defined metadata object. Therefore members (in this case only properties) must be marked as virtual – because Castle tries to override those with its own logic. If that fails - NonProxyableMemberNotification() method is called.
Let’s look into DefaultInterceptor code (it must implement ‘IInterceptor’ interface):
public class DefaultInterceptor<T> : IInterceptor
{
public void Intercept(IInvocation invocation)
{
It only has single method – Intercept(). The most interesting part of interception is parameter – invocation, that gives us lot of info about method client code is calling.
Usually code within Intercept method starts with checking what kind of method client is calling, like:
if (invocation.Method.Name.StartsWith("get_", StringComparison.InvariantCultureIgnoreCase))
{
or
if (invocation.Method.Name.StartsWith("set_", StringComparison.InvariantCultureIgnoreCase))
{
Just to check either user is getting value from the property or setting value for the property.
Actual interception code really depends on situation and requirements but usually some of the properties of IInvocation class are used:
- invocation.Method – is the method that is going to be called.
- invocation.Arguments – is list of arguments passed the call of the method.
- invocation.ReturnValue – set the result of the interception.
Trick for interceptors – if you want to interrupt interception and return immediately to the caller – just return from the method. Otherwise you’ll need to call invocation.Proceed() method that will call next interception or ultimately will call target object’s method.
And within the interception code you can convert called method (getter or setter for properties) into call to stringly-typed object (Substring(4) will remove ‘get_’ or ‘set_’ from the name of the called method):
Entity.SetAttributeValue(invocation.Method.Name.Substring(4), invocation.Arguments[0]);
or for retrieving something and return that value to the caller’s code:
var methodInfo = Entity.GetType().GetMethod("GetAttributeValue");
var genericMethod = methodInfo.MakeGenericMethod(invocation.Method.ReturnType);
invocation.ReturnValue = genericMethod.Invoke(Entity, new object[] { invocation.Method.Name.Substring(4) });
Sequence diagram of final call stack could look something like this:

Sample project where Castle interceptors are used to provide strongly-typed access over EPiServer Relate+ entities can be found there.
Hope this helps!