Tuesday, 17 December 2024

Use a .NET Web API to implement the Mediator Pattern

Leave a Comment

Within an application, it is occasionally necessary for one object or component to connect with another. There are no problems if the components are small. Real-time applications, on the other hand, consist of numerous components, all of which must communicate with one another. The more components there are in the application, the more complex it becomes. In this post, we'll look at how to use the Mediator approach to solve this issue and how to include it into a.NET Web API.

The Real-Time Problem

Let's understand the real-time problem using the following example.

We have four components.

  • Component A
  • Component B
  • Component C
  • Component D

  

These components need to communicate with each other. For example, if Component A wants to communicate with Component B, Component A must have a reference to Component B and use that reference to call Component B's methods. Similarly, if any component wants to send a message to another component, it must know the reference of the other component and use it to call its methods.

The objects are tightly coupled, meaning many objects know each other. In the example, we have only four objects. However, in real-world applications, you might have hundreds of objects that need to communicate with each other. It will be very difficult and will increase the complexity of the application.

How to Reduce the Coupling Between the Components Using Mediator Pattern?

A mediator design pattern is a behavioral design pattern that restricts the direct communication between entities and forces them to interact through a mediator object. It reduces the communication complexity between the components.

In the Mediator pattern, direct communication between components is restricted. Instead, all components communicate indirectly through a dedicated mediator object. The Mediator object serves as the communication hub for all components. Each component interacts with the mediator object, which then routes the messages to the appropriate destination component.

Let's consider the above example and re-design the application using the Mediator pattern as described below.

 
Real-world use cases for Mediator Pattern

Chat Application is a perfect example of the Mediator design pattern. In this application, there are users and groups. Users can join groups and share their messages within the group. When 'Person A' shares a message in the chat group, it is sent to all members who have joined the group. In this scenario, the chat group acts as the Mediator.

Components involved in Mediator Pattern

  • Component: Components are various classes with their own business logic. Each component references a mediator, as defined by the mediator interface.
  • Mediator: The Mediator interface defines methods for communication with components, mainly featuring a notification method.
  • Concrete Mediator: Concrete Mediators manage the interactions between various components.
namespace MediatorDesignPattern
{
    public interface IMediator
    {
        // This Method is used to send the Message to users who are registered with the group
        void SendMessage(string message, IUser user);
        // This method is used to register a user with the group
        void RegisterChatUser(IUser user);
    }
}
namespace MediatorDesignPattern
{
    public interface IUser
    {
        int UserId { get; }
        void SendMessage(string message);
        void RecieveMessage(string message);
    }
}
namespace MediatorDesignPattern
{
    public class ChatUser : IUser
    {
        private readonly IMediator _mediator;
        private readonly string _username;
        private readonly int _userId;
        public int UserId => _userId;
        public ChatUser(IMediator mediator, string username, int userId)
        {
            _mediator = mediator;
            _username = username;
            _userId = userId;
        }
        public void RecieveMessage(string message)
        {
            Console.WriteLine($"{_username} received message: {message}");
        }
        public void SendMessage(string message)
        {
            Console.WriteLine($"{_username} sending message: {message}");
            _mediator.SendMessage(message, this);
        }
    }
}
namespace MediatorDesignPattern
{
    public class ChatMediator : IMediator
    {
        private readonly Dictionary<int, IUser> UsersList; // List of users to whom we want to communicate
        public ChatMediator()
        {
            UsersList = new Dictionary<int, IUser>();
        }
        // To register the user within the group
        public void RegisterChatUser(IUser user)
        {
            if (!UsersList.ContainsKey(user.UserId))
            {
                UsersList.Add(user.UserId, user);
            }
        }
        // To send the message in the group
        public void SendMessage(string message, IUser chatUser)
        {
            foreach (var user in UsersList.Where(u => u.Key != chatUser.UserId))
            {
                user.Value.RecieveMessage(message);
            }
        }
    }
}
namespace MediatorDesignPattern
{
    class Program
    {
        static void Main(string[] args)
        {
             var chatGroup = new ChatMediator();
             var PersonA = new User(chatGroup, "Person A", 1);
             var PersonB = new User(chatGroup, "Person B", 2);
             var PersonC = new User(chatGroup, "Person C", 3);
             chatGroup.RegisterChatUser(PersonA);
             chatGroup.RegisterChatUser(PersonB);
             chatGroup.RegisterChatUser(PersonC);
             PersonA.SendMessage("Any one is available for trip this week?");
             PersonB.SendMessage("I am in");
             PersonC.SendMessage("I am not available");
             Console.Read();
        }
    }
}

