ActionContainer is an implementation of the Service Agent pattern in written in C#. It takes advantage of the C# 4.0 dynamic feature to eliminate cluttering your code with empty message classes and also manipulate calls at runtime.
Usage of ActionContainer is straight forward. Start by creating a class that
implements the empty IActionProvider
interface with public methods.
Inject an instance of the ServiceAgent class, and make calls to the registered methods
through the ServiceAgent
object.
Calling SayHello
with a string, will look up a registered method with the name
SayHello, takes a string argument, and has a void return type. Same behavior
goes for GeneratePassword
, except it returns a string.
Looking up methods by name and parameters doesn’t require creating a class (think SayHelloRequest) for each registered action.
The ServiceAgent is also return type aware. In the call string password =
ServiceAgent.GeneratePassword();
, a search is done for the GeneratePassword
that returns string. In this case, the SimpleProvider
has the only registered
GeneratePassword. Lets say we added another provider, the NumericProvider
as
follows:
Now calls to ServiceAgent.GeneratePassword();
can handle both int and string
return types with no special PasswordResponse or NumericPasswordResponse
wrapper classes.
The default method lookup ability of ActionContainer is just that: the default.
ActionContainer provides a hook into its resolving process simply by creating
implementations of the IActionListener
interface.
The CanHandle
method returns true if it has an opinion on the return value
of a call. If CanHandle
is true, Handle
allows the object to manipulate the
return value a value.
ActionCallInfo
includes the method name, named parameters, unnamed
parameters, and expected return type.
Using this information you could add helpful hooks such as a LogListener
.
The LogListener
will watch for an argument named log with the value of
true. It will then write to the console the name of the call, return type, and
arguments. To put it to use, just use the ServiceAgent as follows:
Because the ServiceAgent is a dynamic object, any number of named arguments can be passed to its method calls.
Another possible hook would be a StringTrimListener
. Any arguments that are strings
can be trimmed before getting passed to the handling method.
No change in code is needed to have calls to the ServiceAgent start using the
StringTrimListener
. Just make a call on something with a string with hanging
spaces.
ActionContainer has some requirements that you must keep in mind while using it. Most deal with determining types.
First, when doing variable assignment you must explicitly provide the type when
returning values. Using var
will result in unfriendly behavior.
Second, passing null values as parameters limits lookup. This has to do with null not carrying any type information other than object.
Finally, ActionContainer is slow (~10x) compared to direct method calls. Using it in a long running loop will have noticeable performance hits. However, in response to user actions, incoming web request, etc, the difference is negligible.
It’s on Github. Go and grab it with Git.
$ git clone git://github.com/statianzo/ActionContainer.git
13 Aug 2010