When you work on different projects and also sometimes you have to do an architecture, there comes a time when you realise that it would be great to create a solution template with your projects and dependencies.
You could read this post in Spanish here
More than once I wanted to create a template in visual studio that had the typical thing that you need to make a solution in three layers. The times I wanted to do I found a problem, the cost/benefit ratio. It's very costly to create a template for a solution - it's already difficult for a project template - utility time may be relatively small (think about the times they changed from Visual Studio 2012 to Visual Studio 2017 to just create a web project). Also, Visual Studio changes support for templates arbitrarily amongst versions. Then came out yeoman with their generators and I forgot a bit about this.
Dotnet CLI ... to the rescue
But seeing what could be done from the dotnet CLI command line, I took it back with new hopes. And I want to share my results.
First, my problem about cost benefit was solved in full. It took me 30 minutes to see it was doable and 3 hours until I had the script I will show you. And unlike a Visual Studio template, this also works for me on Mac and Linux.
The idea is to create the backend skeleton for a typical 3 layer architecture in .NET.
The requirements are:
- The solution must have the following projects:
- Web API
- Messages used in the web API signature
- Application layer,
- Business layer,
- Data layer,
- Entities,
- Testing projects.
- All projects must be linked to the solution.
- Each project will have references to the other projects it uses. In addition, when necessary they will have references that are in nuget.
- Also, I want you to have a directory structure that separates the test code from the application code.
- Another thing I have to add to projects is gitignore, so I will download it from the repository that is on GitHub where there are different gitignore dependent on the development tool you use.
- Restore references for all projects.
- I will compile the solution. Not just a project.
- Open the solution with Visual Studio Code.
The final idea is to open a bash and write "Bash createBackend3Layer.sh SolutionName".
What do you need to have installed?
- .Net Core
- The latest .net core SDK.
- If you have any problem, download the latest dotnet CLI build from the repository releases on GitHub.
Let's go for it !!
If you want to follow the article with the downloaded code, you have it in this GitHub repository.
Variable declaration
We take the name of the solution that was put as a parameter and we'll create the solution file inside a folder with the same name. If the solution is called "CodeCrafters", there will be "CodeCrafters / CodeCrafters.sln". Same as if you did with Visual Studio.
For each project, I'll use three variables for
- The project name
- The folder where the project will reside
- The path where the project file will reside
Remember that at this point I am already fulfilling the requirement of placing the code in one directory and tests in another. The code will reside in the src folder and the tests in the test folder
SolutionName=$1;
SolutionFile="$SolutionName/$SolutionName.sln";
gitIgnorePath="$SolutionName/.gitignore";
projExt=".csproj";
WebApiName="$SolutionName.WebApi";
WebApiPath=${SolutionName%%/}/src/$WebApiName;
WebApiProj=${WebApiPath%%/}/$WebApiName$projExt;
Creating the solution
We'll tell dotnet CLI to create a solution in a directory called the same as the solution.
Just a detail, to be able to differentiate the steps that will be executed from the script of the rest of values ??that will be written in the console I put the first ones of light green colour.
echo -e "\033[1;92m Create solution \033[0m"
dotnet new sln -n $SolutionName -o "$SolutionName"
Create the projects
In the GitHub script you have all the projects, but here I am giving an example of the three types of projects that are created.
As for directories, the idea is that the API Web Project is in "CodeCrafters / src / CodeCrafters.WebApi / CodeCrafters.WebApi.csproj"
In all of them, I am putting the same framework. In your 2.0 version, you can make the framework come as an optional parameter.😁
Class library projects can be projects that reference net Standard, and you can specify as a framework the netstandard from 1.0 to 1.6
dotnet new webapi -n $WebApiName -o "$WebApiPath" -f netcoreapp1.1
dotnet new classlib -n $AppLayerName -o "$AppLayerPath" -f netcoreapp1.1
dotnet new xunit -n $AppLayerTestName -o "$AppLayerTestPath" -f netcoreapp1.1
Use a gitignore
There is a repository in GitHub that has the different gitignore depending on the tools you use. With the following command line, you can download it from Github and save it in the root folder of the solution.
curl -o $gitIgnorePath 'https://raw.githubusercontent.com/github/gitignore/master/VisualStudio.gitignore'
This same mechanism can be used for other files in common use, such as a settings file of StyleCop.
Link the projects with the solution.
You can not leave projects as islands, they belong to a solution and you have to link them. In this line below you look for all the projects and execute the command that links them to the solution.
for refProj in `find $SolutionName -name '*.csproj'` ;
do dotnet sln $SolutionFile add $refProj ;
done
Note: This command can be used to execute all test projects. I invite you to make a script that compiles on your computer and run the tests. You already have 50%, you can not complain 😁
for unitTestProj in `find $SolutionName -name '*UnitTest.csproj'` ;
do dotnet test $unitTestProj ;
done
Cross-project references
To show that the WebApi project requires the Business Layer project you have to execute the following command
dotnet add $WebApiProj reference $BLayerProj
External References
You can download the external packages from a nuget server, but first look at which references each project brings by default.
For example, the API Web project already brings the MVC package.
dotnet add $DALayerProj package Microsoft.EntityFrameworkCore --package-directory $SolutionName/packages
If you are looking for packages that are not in nuget you must specify the URL with the -s parameter.
dotnet add $DALayerProj package Microsoft.EntityFrameworkCore -s https://dotnet.myget.org/F/dotnet-core/api/v3/index.json
With everything so far you would have enough, but let's continue to obtain the maximum grade. 👍
Restore packages
The nuget packages that you need were already downloaded in the previous step, but those that are predetermined in the projects, such as Microsoft.AspNetCore weren't. Let's download now.
for proj in `find $SolutionName -name '*.csproj'` ;
do dotnet restore $proj ;
done
Compile the solution
Here we build the solution, not just a project. When compiling it already detects the dependency between projects.
dotnet msbuild $SolutionFile
(Optional) Open solution in Visual Studio Code
If you have VSCode in your command path, loading the solution is very easy
code $SolutionName
(Recommended) Upload a first version to a local git
In Mac and Linux, git comes already integrated into bash, in windows you have to install it. The idea is that you can start a local repository of git and make the first commit with the solution as I left after running the whole script.
pushd $SolutionName
git init
git add --all && git commit -m "Code generate by @CodeCraftersEs"
popd
"But Daniel ... this last one was not among the requirements ..." Well, I always like to surprise my clients giving something more than they wait for. 😁
Conclusion
Three years ago I did an Angular demo and I used yeoman from the command line to create an MVC web solution. Some saw it as "a step back" because it should be all visual and integrated into Visual Studio.
I think dotnet CLI has opened a different door, one that .net programmers are not as used as node programmers with npm, and it is the use of command line. This is no longer a DevOps thing that makes a script in PowerShell to do something in Azure. Now we can create solutions, add projects, download references, and those commands that we already knew - like Add-migration and UpdateDatabase of Entity Framework - and join them in a single script.