We are building a project containing of several MicroServices from scratch and thought of how to organize it.
For each microservice we set up an own repository. Which results in the following repo structure:
- Global (for shared componenents)
- Documentation (where wiki markdown files and images are stored)
The documentation is done in the azure devops wiki. Files created and images uploaded are stored automatically in the
global repository is the repo where we implement componenents which are used by all MicroServices.
For each MicroService there is an own repository. All MicroServices have the same project structure, because they are created from an custom Visual Studio Project Template.
- Service.Client (for calling this microservice)
Builds and Packages
For every repository we have a build pipeline which builds the solution and runs the UnitTests. The pipeline creates package(s), too.
The global repository has build pipeline, too. Packages from global repository are:
- Global.Entities (shared entities)
- Global.Client.System (Base classes for Service.Client project)
Then the pipeline creates 2 nuget packages,
Service.Client. Those will be published to the azure devops nuget feed.
Using the packages
We thought about how to use packages in development and on devops build.
We wanted to make sure, that you can work an your MicroService without bothering with code from for example the global packages. But still have the possibility to develop directly on the global projects directly in the MicroService solution.
How we did this?
To accomplish this we added the
global repository as a submodule to the MicroService repository.
We have two solutions, one which uses the packages and one which can switch between packages and directly building against the
global projects via the submodule.
Solution with global Submodule
As I described above we have a solution for working with the
global code and building directly against it. This is done by adding a new
build configuration to the
Here is an example of the project xml with:
<ItemGroup Condition="'$(Configuration)' == 'Debug_Global'"> <ProjectReference Include="..\..\Global_System\src\Service.Entities\Service.Entities.csproj" /> <ProjectReference Include="..\..\Global_System\src\Service.Services.System\Service.Services.System.csproj" /> <ProjectReference Include="..\..\Global_System\src\Service.Client.System\Service.Client.System.csproj" /> </ItemGroup> <ItemGroup Condition="'$(Configuration)' != 'Debug_Global'"> <PackageReference Include="Service.Entities" Version="1.0.*" /> <PackageReference Include="Service.Services.System" Version="1.0.*" /> <PackageReference Include="Service.Client.System" Version="1.0.*" /> </ItemGroup>
You can see the switch between project reference and nuget package. If you are using the normal solution, there is no such build cfg and the
Global_System projects aren't in the solution at all.
WithGlobal solution has the
Global_System projects referenced and has the related build config. You can easily switch between the build/debug with the packages or the projects.
Hint: Maybe you recognized the
* in the version number. This has the benefit, that the project uses the newest package. You don't need to update the packages every time a new package was build.
The things described above makes working with packages easy possible. The benefit here is, you can directly work with the
global projects. For example editing files, debugging and so on. Edited files can be checked in to the submodule, which then directly triggers an azure devops pipeline and creates a new package.