Output

How to Implement Mediator Pattern in .NET Web API?

MediatR is a widely used library that simplifies the implementation of the Mediator pattern in .NET applications.

Step 1. Install the MediatR package.

You can do this through the NuGet Package Manager or by running the following command in the Package Manager Console.

Install-Package MediatR
Install-Package MediatR.Extensions.Microsoft.DependencyInjection
Bash

Step 2. Define the Request and Response Models.

public class SendMessageCommand : IRequest<string>
{
    public string Sender { get; set; }
    public string Message { get; set; }
}

This class represents the request model for sending a message. It implements the IRequest<string> interface from MediatR, indicating that it expects a response of type string.

Step 3. Create the Handler.

public class SendMessageHandler : IRequestHandler<SendMessageCommand, string>
{
    public Task<string> Handle(SendMessageCommand request, CancellationToken cancellationToken)
    {
        // Logic to handle the message (e.g., routing it to other components)
        string response = $"[{request.Sender}]: {request.Message}";
        return Task.FromResult(response);
    }
}

This class handles the processing of the SendMessageCommand. It implements the IRequestHandler<SendMessageCommand, string> interface, which indicates it handles SendMessageCommand requests and returns a string response. The Handle method processes the request and returns a formatted string containing the sender and the message.

Step 4. Configure MediatR in the Startup.

public class Startup
{
    public void ConfigureServices(IServiceCollection services)
    {
        services.AddMediatR(typeof(Startup).Assembly);
    }
}

In the Startup class, MediatR is added to the service collection using services.AddMediatR(typeof(Startup).Assembly). This registers all MediatR handlers found in the specified assembly.

Step 5. Send a Message Using MediatR.

public class ChatController : ControllerBase
{
    private readonly IMediator _mediator;
    public ChatController(IMediator mediator)
    {
        _mediator = mediator;
    }
    [HttpPost("send")]
    public async Task<IActionResult> SendMessage([FromBody] SendMessageCommand command)
    {
        string result = await _mediator.Send(command);
        return Ok(result);
    }
}

This controller handles incoming HTTP requests for sending messages. It injects an instance of IMediator via its constructor. The SendMessage action method receives a SendMessageCommand object as its parameter, sends the command using MediatR, and returns the result as an HTTP response.

Flow

  • When a POST request is made to the sending endpoint of the ChatController, the SendMessageCommand is created with the sender's name and message content.
  • The SendMessageCommand is sent to MediatR using _mediator.Send(command).
  • MediatR locates the appropriate handler (SendMessageHandler) for the command.
  • The SendMessageHandler processes the command by formatting the sender's name and message into a string and returns this string as the response.
  • The ChatController returns the formatted string as the HTTP response.

This approach centralizes communication through MediatR, reducing direct dependencies between components and making the code more modular and easier to maintain.

ASP.NET Core 9.0 Hosting Recommendation

One of the most important things when choosing a good ASP.NET Core 9.0 hosting is the feature and reliability. HostForLIFE is the leading provider of Windows hosting and affordable ASP.NET Core, their servers are optimized for PHP web applications. The performance and the uptime of the hosting service are excellent and the features of the web hosting plan are even greater than what many hosting providers ask you to pay for. 

At HostForLIFE.eu, customers can also experience fast ASP.NET Core hosting. The company invested a lot of money to ensure the best and fastest performance of the datacenters, servers, network and other facilities. Its datacenters are equipped with the top equipments like cooling system, fire detection, high speed Internet connection, and so on. That is why HostForLIFEASP.NET guarantees 99.9% uptime for ASP.NET Core. And the engineers do regular maintenance and monitoring works to assure its Orchard hosting are security and always up.

Read More...

Monday, 9 December 2024

Effective Task Scheduling in C# Using the Round Robin Algorithm

