Thursday, March 20, 2008

LinFu.DynamicModel, MxClone, and the Art of Adaptive Object Models

I've done it! :) Both the LinFu.DynamicModel and the MxClone (the MyXaml Engine Clone) libraries are ready for production use, and I can't wait to get started on writing the CP articles for both libraries.

A Tale of Two Approaches

As I mentioned in previous posts, LinFu.DynamicModel allows you to dynamically create an entire object model in memory at runtime without having to recompile your application. With LinFu.DynamicModel, you can either construct the model directly through code, or you can use the MxClone to create the model for you, using XML markup. I'll briefly go over each approach in the following sections, but before I do that, let's take a look at the interface implementation that we're going to dynamically generate:

A Canonical Approach: The Person Interface

Let's suppose that I wanted to dynamically create a dynamic type that looks like the following interface:

public interface IPerson
{
int Age { get; set; }
string Name { get; set; }
}

Using LinFu.DynamicModel in Your Code

Here's how you can dynamically create a type that implements the IPerson interface:

// TypeSpec objects are type descriptions that can be modified at runtime
TypeSpec personSpec = new TypeSpec()
{
Name="PersonType",

// Notice the strongly-typed properties
Properties =
{
new Property<int>("Age"),
new Property<string>("Name")
},
};

// This will return true
bool isPerson = personSpec.LooksLike<IPerson>();
var person = personSpec.CreateDuck<IPerson>();

// Use the person object just like any other POCO
person.Age = 18;
person.Name = "Me";
// ...


Thanks to C#'s 3.0 new language features, you can easily create a model in memory with LinFu in relatively few lines of code. What makes this particularly interesting, however, is the fact that as the given TypeSpec changes, all of the IPerson instances that rely on that TypeSpec automatically "change" their behavior to match the newly-modified Person TypeSpec.

Using LinFu.DynamicModel with MxClone

Needless to say, there's a myriad of things you can do with this sort of technology, but it gets better--you can describe the same model through XML, using a MyXaml-style syntax:

<?xml version="1.0" encoding="utf-8"?>
<Root xmlns="LinFu.Reflection.Extensions, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null"
xmlns:def="Definition" xmlns:set="Setters">
<TypeSpec def:Name="PersonType" Name="PersonType">
<Properties>
<PropertySpec PropertyName="Name"
PropertyType="System.String">
<set:Behavior>
<PropertyBag/>
</set:Behavior>
</PropertySpec>
<PropertySpec PropertyName="Age"
PropertyType="System.Int32">
<set:Behavior>
<PropertyBag/>
</set:Behavior>
</PropertySpec>

</Properties>
</TypeSpec>

</Root>


As you can see, the XML syntax for MxClone is similar to MyXaml, with the exception of the set:Behavior element. MxClone allows you to assign object references to properties without having to give it a specific reference name (e.g., {SomeName}), and in this case, the set:Behavior element means that I'm assigning an object reference of type 'PropertyBag' to a property named "Behavior" on the PropertySpec type. (The PropertyBag class, in turn, is responsible for maintaining the state of each property on every given type instance--but for now, I'll save that for the upcoming LinFu article on CP)

In essence, MxClone is actually constructing the same TypeSpec in memory using XML markup. Having the model specified in XML allows you to change it at runtime without recompiling the application, and that could come in handy if you need to change your business model with minimal downtime. Anyway, back to the markup...

From XML to TypeSpec, in 15 Lines of Code

Now that we have the XML markup, the next thing you might be wondering about is the client code: exactly how do you convert that markup into a running TypeSpec? Here's how you do it:


// Load the engine into the container
string directory = AppDomain.CurrentDomain.BaseDirectory;
SimpleContainer container = new SimpleContainer();
Loader loader = new Loader(container);
loader.LoadDirectory(directory, "*.dll");

IMxEngine engine = container.GetService();

// The instance holder will
// store the object graph once
// it's been instantiated by the engine
IInstanceHolder holder = new DefaultInstanceHolder();
string file = @"C:\YourDirectory\SimpleTypeSpecSample.xml";
engine.Execute(file, holder);

TypeSpec spec = holder.GetInstance("PersonType");
bool isPerson = spec.LooksLike();

// Use the person class normally
IPerson person = spec.CreateDuck();
person.Age = 18;
person.Name = "Me";


In the example above, I used the Simple.IOC container to instantiate the MxClone Engine. The engine, in turn, converted the XML markup into a working Person TypeSpec, and lastly, I used that same TypeSpec instance to create the IPerson instance. It's just that simple. :)

Conclusion

As you can see, there's quite a bit of development going on with LinFu.DynamicModel and LinFu.MxClone, and like everything else in the LinFu project, it will all remain under the LGPL license. I've put my heart and soul into this project, and hopefully, everyone will see that once the next set of LinFu articles comes out on CP. Stay tuned!

Monday, March 17, 2008

Using Selective Method Weaving for LinFu.AOP

A while back, someone asked me if there was a way to make LinFu.AOP weave only certain types of methods and properties, and at the time, LinFu.AOP wasn't capable of doing that--that is, until now.

Here's how you do it. All you need to do is provide your own custom implementation of an interface named IMethodFilter and put that implementation in the same directory as LinFu.Aop.Weavers.Cecil.dll, and you're good to go. Here's a simple example:

