How To Structure Your Epi-Server Project
Sun 26 April, 2015 / By Jon D Jones
At the beginning of every project you need to decide how you will structure your files. If you use the Alloy sample site, all the code is provided to you in the web solution. For smaller sites there is nothing really wrong with this approach. There are a few downsides though, first by having your code in one or more separate class libraries you can get better code re-use. If you ever have a requirement to build a second website you can use that code elsewhere. I also think separating out your project makes your unit tests a bit easier to manage. I would normally have one unit test project per class library.
So if we are not going to stick everything into the web project, what are we going to do?
The Core Class Library Approach
In the Core library approach, you create a class library called Project.Core and you move all your non configuration code into it. Think all your Domain and Model logic goes into this Core project. Some of the folders I would expect to see in Core would be Enums, Blocks, Page Type, Helpers, Validators, Extensions, Repositories, Entities, Config and attributes.
This pattern is great for small one off projects. When I use this pattern, I will still leave things like the initialisation modules, structure map dependencies, route definitions etc.. within the web project. MVC specific configuration code should live in the web project, your Epi Server specific code should live in the Core library.
The Domain/Model/Shared Interface Approach
In this pattern we use three class libraries to store our code.
First, we have a Models project, in this project we store things like, Pages, Blocks, Entities, View Models etc..
Second, we have a domain library, in here we have non-project specific code like, Attributes, Dependency Resolvers, Extensions, Guards, Helpers, Renderings, Resources.
Lastly, we have a third class library, the interface library. This library is needed due to the separation of the projects. For example, you might need a class in Domain that needs something from your Models library. Adding this reference would create a cyclic dependency. In case you've never come across the problem, this is where one project relied on another project in order to build, but that project has a reference to the first project so the compiler would get in an infinite loop. By creating interface and putting them in this shared library it breaks the cyclic chain.
You may ask why split up your project into an additional two libraries when it creates this extra overhead? First, if you have more than one website to build you end up with a Domain class library that does not contain any project specific entities. This means you can share your domains project between one or more projects. This can save you a lot of time in your future projects as you don't have to copy these files into each project, or worse, have pages and models from one website appear in a different project where they do not belong.
The second benefit of having three libraries is that it forces the developer to write more flexible code. If you have everything in one project you can reference things easily. With two projects, Visual Studio forces you to write to an interface to make the project flexible, as you have no choice, you end up with slightly more flexible code.
In this approach Models references Interface and Domain, Interface references Models and Domains and Domain references nothing.
A word of caution using this approach, that sometimes you may have to slightly compromise a bit on where you want to put things and you may end up with a file you'd like to put in Domain that has to live in Models, due to attributes etc.. one example is selection factories normally have to end up living in Models.
My personal preference on larger projects is the Models/Domain approach but I have used the Core library a lot over the years. If you have more than one website to build, the Models/Domain approach will mean easier shared core between projects and less unit tests to write, but, you may have to compromise on the outcode of a few files.
What are you thoughts on this, how do you structure your project and which way do you prefer to implement your projects structure?