Leave a Comment

 One popular scheduling technique in computer science, particularly in operating systems, is the round robin algorithm. It is made to work with time-sharing systems in which every process is given a set time slice or quantum, guaranteeing that every process receives an equal amount of CPU time. When there are several processes that must be carried out without starving, this method works especially well. This article will examine the Round Robin algorithm, comprehend its fundamentals, and demonstrate its implementation in C# with a real-world use case.

Round Robin Algorithm

The round-robin algorithm is a preemptive scheduling algorithm that cycles through all processes in the ready queue in a circular order. Each process is given a fixed time slice during which it can execute. If a process is not complete within its time slice, it is moved to the end of the queue, and the CPU scheduler picks the next process in line. This cycle continues until all processes are completed. The main advantage of the round-robin algorithm is its simplicity and fairness, as each process gets an equal opportunity to execute.

Key Features of Round Robin Algorithm
  1. Time Quantum: A fixed time slice assigned to each process.
  2. Preemption: The algorithm allows processes to be preempted and moved to the end of the queue.
  3. Fairness: Ensures all processes get an equal share of CPU time.
  4. Simple Implementation: Easy to implement and understand.
Round Robin Algorithm in C#

To implement the Round Robin algorithm in C#, we will follow these steps:

  1. Define a class to represent a process.
  2. Implement a method to simulate the Round Robin scheduling.
  3. Test the implementation with a practical use case example.
Step 1. Process Representation

Define a Process class to represent each process in the system. This class will have properties such as Process ID, Burst Time, and Remaining Time.

public class Process
{
    public int ProcessID { get; set; }
    public int BurstTime { get; set; }
    public int RemainingTime { get; set; }

    public Process(int processID, int burstTime)
    {
        ProcessID = processID;
        BurstTime = burstTime;
        RemainingTime = burstTime;
    }
}
Step 2. Round Robin Scheduling

Implement a method to simulate the Round Robin scheduling. This method will take a list of processes and a time quantum as input and simulate the execution of processes based on the Round Robin algorithm.

using System;
using System.Collections.Generic;

public class RoundRobinScheduler
{
    public static void Schedule(List<Process> processes, int timeQuantum)
    {
        int time = 0;
        Queue<Process> readyQueue = new Queue<Process>(processes);

        while (readyQueue.Count > 0)
        {
            Process currentProcess = readyQueue.Dequeue();
            if (currentProcess.RemainingTime <= timeQuantum)
            {
                time += currentProcess.RemainingTime;
                Console.WriteLine($"Process {currentProcess.ProcessID} completed at time {time}");
                currentProcess.RemainingTime = 0;
            }
            else
            {
                time += timeQuantum;
                currentProcess.RemainingTime -= timeQuantum;
                readyQueue.Enqueue(currentProcess);
                Console.WriteLine($"Process {currentProcess.ProcessID} executed for {timeQuantum} units; remaining time: {currentProcess.RemainingTime}");
            }
        }
    }
}
Step 3. Practical Use Case Example

We will create a sample use case to demonstrate the round-robin algorithm. We will define a list of processes with varying burst times and execute them using our round-robin scheduler.

class Program
{
    static void Main(string[] args)
    {
        List<Process> processes = new List<Process>
        {
            new Process(1, 10),
            new Process(2, 4),
            new Process(3, 5),
            new Process(4, 7)
        };

        int timeQuantum = 3;

        Console.WriteLine("Round Robin Scheduling:");
        RoundRobinScheduler.Schedule(processes, timeQuantum);
    }
}
Step 4. Output

 

Conclusion

A straightforward yet effective scheduling technique that guarantees equitable CPU time distribution among activities is the round robin method. A time-sharing system where every process has an equal chance to run can be simulated by using the Round Robin algorithm in C#. An outline of the Round Robin algorithm, its salient characteristics, and a real-world use case example illustrating its use were presented in this article. Designing effective and equitable scheduling systems for a range of applications can be facilitated by comprehending and utilizing the Round Robin algorithm.

ASP.NET Core 9.0 Hosting Recommendation

