GitXplorerGitXplorer
a

modulith

public
128 stars
12 forks
20 issues

Commits

List of commits on branch main.
Unverified
853cfbe884d13d4e67dd6e78db675b58229e26b1

Adding MediatR to Contracts project. #61

llloydkevin committed 4 months ago
Unverified
0bda8cc8383e0be44ffdfbccbb5742d576925240

FastEndpoint version upgrade. Also adding FastEndpoints.Testing and FluentAssertions to test project. Fixes #58

llloydkevin committed 4 months ago
Unverified
6d60236850a6ea8e7f2de16f441bde885da68975

Adding reference to Web in Test projects for creating endpoint migrations.

llloydkevin committed 4 months ago
Unverified
47e5720b8ba79faadd9325e000c5e5c5e3089077

Exclude EF Core Migrations from tests. Fixes #60

llloydkevin committed 4 months ago
Unverified
e00c40385130ff3bac30ccc59554ad9b2b37011b

Shouldn't display an error if assembly cannot be registered.

llloydkevin committed 4 months ago
Verified
cff5ff783a458d61227ff69de51f7564ec39cc9b

add config to registrar (#57)

aardalis committed 4 months ago

README

The README file for this repository.

Ardalis.Modulith

CI NuGet Version

  • ⚠️This project is a work in progress and will likely receive many API changes before v2.0.0. Please keep this in mind when using, as there will be breaking changes often.

  • ⚠️ Automatic project references for new modules are only supported in .Net SDK 9.0.100-preview.7.* and newer. Please make a manual project reference when using earlier versions.

πŸ†• Try UI Module generation with Blazor. Jump to Modules with UI

(originally hosted at david-acm/modulith - thanks David for the contribution!)

Modulith is a dotnet new template suite for Modular Monoliths. It streamlines the creation of new .Net solutions and the addition of modules to existing ones.

But, what is a Modular Monolith? Glad you asked. It is a software architecture style to build maintainable applications as a single unit, but in nicely separated modules (Modu-lith, pun intended πŸ™ƒ). More about Modular Monoliths.

πŸš€ Quickstart

Install the tool running:

dotnet new install Ardalis.Modulith

Create a new solution:

dotnet new modulith -n eShop --with-module Payments 

eShop is your solution name, and Payments is the first module name (defaults to FirstModule if not specified).

Create a new module

cd eShop
dotnet new modulith --add basic-module --with-name Shipments --to eShop

⚠️ cd into the solution folder to add the module inside the solution.

Shipments is the name of your new module. This will create a new module folder with the same three projects as in Payments/.

Add a reference to the new module

Run:

dotnet add eShop.Web/eShop.Web.csproj reference Shipments/eShop.Shipments/eShop.Shipments.csproj

That's it, no need to register the new service -- but you can. The template scans you assemblies and registers services from your modules.

Happy coding!

Running the solution should show both modules with their default endpoint:

Direct service registration

However, if you prefer more control and less magic, or you want to modify registration class, you can remove the builder.DiscoverAndRegisterModules(); in program.cs and add the service registration for each module:

using eShop.Shipments
...
PaymentsModuleServiceRegistrar.ConfigureServices(builder);

πŸ›οΈ Solution directory structure

The previous command creates the following project structure:

  • eShop
    • Users/ πŸ‘ˆ Your first module
    • eShop.Web/ πŸ‘ˆ Your entry point

Inside Payments, the second module added, you will find the project folders:

  • eShop.Payments/ πŸ‘ˆ Your project code goes here
  • eShop.Payments.Contracts/ πŸ‘ˆ Public contracts other modules can depend on
  • eShop.Payments.Tests/ πŸ‘ˆ Your module tests

Project dependencies

Since this is a Modular Monolith, there are a few rules that are enforced to guarantee the modularity:

  • Every type in eShop.Payments/ is internal
  • This is enforced by an ArchUnit test in eShop.Payments.Tests/
  • The only exception to the last two rules is the static class that configures the services for the module: PaymentsModuleServiceRegistrar.cs
  • .Contracts/ and .Tests/ projects depend on eShop.Payments/. The opposite is not possible. This is by design.

* You can always change these rules after you have created the solution to suit your needs. But be mindful of why you are changing the rules. For example, it is ok to add an additional public extensions class to configure the application pipeline, while adding a public contract to eShop.Payments/ is not. We have a project for those.

Adding a reference automatically to new modules

This is only supported on .Net 9 preview 6. If you are running an earlier version you will need to run these commands manually.

⚠️ cd into the solution folder. I.e. eShop/, then run:

dotnet new modulith-proj --ModuleName Shipments --existingProject eShop.Web/eShop.Web.csproj

Here Shipments is the name of your new module, and eShop.Web/eShop.Web.csproj is the path to your web entry project. If you change this, make sure you update it to the new path and that is relative to the solution folder.

Modules with UI

You can generate a solution with a Blazor UI by using the --WithUi:

dotnet new modulith -n eShop --with-module Payments --WithUi

Running the application will show the following blazor app:

Screenshot of Blazor app with Payments module

The app uses MudBlazor as the component library. The template includes a menu item and page for the newly created module with UI whose components are defined in the eShop.Payments.UI project. We include a link to the Swagger UI page in the API menu item.

The previous command will create a solution with a few additional projects.

  • eShop.UI: Is the client project that will be compiled to WebAssembly and executed from the browser. This contains the layout and routes components; but most importantly the program.cs to register the services for the client side application.
  • eShop.Payments.UI: Is a razor class library where you can define the components specific to that UI module.
  • eShop.Payments.HttpModels Contains the DTOs used to send requests from the Blazor client project (eShop.UI) to the WebApi endpoints in eShop.Shipments.

Adding new modules with UI

New modules with UI can be added running:

cd eShop
dotnet new modulith --add basic-module --with-name Shipments --to eShop --WithUi

⚠️ New modules with UI can only be added to solutions that were instantiated using the -WithUI parameter.

However, to allow routing to the newly created module component for the Shipments module, you need to register the new assembly.

In blazor WebAssembly, the routeable components that are not present in the executing assembly need to be passed as arguments to the Router component. In this template, this is done using the BlazorAssemblyDiscoveryService. Simply add the following to the GetAssemblies array:

typeof(ShipmentsComponent).Assembly

After the modification the class should look like this:

public class BlazorAssemblyDiscoveryService : IBlazorAssemblyDiscoveryService
{
  public IEnumerable<Assembly> GetAssemblies() => [typeof(PaymentsComponent).Assembly, typeof(ShipmentsComponent).Assembly];
}

For each additional module you create you will need to add a new assembly to this array.

More about this in Blazor's documentation page: Lazy Load Assemblies with WebAssembly

πŸ“Š About Modular Monoliths

A Modular Monolithic app benefits from the simple deployment of a monolith and the separation of concerns that microservices offer. While avoiding the complexities and maintainability issues they can introduce. When you are ready and if you need it, you can split a module as a microservice. Best of both worlds 🌎

This is not a new concept. Martin Fowler explains it here, and Ardalis teaches it here.

The templates in this project follow the solution structure as taught by Ardalis in his course Modular Monoliths in DotNet.

πŸ›ƒ Custom templates

No template fits all needs. If you want to customize the template you can clone this repository as a template.

Once you have cloned the repo locally you can make your custom changes in the working/content directory. This directory contains the project templates used for every instatiation. Then you can install the template locally running:

⚠️ Make sure to uninstall the original template

dotnet new install .

You can find more information about building dotnet new templates, including how to add commands and parameters, at Microsoft docs page: Custom templates for dotnet new

πŸ—‘οΈ Uninstall Modulith

dotnet new uninstall Ardalis.Modulith