ABP VNext switches from monolith to microservices

Note: The microservices here only consider the service part, not the internal and external gateways, authentication, etc.

ABP VNext switches from a single unit to a microservice, which provides considerable convenience. There is no need to make any adjustments to the internals of each module, just adjust the carrier.

ABP can help you in that point by offerring a microservice-compatible, strict module architecture where your module is splitted into multiple layers/projects and developed in its own VS solution completely isolated and independent from other modules. Such a developed module is a natural microservice yet it can be easily plugged-in a monolithic application.

Layered architecture

  1. The layering method provided by ABP VNext itself is as shown in the figure below. The core part is the Application, Domain and EntityFrameworkCore layers. As for HttpApi.Client and HttpApi, they all belong to the application to be carried on other systems.

  1. The Controller layer is weakened in ABP VNext. VNext provides dynamic Controller for Application, so you may be used to writing part of the logic in the controller will be a bit abrupt, but understanding is fine.

Planning hierarchy

  1. Create an empty folder and name it whatever you want (this time named GravelService) to store the overall project.

  2. Create a new blank solution in the empty folder in the previous step. You can use VS to generate it or follow dotnet commands.

  1. It is customary to create three folders according to the format of the microservice Demo given by ABP VNext, with clear thinking. Of course, the provided microservice Demo has more folders, but this time only focus on these three.

Add three modules

  1. Design three bounded contexts and draw context mapping. According to common orders, products and customers, it is divided into three bounded contexts. And plan the order as the upstream of the downstream dependent products and customers.

  1. Download the three modules directly from the official website, or generate them according to the command line (provided that the ABP CLI has been installed). Either way, make sure you are ready and save them in the modules folder according to the modularity concept.

  1. For example, three modules Product, Order and Customer are prepared this time. According to actual needs, you can streamline the internal files. Here, I only keep the src and test folders inside each module.

  1. For the inside of the src of the customer module, the specific generated folders are as follows. For the HttpApi, HttpApi.Client and MongoDB, I have eliminated this part (the same function in the later carrier).

After cleaning up, it becomes simple.

For the inside of the test, we also remove the unnecessary HttpApi.CLient and MongoDB folders (note: the unnecessary here is just for me, keep it if necessary).

After cleaning up, the hierarchy becomes simple.

  1. The sample cases given in each module are transformed into the beginning of each module name for easy distinction. Take the Customer module as an example, rename the built-in Sample case to Customer, and only make this change.

Mock service call

  1. For the Order and Product modules to add a downstream access to the upstream service link, it is convenient to verify that the underlying service does not need to be changed from the single to the microservice. There are two ways to learn about the invocation form of downstream access to upstream services.

  • The application layer of the current context directly depends on the application services of other contexts;

  • The current context sets up an anti-corrosion layer (adding a layer of isolation between bounded contexts to ensure that the isolation layer only needs to be changed when the dependent bounding context changes), and rely on or remotely call application services in other contexts in the implementation of the anti-corrosion layer;

  1. I personally tend to increase the anti-corrosion layer, although there is no relevant statement in VNext. For specific use, add an anti-corrosion layer interface in the domain layer or application layer, and implement the anti-corrosion layer in the EF Core layer. At this time, the EF Core layer should be renamed the infrastructure layer, not just in the form of a resource library .

  1. The ServiceClients folder is added to the Domain layer in Order to store the anti-corrosion layer interface, and the ServiceClients folder is added to the EntityFrameworkCore layer to store the anti-corrosion layer implementation.

  • Add IProductServiceClient to the anti-corrosion layer interface.

public interface IProductServiceClient : ITransientDependency
{
    Task<int> GetProductId();
}
  • Add ProductServiceClient to the implementation of the anti-corrosion layer.

  • The EntityFrameworkCore layer in the Order refers to the Application.Contracts layer in the Product module.

  • Depend on ProductAppService and complete the call.

public class ProductServiceClient : IProductServiceClient
{
    private readonly IProductAppService _productAppService;
    public ProductServiceClient(IProductAppService productAppService)
    {
        _productAppService = productAppService;
    }
    public async Task<int> GetProductId()
    {
        var productDto = await _productAppService.GetAsync();
        return productDto.Value;
    }
}
  • Rely on the anti-corrosion layer interface in OrderAppService and complete the call.

public class OrderAppService : OrderManagementAppService,   IOrderAppService
{
    private readonly IProductServiceClient _productServiceClient;
    public OrderAppService(IProductServiceClient productServiceClient)
    {
        _productServiceClient = productServiceClient;
    }
    public async Task<OrderDto> GetAsync()
    {
        var productId = await _productServiceClient.GetProductId();
        ...
    }
}
  1. In this way, the application service of the Product context can be used in the implementation of the anti-corrosion layer. Whether the request for this application service is in the current process or between processes is determined by the specific carrying method.

Large monomer load