One of the most important things when choosing a good ASP.NET Core 9.0 hosting is the feature and reliability. HostForLIFE is the leading provider of Windows hosting and affordable ASP.NET Core, their servers are optimized for PHP web applications. The performance and the uptime of the hosting service are excellent and the features of the web hosting plan are even greater than what many hosting providers ask you to pay for. 

At HostForLIFE.eu, customers can also experience fast ASP.NET Core hosting. The company invested a lot of money to ensure the best and fastest performance of the datacenters, servers, network and other facilities. Its datacenters are equipped with the top equipments like cooling system, fire detection, high speed Internet connection, and so on. That is why HostForLIFEASP.NET guarantees 99.9% uptime for ASP.NET Core. And the engineers do regular maintenance and monitoring works to assure its Orchard hosting are security and always up.

Read More...

Tuesday, 3 December 2024

What is Params In C#?

Leave a Comment

When working with methods that accept a variable number of the same type of parameters, the "params" keyword is essential for increasing flexibility and ease in C# programming.


C# parameters

This feature, which enables developers to send an arbitrary number of parameters or optional parameters of the same type in a method declaration, is especially helpful when the precise number of arguments is unknown in advance.

class Program
{
    public static void AddItemsToShoppingBasket(params string[] items)
    {
        // ....
    }

    public static void AddItemsSumToShoppingBasket(params int[] sum)
    {
        // ....
    }
}

Here, we do not know the count of items beforehand, and the method is written in such a way by specifying the params keyword that it accepts string items without specifying the count.

The params keyword is employed in this method signature declarations to denote that a parameter array can be passed to the method. This array can hold zero or more values of a specified type and can also be an optional parameter/hold optional arguments.

The default value for this parameter is an empty array of the type specified in the method signature. For example, when a method containing the argument 'params object[] objects' is called without any parameters, it creates an empty array of objects.

As shown below, "AddToShoppingBasket" can be invoked with a variable number of arguments of string parameters. The params keyword simplifies the syntax for the method call by allowing developers to pass the optional parameters directly without explicitly creating an array.

class Program
{
    AddItemsToShoppingBasket("cake", "pizza", "cold drink");
    AddItemsToShoppingBasket("snacks", "burger");
    AddItemsToShoppingBasket(); // Valid with zero parameters
}
Considerations and Best Practices

Now that we have introduced the params keyword in general let us dive deep into some considerations and best practices of the 'params' keyword.

The parameter type must be a one-dimensional array.

To use the params keyword specified in the method "AddItemsToShoppingBasket" defined above, we can pass a one-dimensional array instead of manually calling the method using parameters like below.

// example

class Program
{
    var items = [] {"cake", "pizza", "cold drink"}; // one-dimensional string array
    AddItemsToShoppingBasket(items); // works
    AddItemsToShoppingBasket("cake", "pizza", "cold drink"); // same as above line

}

Can pass a comma-separated list of arguments for the type of the array elements.

While using a method with the params keyword, we can pass multiple values of arguments as comma-separated values.

// example method signature

class Program
{
    AddItemsToShoppingBasket("snacks", "burger", "snacks", "burger", "cold drink"); // comma separated values
    AddItemsToShoppingBasket("snacks");
}
Pass an array of arguments of the correct type

The below code throws an error if we try to add items of type int into the shopping basket.

// example

AddItemsToShoppingBasket("snacks",2,"burger"); // error
AddItemsToShoppingBasket(2,3,4); // error as params type is string

This occurs as the array argument is a string type and not an int type.

Params should be the last parameter in the Method

No additional parameters are permitted after the params parameter in a method signature declaration, and only one params argument is permitted in a method parameters declaration.

Params should be the last argument of the method signature. This means that all required parameters need to be specified before the params argument.

This is shown in the following code.

static void Main(string[] args)
{
    public static void AddItemsToShoppingBasket(decimal total, params string[] items)
    {
        // ....
    } // This works
}

static void Main(string[] args)
{
    public static void AddItemsToShoppingBasket(decimal total, int totalQuantity, params string[] items)
    {
        // ....
    } // This works
}

static void Main(string[] args)
{
    // Compiler error, This does not work as the params argument is declared before other arguments
    public static void AddItemsToShoppingBasket(params string[] items, decimal total, int totalQuantity)
    {
        // ....
    }
}

Only One params keyword.

There can only be one params parameter in a method signature.

