[Please see the WebActivator wiki for the latest docs]
Now suppose you install a few more packages that use the same WebActivator pattern, and you would end up with something like that at the root of your project:
AppStart_SparkWebMvc.cs AppStart_SQLCEEntityFramework.cs AppStart_BarPackage.cs AppStart_BlahPackage.cs Global.asax Global.asax.cs Web.config More files...
That starts getting really ugly, and most devs like to keep the root of their app free of clutter.
We need a better convention!
The solution is simply to agree on a different convention where we put all this startup code into a folder. To match ASP.NET conventions, the obvious name to pick is App_Start. And once we do that, we no longer need to prefix the file names with AppStart, so we would have:
App_Start SparkWebMvc.cs SQLCEEntityFramework.cs BarPackage.cs BlahPackage.cs Global.asax Global.asax.cs Web.config More files...
Likewise, the full class names would change from WebApplication1.AppStart_SQLCEEntityFramework to WebApplication1.App_Start.SQLCEEntityFramework. Note that the namespace doesn’t matter a whole lot since you won’t call this code explicitly. But since existing convention is to have the namespace match the folder structure, we may as well do that here.
As of today, there are 17 packages that use WebActivator, so I’ll need to try to convince all the authors to follow this. Fun time ahead! :)
But note that it’s just a convention, with no code changes to enforce it. Nothing written here breaks any existing packages. It’s just something where by agreeing on a better convention, we make NuGet yet a little bit better!
An example: EFCodeFirst.SqlServerCompact
As an example, here is what I ended up with for the EFCodeFirst.SqlServerCompact package using this pattern.
The source file transform in the package is in Content\App_Start\SQLCEEntityFramework.cs.pp, and contains:
// namespaces, etc... [assembly: WebActivator.PreApplicationStartMethod( typeof($rootnamespace$.App_Start.SQLCEEntityFramework), "Start")] namespace $rootnamespace$.App_Start { public static class SQLCEEntityFramework { //etc...Note the use of $rootnamespace$ and of App_Start in the namespace.
I like it. How about taking it a step further and making the method name conventional and you could get rid of the attribute for classes in the App_Start folder.
ReplyDelete@joshf: I was kind of thinking about that, but my concern is that it could effect startup times, as we would need to look at all the methods in all classes in all assemblies for methods matching the pattern. With the attribute, we get to do a very quick assembly level check.
ReplyDelete@david - even if you don't lose the attribute, having the convention as @joshf proposes would help with readability... thus the methods might be:
ReplyDelete* PreStart
* PostStart
* Shutdown
@James: Problem is that we don’t know what’s in App_Start at runtime. All we have is a set of assemblies in bin, with no trace of what sources they came from. So I like the idea, but the implementation is tricky :)
ReplyDeleteHi David,
ReplyDeleteEither I've missed something, or you've got the wrong end of what I was trying to say...
If the guidance is to use a convention of PreStart or PostStart for the method name, then this will be more readable to the end user.
It would still necessitate the attribute, but might make the experience nicer for the consumer!
Cheers,
James
@James: Ah sorry, didn't read your comment carefully. I suppose what we could do is have the method name be optional, and default to those names. This way we don't break existing code that use it.
ReplyDeleteThis comment has been removed by the author.
ReplyDeleteHi David,
ReplyDeleteWould it be detrimental to place classes in the app_start folder in the namespace Company.Website.AppStart to follow the PascalCode naming convention as suggested by Microsoft, even though the folder name is App_Start?