ASP.NET Core Microservices Code Refactoring into Reusable NuGet Package

ASP.NET Core Microservices Code Refactoring into Reusable NuGet Package

In our Drone Pizza Delivery application we have built 2 Microservices – CommandCenter and ProcessCenter. You may have notice there are some classes that are used in both these Microservices which makes the code redundant. We can take these common classes and codes to a new Class Library project and create a NuGet package of it.

Then we can use this NuGet Package in both these Microservices. This will remove the problem of code redundancy from our app.

You can find this tutorial’s the complete Source Code at my GitHub Repository.

Create a Class Library Project and Refactoring Code

In Visual Studio create a new Class Library (.NET Core) project and name it Common.

class library dotnet

Then select properties and make sure you have selected .NET 8.0 as the target framework.

Next add the following NuGet package to the solution:

MassTransit.RabbitMQ
MongoDB.Driver
Microsoft.Extensions.Configuration
Microsoft.Extensions.Configuration.Binder
Microsoft.Extensions.DependencyInjection

These are the same packages we are using in both the Microservices.

In this project we will move common files and codes from both the microservices. So open CommandCenter microservice project and move the following folders to the “Common” project.

  • 1. Entity
  • 2. MongoDB
  • 3. Setting

Note that the files in the above 3 folders are also used in the ProcessCenter microservices. So, by moving these files to a comman project we will be removing redundant files from both the microservices.

Next, move the Contracts.cs file from the Infrastructure folder to the Common project. I have shown this in the below image:

commandcenter microservice files to refactor

Now we will create an extension method of MassTransit code used in both Microservices. So in the “Common” project create a new folder called MassTransit and inside it create a new class called Extensions.cs whose code is given below:

using CommandCenter.Setting;
using MassTransit;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using System.Reflection;

namespace Common.MassTransit
{
    public static class Extensions
    {
        public static IServiceCollection AddMassTransitWithRabbitMQ(this IServiceCollection services)
        {
            services.AddMassTransit(x =>
            {
                x.AddConsumers(Assembly.GetEntryAssembly());
                x.UsingRabbitMq((context, configurator) =>
                {
                    var configuration = context.GetService<IConfiguration>();
                    var serviceSettings = configuration.GetSection(nameof(ServiceSettings)).Get<ServiceSettings>();
                    var rabbitMqSettings = configuration.GetSection(nameof(RabbitMQSettings)).Get<RabbitMQSettings>();
                    configurator.Host(rabbitMqSettings.Host);
                    configurator.ConfigureEndpoints(context, new KebabCaseEndpointNameFormatter(serviceSettings.ServiceName, false));
                    configurator.UseMessageRetry(b =>
                    {
                        b.Interval(3, TimeSpan.FromSeconds(5));
                    });
                });
            });
            return services;
        }
    }
}

Creating NuGet Package

Now it’s turn to create a NuGet Package for the “Common” project. So open Package Manager Console and add the following command:

dotnet pack --output commonpackage

This command will create the package inside commonpackage folder of your project.

nuget package command

If you open this folder then you will NuGet package file called Common.1.0.0.nupkg there. Common is the name of the package, 1.0.0 is the version and NuGet packages have .nupkg file extension.

Next run the following command to add a NuGet source:

dotnet nuget add source D:\commonpackage -n MyCommon

Here I have named NuGet source as MyCommon and my NuGet Package is kept inside D:\commonpackage. Note that the name of the Package will be the same as the name of the project, in our case the name of the project was Common so the NuGet package will also be named as common.

nuget package added to source

Before proceeding, copy the package file we created to D:\commonpackage location of your pc.

.

Now we will use this NuGet package in both of our Microservices. So kindly close and reopen the CommandCenter and ProcessCenter microservice applications on Visual Studio, this is necessary so that we can add our new package to the solution file.

Now on the Visual Studio, open NuGet Package Manager ➤ Manage NuGet Packages for Solutions. On the package source drop down, you will see MyCommon, so select it. Then click the Browse link and you will see the “Common” package is visible there, so install it on the CommandCenter and ProcessCenter microservices.

Installing NuGet package

Now all you have to do is remove the common files and use it from this NuGet package in both the Microservices.

Also change the Program.cs class to use AddMassTransitWithRabbitMQ() from the NuGet Package in both the Microservices. To do this, open Program.cs class of CommandCenter microservice and remove the below code:

builder.Services.AddMassTransit(x =>
{
    x.AddConsumers(Assembly.GetEntryAssembly());
    x.UsingRabbitMq((context, configurator) =>
    {
        var rabbitMqSettings = builder.Configuration.GetSection(nameof(RabbitMQSettings)).Get<RabbitMQSettings>();
        configurator.Host(rabbitMqSettings.Host);
        configurator.ConfigureEndpoints(context, new KebabCaseEndpointNameFormatter(serviceSettings.ServiceName, false));
    });
});