class Program
{
    static void Main(string[] args)
    {
        public static void AddItemsToShoppingBasket(params string[] items, params string[] quantity)
        {
            // Compiler error, This does not work.
        }
    }
}

You can pass no arguments.

If you send no arguments, the length of the params list is zero.

AddItemsToShoppingBasket(); // Works

For any parameter with params, an argument is considered optional and can be called without passing parameters.

Code Example

Here is a complete code example written in C# that shows how to pass different numbers of variables in a params method as a params argument and read these values back in the caller code.

Create a new console application

In Visual Studio, select Create New Project to get the below window. Here, you can provide the Solution Name, Project Name, and paths. Once this information is entered, click next to create the console application ready to start coding.

 Now, add the code below.

class Program
{
    List<string> cart = new List<string>();

    void AddItemsToShoppingBasket(params string[] items)
    {
        for (int i = 0; i < items.Length; i++)
        {
            cart.Add(items[i]);
        }
    }

    // caller code
    static void Main(string[] args)
    {
        Console.WriteLine("Params Example");

        Program program = new Program();

        Console.WriteLine("Enter the cart items as comma separated values");
        var itemsString = Console.ReadLine();

        if (itemsString != null)
        {
            var items = itemsString.Split(",").ToArray();
            program.AddItemsToShoppingBasket(items);
        }

        program.AddItemsToShoppingBasket("Sample1", "Sample2");

        Console.WriteLine("-------------------------------------------------------");
        Console.WriteLine("Display Cart");

        foreach (var item in program.cart)
        {
            Console.WriteLine(item);
        }
    }
}

Output

The output of the above code looks like the following.


 

ASP.NET Core 9.0 Hosting Recommendation

One of the most important things when choosing a good ASP.NET Core 9.0 hosting is the feature and reliability. HostForLIFE is the leading provider of Windows hosting and affordable ASP.NET Core, their servers are optimized for PHP web applications. The performance and the uptime of the hosting service are excellent and the features of the web hosting plan are even greater than what many hosting providers ask you to pay for. 

At HostForLIFE.eu, customers can also experience fast ASP.NET Core hosting. The company invested a lot of money to ensure the best and fastest performance of the datacenters, servers, network and other facilities. Its datacenters are equipped with the top equipments like cooling system, fire detection, high speed Internet connection, and so on. That is why HostForLIFEASP.NET guarantees 99.9% uptime for ASP.NET Core. And the engineers do regular maintenance and monitoring works to assure its Orchard hosting are security and always up.

 

Read More...

Thursday, 28 November 2024

IExceptionHandler in.NET Core 8 for Improved Exception Handling

Leave a Comment

Determining how our programs behave requires proper error handling. It involves developing consistent answer formats for our applications so that we can continue to follow a normal process even if something goes wrong. We have a new and improved way to handle problems in our apps thanks to the IExceptionHandler abstraction that comes with.NET 8.

What is an IExceptionHandler?

An interface called IExceptionHandler is used in ASP.NET Core applications to handle exceptions. It outlines an interface that we can use to deal with various exceptions. This enables us to create unique logic that responds to specific exceptions or sets of exceptions according to their type, logging and generating customized error messages and responses.

Why use IExceptionHandler?

We can create more reliable and user-friendly APIs by utilizing IExceptionHandler, which provides a strong and adaptable method for handling exceptions in .NET APIs. In order to handle various exception types, we can also implement IExceptionHandler in standard C# classes. By doing this, we can easily maintain and modularize our applications.

By customizing the responses to the individual exceptions, IExceptionHandler enables us to provide more detailed error messages. This is useful for creating user interfaces that allow us to route users to a specific error page in the event that one of our APIs throws an exception.

Furthermore, because .NET 8 already has the middleware implemented for us through the IExceptionHandler interface, we don't always need to create custom global exception handlers for our applications when using the IExceptionHandler interface.

As an illustration

Let’s create the GlobalExceptionHandler.cs file in our application.

