I spent yesterday and today refactoring the code for the Controller Action/View map generator tool. I made some improvements, wrote some tests and I'm pleased to announce the first release. I saw Brian had implemented his as an MsBuild task and I liked that idea, so that's how ours runs now. First, things aren't as "drop in and go" as I would like because it's still evolving in and around our, already large, code base. It's my hope that over time the tool evolves as peoples needs change, etc... we can add some more configuration, that sort of thing. I'm more than willing to hear suggestions and such. Anway, here we go...
So in order to get yourself up and running, you'll need to do a few things. First, you'll need to add the task to your MsBuild. Simply open your csproj and add the following:
<UsingTask TaskName="Eleutian.Tools.CodeGenerator.MsBuild.GenerateMonoRailSiteTreeTask" AssemblyFile="Eleutian.Tools.CodeGenerator.dll" />
<ItemGroup>
<ViewSources Include="../YourViewsDirectory/**/*.brail">
<InProject>false</InProject>
</ViewSources>
</ItemGroup>
<ItemGroup>
<ControllerSources Include="Controllers/**/*.cs">
<InProject>false</InProject>
</ControllerSources>
</ItemGroup>
<Target Name="BeforeBuild" Inputs="@(Compile)" Outputs="$(ProjectDir)\SiteMap.generated.cs">
<GenerateMonoRailSiteTreeTask File="SiteMap.generated.cs" Namespace="YourNamespace.SiteMap" ControllerSources="@(ControllerSources)" ViewSources="@(ViewSources)">
</GenerateMonoRailSiteTreeTask>
</Target>
You'll notice a few things in here. ViewSources is just the collection of view files (be it .vm or .brail, etc..). It will use the paths of those files to add the View nodes into the map. ControllerSources is the C# source files for your controllers only, specifying this helps speed up parsing. I'll get to why in a bit. And for the Sources attribute on the task you should specify all the sources in the assembly, which @(Compile) works great for.
With the task added, you should be able to build and have a SiteMap.generated.cs file, now you'll need to tweak your "base" Controller class. If you're like us, you have a Controller class that you made yourself that all of your Controller's inherit from. In that class you'll need to add some code like the following:
private ICodeGeneratorServices _services;
public ICodeGeneratorServices CodeGeneratorServices
{
get { return _services; }
}
public RootAreaNode Site
{
get { return new RootAreaNode(this.ControllerServices); }
}
protected virtual void PerformGeneratedInitialize()
{
_services = new DefaultCodeGeneratorServices(
new DefaultControllerReferenceFactory(),
new AspDotNetRedirectService()
);
_services.Controller = this;
}
First is the member variable, _services. You can do this however you like, but it's consumed by the ControllerAction/ViewReference classes to do various likes. CodeGeneratorServices is a property the partial controller code uses to create the MyActions and MyViews node instances. Site is just an easy way to get the top, root level node. PerformGeneratorInitialize is overridden in the partial controller classes to add the MyViews and MyActions nodes to the PropertyBag so they are available in the views. So there you go. If I'm not missing anything, that should do the trick. Let me know if I did and I'll append to this post.
Oh, the reason for specifying the ControllerSources is to cut down on the number of classes/types we visit when generating the internal "tree" that the source code is generated from. At first glance it seems like you should just be able to parse the ControllerSources only. We coudln't really do that because we needed to gather information on the other types in the assembly so we'd be able to use them in the arguments of our actions, etc...
I have to stress that the code is relatively new, having undergone a major refactor to isolate it from the rest of our project. I make no promises that I won't have to upload a new copy, with a fix. :)
Source and Binaries