Add AddMassTransitWithRabbitMQ() method:

builder.Services.AddMongo().AddMongoRepository<Order>("pizzaItems").AddMassTransitWithRabbitMQ();

The updated Program class should look as shown below:

using CommandCenter.Entity;
using CommandCenter.MongoDB;
using CommandCenter.Setting;
using Common.MassTransit;

var builder = WebApplication.CreateBuilder(args);

// Add services to the container.
var serviceSettings = builder.Configuration.GetSection(nameof(ServiceSettings)).Get<ServiceSettings>();
builder.Services.AddMongo().AddMongoRepository<Order>("pizzaItems").AddMassTransitWithRabbitMQ();

builder.Services.AddControllers(options =>
{
    options.SuppressAsyncSuffixInActionNames = false;
});

// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();

var app = builder.Build();

// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
{
    app.UseSwagger();
    app.UseSwaggerUI();
}

app.UseHttpsRedirection();

app.UseAuthorization();

app.MapControllers();

app.Run();

In the Program.cs class of ProcessCenter microservice. Remove the following code lines.

builder.Services.AddMassTransit(x =>
{
    x.AddConsumers(Assembly.GetEntryAssembly());
    x.UsingRabbitMq((context, configurator) =>
    {
        var configuration = context.GetService<IConfiguration>();
        var serviceSettings = configuration.GetSection(nameof(ServiceSettings)).Get<ServiceSettings>();
        var rabbitMqSettings = configuration.GetSection(nameof(RabbitMQSettings)).Get<RabbitMQSettings>();
        configurator.Host(rabbitMqSettings.Host);
        configurator.ConfigureEndpoints(context, new KebabCaseEndpointNameFormatter(serviceSettings.ServiceName, false));
        configurator.UseMessageRetry(b =>
        {
            b.Interval(3, TimeSpan.FromSeconds(5));
        });
    });
});

Add AddMassTransitWithRabbitMQ() method:

builder.Services.AddMongo().AddMongoRepository<Process>("processItems").AddMongoRepository<Order>("pizzaItems").AddMassTransitWithRabbitMQ(); 

The updated code of the Program class is:

using Polly.Timeout;
using Polly;
using ProcessCenter.Client;
using ProcessCenter.Entity;
using CommandCenter.MongoDB;
using CommandCenter.Entity;
using Common.MassTransit;

var builder = WebApplication.CreateBuilder(args);

// Add services to the container.
builder.Services.AddMongo().AddMongoRepository<Process>("processItems").AddMongoRepository<Order>("pizzaItems").AddMassTransitWithRabbitMQ();  

builder.Services.AddHttpClient<OrderClient>(a =>
{
    a.BaseAddress = new Uri("https://localhost:44393");
})
.AddTransientHttpErrorPolicy(b => b.Or<TimeoutRejectedException>().WaitAndRetryAsync(
    5,
    c => TimeSpan.FromSeconds(Math.Pow(2, c))
))
.AddTransientHttpErrorPolicy(b => b.Or<TimeoutRejectedException>().CircuitBreakerAsync(
    3,
    TimeSpan.FromSeconds(15)
))
.AddPolicyHandler(Policy.TimeoutAsync<HttpResponseMessage>(1));

builder.Services.AddControllers();

// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();

var app = builder.Build();

// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
{
    app.UseSwagger();
    app.UseSwaggerUI();
}

app.UseHttpsRedirection();

app.UseAuthorization();

app.MapControllers();

app.Run();

Finally, on the ProcessCenter project do the following 3 things:

  1. Remove the “MongoDB” and “Setting” folder.
  2. Remove all files except “Process.cs” from the “Entity” folder.
  3. Remove “Contracts.cs” file from the “Infrastructure” folder.

In the below image I have shown how the final files and folder structure looks for both the microservices. We have removed as much as 60% of redundant code now.

code refactor final

Conclusion

In this tutorial we covered code refactoring in microservices. We first moved the comman files and folder to a new class project and created a NuGet package of it. Then used that package in both the microservices.

SHARE THIS ARTICLE

  • linkedin
  • reddit

ABOUT THE AUTHOR

I am Yogi S. I write DOT NET artciles on my sites hosting.work and yogihosting.com. You can connect with me on Twitter. I hope my articles are helping you in some way or the other, if you like my articles consider buying me a coffee - Buy Me A Coffee

Leave a Reply

Your email address will not be published. Required fields are marked *

Related Posts based on your interest