public class GlobalExceptionHandler(ILogger<GlobalExceptionHandler> logger) : IExceptionHandler
{
    private readonly ILogger<GlobalExceptionHandler> _logger = logger;
    public async ValueTask<bool> TryHandleAsync(HttpContext httpContext, Exception exception, CancellationToken cancellationToken)
    {
        _logger.LogError(exception, "An unexpected error occurred");
        string? currentId = Activity.Current?.Id ?? httpContext.TraceIdentifier;
        Dictionary<string, object> otherDetails = new()
        {
            { "CurrentId", currentId },
            { "TraceId", Convert.ToString(Activity.Current!.Context.TraceId)! }
        };
        await httpContext.Response.WriteAsJsonAsync(
            new ProblemDetails
            {
                Status = (int)HttpStatusCode.InternalServerError,
                Type = exception.GetType().Name,
                Title = "An unexpected error occurred",
                Detail = exception.Message,
                Instance = $"{httpContext.Request.Method} {httpContext.Request.Path}",
                Extensions = otherDetails!
            },
            cancellationToken
        );
        return true;
    }
}

Next, let's set up the dependency injection container to register our exception handler.

builder.Services.AddExceptionHandler<GlobalExceptionHandler>();

Our application will automatically call the GlobalExceptionHandler handler whenever an exception occurs. According to RFC 7807 specifications, the API will also produce ProblemDetails standardized responses. We will have more control over how to handle, format, and intercept error responses in this way.

Let's now complete the application request pipeline by adding the middleware:

app.UseExceptionHandler(opt => { });

Let’s run the application and execute the API so we are able to see whether our global exception handler is executing when any exception is raised in our application and showing the details in the API response or not.



Managing various Exception Types

We implement distinct instances of IExceptionHandler, each handling a particular type of exception when handling various error types. Next, by invoking the AddExceptionHandler<THandler>() extension method, we can register each handler in the dependency injection container. It's important to remember that we should register exception handlers in the order in which we want them to be executed.

Let’s create an exception handler to handle The timeout exception handler.

public class TimeoutExceptionHandler(ILogger<TimeoutExceptionHandler> logger) : IExceptionHandler
{
    private readonly ILogger<TimeoutExceptionHandler> _logger = logger;

    public async ValueTask<bool> TryHandleAsync(
        HttpContext httpContext,
        Exception exception,
        CancellationToken cancellationToken)
    {
        _logger.LogError(exception, "A timeout occurred");
        if (exception is not TimeoutException)
        {
            return false;
        }
        httpContext.Response.StatusCode = (int)HttpStatusCode.RequestTimeout;
        string? currentId = Activity.Current?.Id ?? httpContext.TraceIdentifier;
        Dictionary<string, object> otherDetails = new()
        {
            { "CurrentId", currentId },
            { "TraceId", Convert.ToString(Activity.Current!.Context.TraceId)! }
        };
        await httpContext.Response.WriteAsJsonAsync(
            new ProblemDetails
            {
                Status = (int)HttpStatusCode.RequestTimeout,
                Type = exception.GetType().Name,
                Title = "A timeout occurred",
                Detail = exception.Message,
                Instance = $"{httpContext.Request.Method} {httpContext.Request.Path}",
                Extensions = otherDetails
            },
            cancellationToken);
        return true;
    }
}

Let’s register the services in the dependency injection.

builder.Services.AddExceptionHandler<TimeoutExceptionHandler>();
builder.Services.AddExceptionHandler<GlobalExceptionHandler>();
 

We learned the new technique and evolved together.

Happy coding!

ASP.NET Core 9.0 Hosting Recommendation

One of the most important things when choosing a good ASP.NET Core 9.0 hosting is the feature and reliability. HostForLIFE is the leading provider of Windows hosting and affordable ASP.NET Core, their servers are optimized for PHP web applications. The performance and the uptime of the hosting service are excellent and the features of the web hosting plan are even greater than what many hosting providers ask you to pay for. 

At HostForLIFE.eu, customers can also experience fast ASP.NET Core hosting. The company invested a lot of money to ensure the best and fastest performance of the datacenters, servers, network and other facilities. Its datacenters are equipped with the top equipments like cooling system, fire detection, high speed Internet connection, and so on. That is why HostForLIFEASP.NET guarantees 99.9% uptime for ASP.NET Core. And the engineers do regular maintenance and monitoring works to assure its Orchard hosting are security and always up.

Read More...