Project structure with own Nuget packages

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:

  • MicroService1
  • MicroService2
  • MicroServiceN
  • Global (for shared componenents)
  • Documentation (where wiki markdown files and images are stored)

Repositories

Documentation

The documentation is done in the azure devops wiki. Files created and images uploaded are stored automatically in the Documentation repository.

Global

The global repository is the repo where we implement componenents which are used by all MicroServices.

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.Web
  • Service.Dal
  • Service.Entities
  • Service.Client (for calling this microservice)
  • Service.UnitTests
  • Service.IntegrationTests

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.

Global

The global repository has build pipeline, too. Packages from global repository are:

  • Global.Entities (shared entities)
  • Global.System
  • Global.Client.System (Base classes for Service.Client project)

MicroService

Then the pipeline creates 2 nuget packages, Service.Entities and 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 WithGlobal solution.

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.

The 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.

Recap

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.