According to the following figure, the three modules will be hosted on GravelService.Host.

  1. Create a new GravelService.Host project and use the WebApi type. Stored in the microservices folder, which makes it easier to understand the entire hierarchy.

  1. Secondly, it relies on some basic Nuget packages, such as ABP itself and Swagger which is convenient for displaying Api. This time, the creation of the entity is not considered, and the dependency of the EF Core package is not considered.

  • Volo.Abp

  • Volo.Abp.AspNetCore.MultiTenancy

  • Volo.Abp.AspNetCore.Mvc

  • Volo.Abp.Autofac

  • Swashbuckle.AspNetCore

  1. Reference the Application layer and EntityFrameworkCore layer in each module. Imitate the given microservice Demo to complete a wave of CV operations. Adding a class is responsible for the configuration of services and middleware.

  1. Rely on the referenced Application layer and Module in the EntityFrameworkCore layer, so that the module dependencies are fixed.

[DependsOn(
    typeof(AbpAutofacModule),
    typeof(AbpAspNetCoreMvcModule),
    typeof(AbpAspNetCoreMultiTenancyModule),
    typeof(CustomerManagementApplicationModule),
    typeof(CustomerManagementEntityFrameworkCoreModule),
    typeof(OrderManagementApplicationModule),
    typeof(OrderManagementEntityFrameworkCoreModule),
    typeof(ProductManagementApplicationModule),
    typeof(ProductManagementEntityFrameworkCoreModule)
   )]
public class GravelServiceHostModule : AbpModule
{
  ...
}
  1. Increase the service configuration and dynamically convert the application services in each module into an Api controller.

Configure<AbpAspNetCoreMvcOptions>(options =>
{
    options.ConventionalControllers
        .Create(typeof(CustomerManagementApplicationModule).Assembly,       
        opts =>
        {
            opts.RootPath = "CustomerManagement";
        })
        .Create(typeof(OrderManagementApplicationModule).Assembly, 
        opts =>
        {
            opts.RootPath = "OrderManagement";
        })
        .Create(typeof(ProductManagementApplicationModule).Assembly, 
        opts =>
        {
            opts.RootPath = "ProductManagement";
        });
});
  1. Then, just start it, and all the interfaces in the modules are carried in the carrier.

  1. By accessing the api/OrderManagement/order interface of Order to get the returned 9527, it is verified that the application service of the Product context is accessed in the anti-corrosion layer.

At this time, it is in the same process, and the specific implementation of ProductAppService is used. The breakpoint view can also see the request in the current process. The application service that depends on other context services is ApplicationServiceProxy.

Multi-service bearer

Start to switch the bearer mode according to the following figure, only change the bearer, and divide a large bearer into individual bearers for each context.

  1. Create three new WebApi projects equivalent to GravelService.Host. It can be tailored on GravelService.Host, each independent carrier only has its own context.

  1. According to the context mapping relationship, the Order bearer in the downstream increases the dependency on the upstream Product, and the Order bearer increases the dependency on the Application.Contracts layer in the Product module. And complete the dependency in the service configuration (line 7).

[DependsOn(
    typeof(AbpAutofacModule),
    typeof(AbpAspNetCoreMvcModule),
    typeof(AbpAspNetCoreMultiTenancyModule),
    typeof(OrderManagementApplicationModule),
    typeof(OrderManagementEntityFrameworkCoreModule),
    typeof(ProductManagementApplicationContractsModule)
    )]
public class OrderServiceHostModule : AbpModule
{
...
}
  1. Configure the remote service proxy, and set the remote service request from the Order bearer to the Product bearer in the service configuration. Add the Volo.Abp.Http.Client package to the Order bearer and complete the dependency in the service configuration.

[DependsOn(
    ...
    typeof(AbpHttpClientModule),
    ...
    )]
public class OrderServiceHostModule : AbpModule
{
    public override void ConfigureServices(ServiceConfigurationContext context)
    {
        var configuration = context.Services.GetConfiguration();
        ...                       
        context.Services.AddHttpClientProxies(         typeof(ProductManagementApplicationContractsModule).Assembly);
        ...
    }
}
  1. Add the remote call address to the Product carrier in the configuration source appsettings file

 {
  "RemoteServices": {
    "Default": {
      "BaseUrl": "http://localhost:57687"
    }
}
  1. Change the project configuration, start multiple files, start three independent carriers together, call the Get request in the Order again, and also obtain the data from the application service in the Product context

  1. The different inter-process bearing method adopted this time passes through the anti-corrosion layer, and then calls the Product carrier through the Http proxy service provided by ABP. You can breakpoint to view the current AppService type in the anti-corrosion layer. It is no longer directly using ProductAppService.

Maka

It is really convenient to switch from a large single bearer to a multi-service bearer, the Modules part does not require any changes. As for the internal remote calls, ABP VNext itself still has some problems, like the similar collection of Get requests that were fixed in version 3.1, but this does not affect the giant's progress.

Guess you like

Origin blog.csdn.net/sD7O95O/article/details/108877851