A pattern for modifying method behavior by an unknown party
I’m currently doing some experimental work towards what i’m tentatively calling DReAM 3.0. I’ve got some ideas for additions and changes and welcome any and all feedback. A primary focus for this release is to make Dream more approachable and easier to use. Mind you, this is speculative work and nothing on that page nor mentioned in this post is set in stone yet.
Last night I was dealing with splitting up some DReAM functionality into client and server assemblies and running into a consistent pattern where certain classes have augmented behavior when running in the server context instead of the client context. Since the client assembly is used by the server assembly, and these classes are part of the client assembly, they do not even know about the concept of the server context. Which leads me to the dilemma, how do I inject different behavior into these classes when they run under the server context?
I originally posted this on my personal blog as a late night rambling about a solution I came up with, but wasn’t particularly enamored with, hoping to see if there was an obvious pattern or facility I was overlooking. Since then @jongalloway suggested on twitter that I look into using MEF. Since DReAM already does assembly discovery in a number of places, I’ve been meaning to look at MEF to replace that hand-rolled reflection code. So this might be the final nudge.
This is one way to do it…
Let’s assume that the server context can be discovered by static means (i.e. a static singleton accessor) which also lives in the server assembly. To let this context inject its behavior, I’ve extracted the affected behavior into an interface and use discovery to build a chain of implementations to handle the behavior. A sample interface might look like this:
public interface IFooHandler {
ushort Priority { get; }
bool TryFoo(string input, out string output);
}
TryFoo gives the handler implementation a chance to look at the inputs and decide whether to handle or pass on it. The handler chain is used with this linq expression:
public string Foo(string input) {
string output = null;
_handlers.Where(x => x.TryFoo(input, out output)).First();
return output;
}
This assumes that _handlers is sorted by priority. The method returns the result of the first handler to report true on invocation. Building up the _handlers happens in the static constructor:
static Bar() {
_handlers = typeof(IFooHandler)
.DiscoverImplementors()
.Instantiate()
.Cast<IFooHandler>()
.OrderBy(x => x.Priority)
.ToArray();
}
where DiscoverImplementors and Instantiate are extension methods i’ll leave as an exercise to the reader.
Now the server assembly simply creates its implementation of IFooHandler, gives it a higher priority and on invocation checks its static accessor to see if it’s running in the server context and if not, lets the chain fall through to the next (likely the default) implementation.
Looking for alternatives
I’m about to do a deep dive into MEF to see how it can help. Whether it’ll just take over the discovery of handlers for the chain or has a way to better deal with the injection of the behavior as well, I don’t know yet. I’m of course open to other solutions as well.