I’m working on some personal .NET Core projects and I faced some strange errors. Ok, I’m too fresh on .NET Core and I expected this. What I was not expecting is to find problems with .NET Core folder structure no one would be able to correctly identify and in the end discover what I imagine is a huge amount of developers making some small mistakes when developing with .NET Core.
The common errors
While developing my project I discovered some error messages with very wrong recommendations on the web and probably many people are following these wrong guidance.
These are the common errors:
- When building the entire solution, we will receive error messages complaining about duplicated assembly properties.
If we look for this error in google, we found something between 600K and 37M results depending what property you look for. Most of the results have absolutely the same solution: Disable the assemblyInfo generation in the CSPROJ file.
What if I want to generate an assembly info file with properties for each assembly, how to solve that? Something is not right.
- A very similar problem will happen with the target framework property and again google will tell us to disable the generation of the target framework property
- If the most internal projects in the solution use some packages, the project in the root will need to have the same packages installed. Could you notice the code smell of this situation?
The Critical Discovery
There is a critical discovery on this blog. I could say I would bet I’m right about this. Every developer who ever disabled assembly info or target framework generation and every developer who ever included a reference in a project which doesn’t need it just because the build is complaining is developing wrong with .NET Core.
In Summary, every developer who followed the recommendations of one of the 600K pages about this problem is developing wrong with .NET Core.
The solution that you will find spread on the internet is to add the code below to your CSPROJ files. I would like to know: Have you been mislead by these wrong recommendations on the web? Please, comment on this blog telling us your history.
My recommendation is to use the code above as a code smell.
Solution Structure difference
.NET and .NET Core organize projects and solutions in a slightly different way, specially if you are using a tool such as Visual Studio Code.
Using Visual Studio our work starts with a solution and we can add in the solution the projects we would like to achieve our result.
One first question Visual Studio asks us is if we would like to create a different folder for the solution or not. In the past creating the solution folder was optional, nowadays it’s the default.
By default the solution will have its own folder and all the projects will be folders inside the solution folder. I always recommended this option to the students.
However, if you choose to not create this folder, leaving the solution in the same folder as the project, .NET will create the solution file together the first project of the solution and this doesn’t create any kind of problem to us, besides not be perfectly organized.
However, using Visual Studio Code and .NET Core you need to be a bit more careful. The main difference is the project files, CSPROJ, don’t contain reference to each file of the project. The folder is the project and this opens a huge space for many mistakes, at least in my opinion.
Let’s imagine HOW NOT TO CREATE A SOLUTION and the consequences this can bring to us.
Starting the Creation
You have a GitHub folder in your hard drive where you store all your local repositories. You open Visual Studio Code and use the terminal to navigate to this folder. Once in the folder, you create a project using the following statement:
dotnet new Console -n MyNewProject
VS Code will create a folder called MyNewProject directly inside your GitHub folder and this will become the root of your repository.
I will not get into details about how you will add this project to GitHub, it’s not really important at this moment.
Growing the project
While we develop and evolve the project, we will need to create additional project and transform what was a single project in a solution.
All additional projects will be on its own folder under the root. However, the first project and the solution will end up in the root.
Some details will trick us in not seeing any problem to this:
- Our old .NET knowledge will look to this scenario as perfectly usual. Not very well organized, but usual.
- Dot net core will allow us to create references between the projects, including the project in the root and the projects in sub folders. VS Code will not block us to create these references and the projects most of the times will build without any problem.
The problems start to appear
The problems I mentioned before, build errors due to duplicated assembly attributes and missing references will start to appear once the project grows.
The Root Cause of the Problem
The CSPROJ files in .NET Core don’t include references to each file of the project, like the old CSPROJ files were used to. So, what is include in the project?
Simple: Everything in the folder is part of the project. All the files in the folder will be compiled as part of the project. However, not only the files, but also the folders. The project in the root folder contains all the code in the root folder and in the sub-folders, all in a single project.
This explains the errors we get:
Duplicated assembly attribute: Yes, it’s duplicated, because the compilation of the projects inside the folders create an AssemblyInfo.CS file, but when we compile the project in the root folder, it finds one assemblyinfo in each folder and will complain about the duplication.
Packages and References needed in the root project: Once again, it has a simple reason. When we compile the root project all the code files in the sub folders are included, but the project files in the sub folders are ignored. Due to that, the root project needs to have a reference to all libraries and packages used in the entire solution.
We need to plan our .NET Core solution folder structure since the beginning. If you are building a solution with multiple projects, your root folder can, at most, contain the solution and each project needs to be contained in its own folder.