[Implements(typeof(IMethodFilter), LifecycleType.OncePerRequest)]
public class MySampleCustomFilter : IMethodFilter
{
public bool ShouldWeave(MethodDefinition method)
{
// Intercept only public methods
return method.IsPublic;
}

}

All you have to do is put that in a separate DLL and make sure that the assembly is located in the same directory as LinFu.Aop.Weavers.dll, and you can customize it to your heart's content. It's just that simple. Enjoy!

Thursday, March 13, 2008

A Peek at LinFu.DynamicObject

Although it's been quite a while since my last post, LinFu has been coming along quite nicely with some recent additions. In the past month, I've managed to create two new things for LinFu:

  • A Dynamic Typing System for LinFu.DynamicObject, and
  • A MyXaml clone that will deserialize the DynamicModel from disk and load it into memory.


The Current State of Affairs

In LinFu's current state, you can only dynamically add properties and methods to DynamicObjects on a per-instance basis. Currently, there's no way to create a prototype for an entire set of DynamicObject instances and have all of those instances share the same conceptual prototype. For example, suppose that I wanted to create a Person type that looks something like this:

public interface IPerson
{
string Name { get; set; }
int Age { get; set; }
}

In order to have a set of dynamic objects emulate a IPerson instance, I would have to manually generate a Name and an Age property on each dynamic object that I needed to use. While such a scenario might be acceptable if I only needed to use a few DynamicObjects, the story starts to become quite different if that small few suddenly becomes a few hundred thousand. Suffice to say, there's quite a cost in having to set up a couple hundred thousand dynamic objects in memory at runtime. There must be a better way to do this, and thus, LinFu.DynamicModel was born.

Build Your Own Model, All at Runtime

LinFu.DynamicModel allows you to create an in-memory type specification (or prototype) of what you want your DynamicObjects to look like. You can add or remove methods and properties to this specification at runtime, all without having to create a single DynamicObject. Any DynamicObject that is attached to that type specification will effectively have all the properties and methods of that spec. The best part about all this is that all changes you make to a spec at runtime will be reflected in every single DynamicObject that uses that type specification.

For example, let's suppose that I wanted to create an implementation of the IPerson interface and have two DynamicObjects share the same conceptual Person type. Here's how it would look like:

DynamicObject firstPerson = new DynamicObject();
DynamicObject secondPerson = new DynamicObject();

// Both of these LooksLike() calls will return false
// since IPerson has yet to be implemented
Console.WriteLine("Object #1: IsPerson? {0}", firstPerson.LooksLike());
Console.WriteLine("Object #2: IsPerson? {0}", secondPerson.LooksLike());

// Create a person type with only the Name property implemented
TypeSpec personSpec = new TypeSpec();
personSpec.AddProperty("Name", typeof(string));


DynamicType personType = new DynamicType(personSpec);

// Make both DynamicObjects act like the person type
firstPerson += personType;
secondPerson += personType;

// Note: This still will return false since we haven't implemented the Age property
Console.WriteLine("Object #1: IsPerson? {0}", firstPerson.LooksLike());
Console.WriteLine("Object #2: IsPerson? {0}", secondPerson.LooksLike());

// Finally, implement the age property so that both types look like an IPerson
personSpec.AddProperty("Age", typeof(int));


// Note: Both DynamicObject instance calls to LooksLike() will now return true
// since the type they refer to now implements IPerson
Console.WriteLine("Object #1: IsPerson? {0}", firstPerson.LooksLike());
Console.WriteLine("Object #2: IsPerson? {0}", secondPerson.LooksLike());

// Use both instances normally as IPerson instances...
IPerson first = firstPerson.CreateDuck();
IPerson second = secondPerson.CreateDuck();

// ...

As you probably noticed from the example above, the only thing I needed to do was modify the TypeSpec instance and both DynamicObjects automatically changed their behavior to match the given TypeSpec. In theory, this will allow you to effectively generate an entire object model in memory without having to recompile the application. In fact, the only thing you would need at this point is a reliable way to deserialize the object model from disk. At first, using the .NET BCL's serialization mechanisms might be the easiest way to do this, but LinFu.DynamicModel's metamodel heavily relies on interfaces to provide each method and property implementation, and those interfaces cannot be serialized to disk by the classes in the System.Runtime.Serialization namespace.

Legally Infeasible

Now, since MyXaml is very good at instantiating object graphs, and LinFu's DynamicModel is nothing but a metamodel object graph, the next logical step would be to use MyXaml, but there's just one problem--MyXaml is licensed under the GPL, not the LGPL, which means that MyXaml can't be used in commercial applications unless you obtain a commercial license from Marc Clifton, or you publish the source code to your own commercial applications. Since I'm committed to making all of LinFu available under the LGPL, I had no choice but to write my own MyXaml engine from scratch, and hopefully, I can cover that in my next blog post. For now, all I can say about my unnamed MyXaml clone is that it's some of the best code that I've ever written, and this one is definitely worth the wait.

In the meantime, this should whet our appetite for what's to come in LinFu, and the future looks bright indeed.

Stay tuned!

Ratings by outbrain