KallDrexx KallDrexx - 16 days ago 8
C# Question

How can I have T4 generate code based on classes in a specific namespace (Recursively)

My architecture's service layer is made up of many single purpose command classes (classes that perform one specific function on data, such as creating a user) and query classes (individual classes that query the database for specific data). These get injected into my Asp.net MVC controller classes via Windsor installers.

For example, I run

container.Register(Component.For<CreateUserCommand>().ImplementedBy<CreateUserCommand>());
in my custom
IWindsorInstaller
class to instantiate the
CreateUserCommand
in my controllers.

The problem is that since each command/query class is single purpose, I will end up with a lot of these classes, and maintaining my installer class is going to be a pain in the butt. It occurred to me that this would be a perfect job for T4, as I can just run the T4 and have it regenerate the installer class to automatically register all of my command and query classes.

Unfortunately, since I have never done T4 before I don't know how to proceed to actually implement this. I have read the basics on T4, but my main point of confusion is how to actually find all of my command and query classes via T4.

On paper, I can find all my command/query classes because they are defined in the
MyApp.DomainModel.Commands.*
and
MyApp.DomainModel.Queries.*
namespaces. For example, the
CreateUserCommand
class resides in the
MyApp.DomainModel.Queries.Users
namespace. However, I have no idea how to go about actually looking through namespaces at runtime, let alone recursively.

It's possible for me to create a
ICommand
and
IQuery
interface for these classes to be based off of if that's easier to find in T4 than namespaces, but I don't know how I would find all
ICommand/IQuery
subclasses via T4.

I do know reflection, but from reading I have read a lot saying that using reflection in T4 is a bad idea and/or doesn't work properly.

If anyone could point me to anything that would help me accomplish this I would be greatly appreciative!

Answer

Using reflection from T4 is not inherently a bad thing, but regarding "not working properly", the primary problem is that you cannot reliably reflect that current assembly in which the T4 template is defined, as this has yet to be compiled. You generally need to split your project into different assemblies in order to access your own types from T4.

Finding all types in a namespace is not a difficult issue, particularly if they're all defined in the same assembly.

<#@ import namespace = "System.Reflection" #>
<# 
var path="D:\Path\To\MyApp.DomainModel.dll";
Assembly a = Assembly.ReflectionOnlyLoadFrom(path);
foreach (var type in a.GetTypes()) {
    if (type.Namespace == "MyApp.DomainModel.Commands") { #>
        <#=type.Name #>
<#  }
} 
#>