T4 Code Generator Extensibility

In my previous post, I covered the overall structure of the T4 Code Generator and how it can be used instead of the default code generator. Here I will cover how you can customize it.

The T4 Code Generator is intended to be extensible.  You should be able to derive from it and tweak the code generation to modify the generated code as required. For that, the generator has the following extensibility points:

1.

Each of the 5 code generators (CSharpDomainContextGenerator, CSharpEntityGenerator, CSharpComplexObjectGenerator, CSharpEnumGenerator and CSharpWebContextGenerator) contain a number of protected virtual methods. Each of these methods roughly map to the corresponding part of generated code. To modify the code for a particular component, you can derive from that particular code generator and override the method for the part for which you want to modify the generated code.

For example, consider the CSharpDomainContextGenerator that generates DomainContext code in C# given a DomainServiceDescription. It contains the following protected virtual methods:

protected virtual void GenerateAttributes(IEnumerable<Attribute> attributes);
protected virtual void GenerateBody();
protected virtual void GenerateClassDeclaration();
protected virtual void GenerateConstructors();
protected virtual void GenerateCustomMethods();
protected virtual void GenerateDomainOperationEntry(DomainOperationEntry domainMethod);
protected virtual void GenerateEntityContainer();
protected virtual void GenerateEntitySet(Type entityType);
protected virtual void GenerateEntitySets();
protected virtual void GenerateExtensibilityMethods();
protected virtual void GenerateInvokeOperations();
protected virtual void GenerateQueryMethod(DomainOperationEntry domainOperationEntry);
protected virtual void GenerateQueryMethods();

Now, if you want to modify the code generated for the DomainContext constructors, you would declare a type that derives from the CSharpDomainContextGenerator and override the GenerateConstructors() method. Note that if you want to add code before or after the code generated by the base method, you can follow the following pattern (which is pretty convenient in quite a few cases):

class MyDomainContextGenerator : CSharpDomainContextGenerator
{
protected override void GenerateConstructors()
{
//Add code before

base.GenerateConstructors();

//Add code after
}
}

Of course, you can completely change the generate code by not calling into the base class implementation, if that suits your needs.

Each of the above virtual methods generate code as indicated by their names. All the other code generators also have such virtual methods that can be overridden in a similar fashion. I won’t go into the details of each one of those here.
The GenerateBody() method is special (it exists on all the code generators). This method generates the entire body of the class by calling into other protected virtual methods above. If you want to add additional code to the class, you will override this method, call base.GenerateBody() and then add any additional code that you might want to generate.
Note: This method does not include the class declaration (it does not call the ClassDeclaration() method).
2.

The ClientCodeGenerator class (which is the base class for CSharpClientCodeGenerator) contains protected abstract properties for the 5 code generators.

protected abstract ComplexObjectGenerator ComplexObjectGenerator { get; }
protected abstract DomainContextGenerator DomainContextGenerator { get; }
protected abstract EntityGenerator EntityGenerator { get; }
protected abstract EnumGenerator EnumGenerator { get; }
protected abstract WebContextGenerator WebContextGenerator { get; }

The CSharpClientCodeGenerator populates them with the default implementations of the code generators above. To make the code generator use your custom generator for any of the above generators, define a type that derives from CSharpClientCodeGenerator and override the property for the generator you want to substitute with your own. This now becomes your custom T4 Code Generator. So the WCF RIA Services code generation process will use this type to do all code generation. For that you will have to add the attribute [DomainServiceClientCodeGenerator] on the type you define. For example, to use the custom DomainContextGenerator from the above example, you will define a type as follows:

[DomainServiceClientCodeGenerator(“MyCustomGenerator”, “C#”)]
class MyCSharpClientCodeGenerator : CSharpClientCodeGenerator
{
protected override DomainContextGenerator DomainContextGenerator
{
get
{
return new MyDomainContextGenerator();
}
}
}

Now this is your T4 Code Generator. Then when you add a reference to your assembly (containing these types) on the server and a <RiaClientCodeGeneratorName>property indicating the assembly name to the Silverlight project file, you will get your custom code generated on the client.

For a complete walkthrough of the T4 Code Generation customization process (along with ways to work around the bugs in it), please refer to a great post by Jeff here.

About these ads

About varunpuranik
I am a Developer at Microsoft. I work in the App Server Group on WCF RIA Services.

One Response to T4 Code Generator Extensibility

  1. Pingback: T4 Code Generator Dec ‘10 Update « varunpuranik

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

Follow

Get every new post delivered to your Inbox.

%d bloggers like this: