Some of our controllers are currently redundant so I changed the base class' constructor to make sure no-one called them accidentally...
public abstract class MyRedundantBaseClass { public MyRedundantBaseClass() { throw new NotImplementedException(); } }
Now, none of my tests go anywhere near this class (or any inherited ones) so why was it throwing the exceptions?
The problem is in one of the auto-generated classes in the T4MVC.cs file. The template generates a static field for each non-abstract controllers in your application...
public static class MVC { public static MyApp.Controllers.Account.AccountController Account = new MyApp.Controllers.Account.T4MVC_AccountController(); // Repeated for each controller... }
This list of fields also included a number that extended my redundant class. So, as soon as I did anything with the T4MVC framework all these classes got automatically instantiated and now I'm dead in the water.
My solution is to edit the template so that it generates a Lazy Loading version of the T4MVC.cs file. This also makes it a little more efficient as it will only new-up classes when it needs them.
Here's the old template section (starting from line 73)...
<#foreach (var controller in DefaultArea.GetControllers()) { #> public static <#=controller.FullClassName #> <#=controller.Name #> = new <#=controller.FullDerivedClassName #>(); <#} #>
... and here's what I changed it to...
<#foreach (var controller in DefaultArea.GetControllers()) { #> private static <#=controller.FullClassName #> _<#=controller.Name #>; <#} #> <#foreach (var controller in DefaultArea.GetControllers()) { #> public static <#=controller.FullClassName #> <#=controller.Name #> { get { if (_<#=controller.Name #> == null) _<#=controller.Name #> = new <#=controller.FullDerivedClassName #>(); return _<#=controller.Name #>; } } <#} #>
This now generates the following code in T4MVC.cs...
public static class MVC { private static MyApp.Controllers.Account.AccountController _Account; public static MyApp.Controllers.Account.AccountController Account { get { if (_Account == null) _Account = new MyApp.Controllers.Account.T4MVC_AccountController(); return _Account; } } // Repeated for each controller... }
I still need to add a double locking mechanism for thread safety, but I think this makes a valuable improvement to an already great framework.
Good idea, let's get this change in. Let's discuss by email offline. Thanks!
ReplyDelete