European ASP.NET 4.5 Hosting BLOG

BLOG about ASP.NET 4, ASP.NET 4.5 Hosting and Its Technology - Dedicated to European Windows Hosting Customer

European ASP.NET Core Hosting - HostForLIFE :: SRP (Single Responsibility Principle) in.NET Core

clock October 26, 2023 10:09 by author Peter

As a one-year developer, you've probably heard of the SOLID principles, which are a collection of five principles that promote clean, maintainable, and scalable code. The Single Responsibility Principle (SRP) is the most important of these concepts to understand and master. In this post, we'll describe SRP in layman's terms and present a simple.NET Core example to demonstrate its importance.

What exactly is SRP?
The Single Responsibility Principle (SRP) is the first letter in SOLID, and it emphasizes the need of keeping your code simple and well-organized. In a nutshell, SRP asserts that a class should have only one reason to modify. In other words, a class should only have one task or goal.

Consider real-world examples to help you understand this subject. Consider a simple kitchen equipment such as a toaster. Its primary function is to toast bread; it does not brew coffee or conduct any other unrelated duties. Similarly, classes in software development should have a single purpose.

What is the significance of SRP?
Readability: Classes having a single purpose are simpler to grasp for you and other developers, boosting code readability and maintainability.
Reusability: When a class excels at one task, it is more likely to be reusable in other parts of your application without producing unexpected side effects.
Smaller, more concentrated classes are easier to test. Specific tests for a class's single task can be written, making it easier to find and fix errors.

A Simplified.NET Core Example
Let's look at a simple.NET Core example to explain SRP. User Class. In this example, a User class is in charge of managing user-specific data such as name, email address, and age. This class's sole responsibility is to handle user data.

public class User
{
    public string Name { get; set; }
    public string Email { get; set; }
    public int Age { get; set; }

    public User(string name, string email, int age)
    {
        Name = name;
        Email = email;
        Age = age;
    }
}

Classification of NotificationServices
Then we make a NotificationService class. This class is in charge of sending user notifications. It may send emails, SMS messages, or other types of communication. The key point is that it only has one responsibility: handling notifications.

public class NotificationService
{
    public void SendEmail(User user, string message)
    {
        // Code to send an email notification
        Console.WriteLine($"Email sent to {user.Name}: {message}");
    }

    public void SendSMS(User user, string message)
    {
        // Code to send an SMS notification
        Console.WriteLine($"SMS sent to {user.Name}: {message}");
    }
}

In this example, the User class deals with user data, while the NotificationService class manages sending notifications. This clear separation of responsibilities aligns with the Single Responsibility Principle.

Using the Classes

Here's how you can use these classes in your application.

public class Program
{
    public static void Main()
    {
        var user = new User("
Peter", "Peter@hfl.eu", 30);
        var notificationService = new NotificationService();

        // Sending a notification to the user
        notificationService.SendEmail(user, "Hello, Peter! Don't forget about our meeting.");
        notificationService.SendSMS(user, "Reminder: Meeting today at 3 PM.");
    }
}

This example shows how to use the SRP to keep your code orderly, maintainable, and extensible. These concepts will assist a novice developer (fresher) in building more robust and scalable programs. With SRP, you'll be well on your way to being a more capable and efficient developer. Remember that in your journey as a software developer, simplicity and adherence to core principles such as SRP are critical to generating high-quality software.

HostForLIFE ASP.NET Core Hosting

European best, cheap and reliable ASP.NET hosting with instant activation. HostForLIFE.eu is #1 Recommended Windows and ASP.NET hosting in European Continent. With 99.99% Uptime Guaranteed of Relibility, Stability and Performace. HostForLIFE.eu security team is constantly monitoring the entire network for unusual behaviour. We deliver hosting solution including Shared hosting, Cloud hosting, Reseller hosting, Dedicated Servers, and IT as Service for companies of all size.



European ASP.NET Core Hosting - HostForLIFE :: Using xUnit for unit testing

clock October 23, 2023 09:08 by author Peter

It is critical for a software developer to assure the quality and dependability of code, and unit testing is one of the finest strategies for doing so. Developers may quickly construct extensive unit tests that confirm that each unit of software code operates as intended using xUnit, a popular unit testing tool in the.NET ecosystem. Developers can save time and resources while greatly improving overall program quality by embracing the capabilities of xUnit and introducing unit testing into the development workflow. So, let's get started on creating effective unit tests for our.NET apps right away!

Unit Testing Fundamentals
element testing is a type of software testing in which individual components or functions of a software program are tested separately to ensure that each element of the software behaves as intended. The goal is to ensure that each unit of software code operates as planned. A unit is the smallest testable component of any piece of software. A unit in object-oriented programming could be a method or a class.

The primary objectives of unit testing are as follows:

  • Unit tests should be isolated, which means they should test a specific piece of functionality in the application without relying on other elements of the system.
  • Unit tests should be automated and repeatable so that developers can run them regularly to catch regressions as soon as they occur.
  • Unit tests should be executed quickly so that developers can receive immediate feedback on the correctness of the code.

An Overview of xUnit
xUnit is a free and open-source unit testing framework for.NET programming languages. It is a member of the xUnit testing family, which contains frameworks for other programming languages such as Java and PHP. xUnit adheres to the xUnit architecture, which is founded on four major principles:

  1. Setup: Create the prerequisites for the test
  2. Act: Run the unit of code that will be tested
  3. Verify that the unit of code behaves as intended
  4. Teardown: Remove any resources used during the test

xUnit is a simple and beautiful tool for writing unit tests for.NET applications.

Using xUnit to Implement Unit Tests in.NET
Step 1: In Visual Studio, create a new Console App.

Now create a Class name Calculator

public class Calculator
{
    public double Add(double number1, double number2)
    {
        return (number1 + number2);
    }

    public double Subtract(double number1, double number2)
    {
        return (number1 - number2);
    }
}

Now you can build this project.

Step 2. Create a new xUnit Project
We must add a reference to our original project after generating the new xUnit project. To do so, right-click on the References folder in the xUnit project and select "Add Reference." Then, choose the project you wish to refer to and press "OK." We will be able to use the classes and methods defined in our initial project in our xUnit tests as a result of this.

Now comes the drafting of the test.
Calculator cal = new Calculator();

[Fact]
public void Test_AddTwoNumber()
{
    // Arrange
    var num1 = 3.5;
    var num2 = 5.5;
    var expectedValue = 9;

    // Act
    var sum = cal.Add(num1, num2);

    //Assert
    Assert.Equal(expectedValue, sum, 1);
}

[Fact]
public void Test_SubtractTwoNumber()
{
    // Arrange
    var num1 = 6;
    var num2 = 2;
    var expectedValue = 4;

    // Act
    var sum = cal.Subtract(num1, num2);

    //Assert
    Assert.Equal(expectedValue, sum, 1);
}

Step 3: Carry out the test
To run the test, right-click on the xUnit Test project and choose "Run Test". This will run all of the unit tests in the project and display the results. Make sure to perform this after you've written the unit tests to ensure they're operating properly and catching any regressions as soon as they appear.

The results of the test are presented on the screen once you run it. This is an important phase in the unit testing process since it aids in the identification of any flaws or bugs in the code. Developers may discover any regressions as soon as they appear by running the test regularly, allowing them to fix the problems quickly and efficiently. Unit tests should also be automated and repeatable, which means they can be run fast and easily, providing developers with immediate feedback on the quality of the code. With xUnit, developers can simply create extensive unit tests for their.NET projects, assuring the codebase's reliability and maintainability.

HostForLIFE ASP.NET Core Hosting

European best, cheap and reliable ASP.NET hosting with instant activation. HostForLIFE.eu is #1 Recommended Windows and ASP.NET hosting in European Continent. With 99.99% Uptime Guaranteed of Relibility, Stability and Performace. HostForLIFE.eu security team is constantly monitoring the entire network for unusual behaviour. We deliver hosting solution including Shared hosting, Cloud hosting, Reseller hosting, Dedicated Servers, and IT as Service for companies of all size.



European ASP.NET Core Hosting - HostForLIFE :: FluentValidation for data validation in ASP.NET Core

clock October 20, 2023 07:19 by author Peter

Validation of data is an important part of web application development. It guarantees that the information submitted by users is correct, safe, and follows the anticipated format. FluentValidation in ASP.NET Core provides a powerful and easy way to handle validation logic, allowing developers to validate user input while maintaining clean, maintainable code.

What is ASP.NET Core FluentValidation?
FluentValidation is a well-known.NET library for creating strongly typed validation rules. FluentValidation, as opposed to traditional attribute-based validation, provides a more expressive syntax and allows developers to construct validation logic in a distinct, clean, and reusable manner. It integrates effortlessly into ASP.NET Core applications, providing a strong solution for validating user input.To begin using FluentValidation, create an ASP.NET Core Web API project.

After you've created the project, you'll need to add two NuGet packages to it.

NuGet\Install-Package FluentValidation -Version 11.7.1
NuGet\Install-Package FluentValidation.DependencyInjectionExtensions -Version 11.7.1

After the installation is complete, you will be able to define validation criteria for the models you generate.

Developing Validation Rules

Consider a straightforward registration form with fields such as username, email, and password. Create a validator class and an associated model to validate this form:

public class UserRegistrationModel
{
    public string Username { get; set; }
    public string Email { get; set; }
    public string Password { get; set; }
}

public class UserRegistrationValidator : AbstractValidator<UserRegistrationModel>
{
    public UserRegistrationValidator()
    {
        RuleFor(x => x.Username).NotEmpty().MinimumLength(3);
        RuleFor(x => x.Email).NotEmpty().EmailAddress();
        RuleFor(x => x.Password).NotEmpty().MinimumLength(6);
    }
}

After the installation is complete, you will be able to define validation criteria for the models you generate.
Developing Validation Rules

Consider a straightforward registration form with fields such as username, email, and password. Create a validator class and an associated model to validate this form:

builder.Services.AddScoped<IValidator<UserRegistrationModel>, UserRegistrationValidator>(); // register validators

Including Validation in Controllers
You can now utilize the validator in your controller to validate the model.

[HttpPost]
  public IActionResult Register(UserRegistrationModel model)
  {
      var validator = new UserRegistrationValidator();
      var validationResult = validator.Validate(model);

      if (!validationResult.IsValid)
      {
          return BadRequest(validationResult.Errors);
      }

      // Process registration logic if the model is valid

      return Ok("Registration successful!");
  }

In this case, the Register action method validated the receiving UserRegistrationModel with UserRegistrationValidator. If the model is invalid, a BadRequest response containing the validation errors is returned.

Please test it with Postman to check that it is working properly. Please let me know if you require any assistance in setting up the test.

The validation appears to be working well now.

FluentValidation streamlines the data validation process in ASP.NET Core apps. Developers can design complicated validation rules in a legible and maintainable manner by providing a fluent and expressive API. You can ensure that your apps process user input accurately and securely by introducing FluentValidation into your ASP.NET Core projects, resulting in a more robust and dependable user experience.

HostForLIFE ASP.NET Core Hosting

European best, cheap and reliable ASP.NET hosting with instant activation. HostForLIFE.eu is #1 Recommended Windows and ASP.NET hosting in European Continent. With 99.99% Uptime Guaranteed of Relibility, Stability and Performace. HostForLIFE.eu security team is constantly monitoring the entire network for unusual behaviour. We deliver hosting solution including Shared hosting, Cloud hosting, Reseller hosting, Dedicated Servers, and IT as Service for companies of all size.



European ASP.NET Core Hosting - HostForLIFE :: FluentValidation for data validation in ASP.NET Core

clock October 20, 2023 07:19 by author Peter

Validation of data is an important part of web application development. It guarantees that the information submitted by users is correct, safe, and follows the anticipated format. FluentValidation in ASP.NET Core provides a powerful and easy way to handle validation logic, allowing developers to validate user input while maintaining clean, maintainable code.

What is ASP.NET Core FluentValidation?
FluentValidation is a well-known.NET library for creating strongly typed validation rules. FluentValidation, as opposed to traditional attribute-based validation, provides a more expressive syntax and allows developers to construct validation logic in a distinct, clean, and reusable manner. It integrates effortlessly into ASP.NET Core applications, providing a strong solution for validating user input.To begin using FluentValidation, create an ASP.NET Core Web API project.

After you've created the project, you'll need to add two NuGet packages to it.

NuGet\Install-Package FluentValidation -Version 11.7.1
NuGet\Install-Package FluentValidation.DependencyInjectionExtensions -Version 11.7.1

After the installation is complete, you will be able to define validation criteria for the models you generate.

Developing Validation Rules

Consider a straightforward registration form with fields such as username, email, and password. Create a validator class and an associated model to validate this form:

public class UserRegistrationModel
{
    public string Username { get; set; }
    public string Email { get; set; }
    public string Password { get; set; }
}

public class UserRegistrationValidator : AbstractValidator<UserRegistrationModel>
{
    public UserRegistrationValidator()
    {
        RuleFor(x => x.Username).NotEmpty().MinimumLength(3);
        RuleFor(x => x.Email).NotEmpty().EmailAddress();
        RuleFor(x => x.Password).NotEmpty().MinimumLength(6);
    }
}

After the installation is complete, you will be able to define validation criteria for the models you generate.
Developing Validation Rules

Consider a straightforward registration form with fields such as username, email, and password. Create a validator class and an associated model to validate this form:

builder.Services.AddScoped<IValidator<UserRegistrationModel>, UserRegistrationValidator>(); // register validators

Including Validation in Controllers
You can now utilize the validator in your controller to validate the model.

[HttpPost]
  public IActionResult Register(UserRegistrationModel model)
  {
      var validator = new UserRegistrationValidator();
      var validationResult = validator.Validate(model);

      if (!validationResult.IsValid)
      {
          return BadRequest(validationResult.Errors);
      }

      // Process registration logic if the model is valid

      return Ok("Registration successful!");
  }

In this case, the Register action method validated the receiving UserRegistrationModel with UserRegistrationValidator. If the model is invalid, a BadRequest response containing the validation errors is returned.

Please test it with Postman to check that it is working properly. Please let me know if you require any assistance in setting up the test.

The validation appears to be working well now.

FluentValidation streamlines the data validation process in ASP.NET Core apps. Developers can design complicated validation rules in a legible and maintainable manner by providing a fluent and expressive API. You can ensure that your apps process user input accurately and securely by introducing FluentValidation into your ASP.NET Core projects, resulting in a more robust and dependable user experience.



European ASP.NET Core Hosting - HostForLIFE :: How to Create an ASP.NET Core Web API Using a Simple Design Pattern?

clock October 11, 2023 09:16 by author Peter

Implementing a complete solution with all of the details you've asked requires a substantial amount of code, and providing an exhaustive example here may not be possible. I can, however, provide a general layout and code snippets for each layer of the Clean Architecture in an ASP.NET Core Web API application using the Facade Pattern for a CarCompany CRUD transaction.
Layers of Architecture that are Clean

Web API (Presentation Layer)
HTTP requests are handled by controllers.
DTOs (Data Transfer Objects) are used to communicate.

// CarCompanyController.cs
[ApiController]
[Route("api/[controller]")]
public class CarCompanyController : ControllerBase
{
    private readonly ICarCompanyFacade _carCompanyFacade;

    public CarCompanyController(ICarCompanyFacade carCompanyFacade)
    {
        _carCompanyFacade = carCompanyFacade;
    }

    [HttpGet]
    public IActionResult GetAll()
    {
        var carCompanies = _carCompanyFacade.GetAllCarCompanies();
        return Ok(carCompanies);
    }

    [HttpGet("{id}")]
    public IActionResult GetById(int id)
    {
        var carCompany = _carCompanyFacade.GetCarCompanyById(id);
        return Ok(carCompany);
    }

    [HttpPost]
    public IActionResult Create([FromBody] CarCompanyDto carCompanyDto)
    {
        var createdCompany = _carCompanyFacade.CreateCarCompany(carCompanyDto);
        return CreatedAtAction(nameof(GetById), new { id = createdCompany.Id }, createdCompany);
    }

    [HttpPut("{id}")]
    public IActionResult Update(int id, [FromBody] CarCompanyDto carCompanyDto)
    {
        _carCompanyFacade.UpdateCarCompany(id, carCompanyDto);
        return NoContent();
    }

    [HttpDelete("{id}")]
    public IActionResult Delete(int id)
    {
        _carCompanyFacade.DeleteCarCompany(id);
        return NoContent();
    }
}

Application Layer

  • Interfaces for the Facade.
  • Implementation of the Facade.

// ICarCompanyFacade.cs
public interface ICarCompanyFacade
{
    IEnumerable<CarCompanyDto> GetAllCarCompanies();
    CarCompanyDto GetCarCompanyById(int id);
    CarCompanyDto CreateCarCompany(CarCompanyDto carCompanyDto);
    void UpdateCarCompany(int id, CarCompanyDto carCompanyDto);
    void DeleteCarCompany(int id);
}

// CarCompanyFacade.cs
public class CarCompanyFacade: ICarCompanyFacade
{
    private readonly ICarCompanyService _carCompanyService;

    public CarCompanyFacade(ICarCompanyService carCompanyService)
    {
        _carCompanyService = carCompanyService;
    }

    public IEnumerable<CarCompanyDto> GetAllCarCompanies()
    {
        try
        {
            var carCompanies = _carCompanyService.GetAllCarCompanies();
            return carCompanies.Select(MapToDto);
        }
        catch (Exception ex)
        {
            throw new ApplicationException("Error occurred while fetching car companies.", ex);
        }
    }

    public CarCompanyDto GetCarCompanyById(int id)
    {
        try
        {
            var carCompany = _carCompanyService.GetCarCompanyById(id);
            return carCompany != null ? MapToDto(carCompany) : null;
        }
        catch (Exception ex)
        {
            throw new ApplicationException($"Error occurred while fetching car company with Id {id}.", ex);
        }
    }

    public CarCompanyDto CreateCarCompany(CarCompanyDto carCompanyDto)
    {
        try
        {
            var newCompany = new CarCompany
            {
                Name = carCompanyDto.Name,
            };

            _carCompanyService.CreateCarCompany(newCompany);
            return MapToDto(newCompany);
        }
        catch (Exception ex)
        {
            throw new ApplicationException("Error occurred while creating a new car company.", ex);
        }
    }

    public void UpdateCarCompany(int id, CarCompanyDto carCompanyDto)
    {
        try
        {
            var existingCompany = _carCompanyService.GetCarCompanyById(id);

            if (existingCompany != null)
            {
                existingCompany.Name = carCompanyDto.Name;
                // Update other properties...

                _carCompanyService.UpdateCarCompany(existingCompany);
            }
            else
            {
                throw new KeyNotFoundException($"Car company with Id {id} not found.");
            }
        }
        catch (Exception ex)
        {
            throw new ApplicationException($"Error occurred while updating car company with Id {id}.", ex);
        }
    }

    public void DeleteCarCompany(int id)
    {
        try
        {
            var existingCompany = _carCompanyService.GetCarCompanyById(id);

            if (existingCompany != null)
            {
                _carCompanyService.DeleteCarCompany(existingCompany);
            }
            else
            {
                throw new KeyNotFoundException($"Car company with Id {id} not found.");
            }
        }
        catch (Exception ex)
        {
            throw new ApplicationException($"Error occurred while deleting car company with Id {id}.", ex);
        }
    }

    private CarCompanyDto MapToDto(CarCompany carCompany)
    {
        return new CarCompanyDto
        {
            Id = carCompany.Id,
            Name = carCompany.Name,
        };
    }
}


Domain Layer
Define the CarCompany entity.
// CarCompany.cs
public class CarCompany
{
    public int Id { get; set; }
    public string Name { get; set; }
}

Infrastructure Layer
Implement the repository, database context, and any other infrastructure concerns.
// CarCompanyDbContext.cs
public class CarCompanyDbContext: DbContext
{
    public DbSet<CarCompany> CarCompanies { get; set; }

    public CarCompanyDbContext(DbContextOptions<CarCompanyDbContext> options) : base(options)
    {
    }

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        // Configure entity properties, relationships, etc.
        modelBuilder.Entity<CarCompany>().HasKey(c => c.Id);
        modelBuilder.Entity<CarCompany>().Property(c => c.Name).IsRequired();
        // Configure other properties...

        // Seed initial data if needed
        modelBuilder.Entity<CarCompany>().HasData(
            new CarCompany { Id = 1, Name = "Company A" },
            new CarCompany { Id = 2, Name = "Company B" }
            // Add other seed data...
        );

        base.OnModelCreating(modelBuilder);
    }
}

// CarCompanyRepository.cs
public class CarCompanyRepository: ICarCompanyRepository
{
    private readonly CarCompanyDbContext _dbContext;

    public CarCompanyRepository(CarCompanyDbContext dbContext)
    {
        _dbContext = dbContext;
    }

    public IEnumerable<CarCompany> GetAll()
    {
        return _dbContext.CarCompanies.ToList();
    }

    public CarCompany GetById(int id)
    {
        return _dbContext.CarCompanies.Find(id);
    }

    public void Add(CarCompany carCompany)
    {
        _dbContext.CarCompanies.Add(carCompany);
        _dbContext.SaveChanges();
    }

    public void Update(CarCompany carCompany)
    {
        _dbContext.CarCompanies.Update(carCompany);
        _dbContext.SaveChanges();
    }

    public void Delete(int id)
    {
        var carCompany = _dbContext.CarCompanies.Find(id);
        if (carCompany != null)
        {
            _dbContext.CarCompanies.Remove(carCompany);
            _dbContext.SaveChanges();
        }
    }
}

// ICarCompanyRepository.cs
public interface ICarCompanyRepository
{
    IEnumerable<CarCompany> GetAll();
    CarCompany GetById(int id);
    void Add(CarCompany carCompany);
    void Update(CarCompany carCompany);
    void Delete(int id);
}


Dependency Injection
Register dependencies in Startup.cs.

public void ConfigureServices(IServiceCollection services)
{
    services.AddScoped<ICarCompanyRepository, CarCompanyRepository>();
    services.AddScoped<ICarCompanyService, CarCompanyService>();
    services.AddScoped<ICarCompanyFacade, CarCompanyFacade>();
}

The implementation follows Clean Architecture principles in an ASP.NET Core Web API application, using the Facade Pattern to encapsulate the complexity of the CarCompany CRUD activities. The presentation layer, represented by the CarCompanyController, is in charge of handling HTTP requests, whilst the application layer introduces the ICarCompanyFacade interface and its implementation, CarCompanyFacade, which is in charge of orchestrating interactions with the underlying services. The CarCompany object is defined in the domain layer, containing the fundamental business logic, while the infrastructure layer handles data access via the CarCompanyRepository and database context. The Startup.cs file uses dependency injection to connect the various components. This structured method improves maintainability, scalability, and testability, allowing for simple system extension and modification in accordance with Clean Architecture principles. As a starting point, and further improvements can be developed based on unique project requirements.

HostForLIFE ASP.NET Core Hosting

European best, cheap and reliable ASP.NET hosting with instant activation. HostForLIFE.eu is #1 Recommended Windows and ASP.NET hosting in European Continent. With 99.99% Uptime Guaranteed of Relibility, Stability and Performace. HostForLIFE.eu security team is constantly monitoring the entire network for unusual behaviour. We deliver hosting solution including Shared hosting, Cloud hosting, Reseller hosting, Dedicated Servers, and IT as Service for companies of all size.



European ASP.NET Core Hosting - HostForLIFE :: In ASP.NET Core, use AddTransient and AddScoped for Repository Registration

clock October 5, 2023 07:57 by author Peter

Microsoft's open-source web framework, ASP.NET Core, provides developers with a versatile and modular platform for developing high-performance web applications. One of the most important components of ASP.NET Core application development is effectively managing dependencies. AddTransient and AddScoped are two often used techniques for registering services in the world of dependency injection, particularly when working with repositories. Choosing between these strategies can have a major impact on your application's behavior and performance. This detailed guide seeks to clarify the distinctions between AddTransient and AddScoped in order to assist developers in making educated decisions when registering repositories in ASP.NET Core apps.

Understanding ASP.NET Core Dependency Injection
DI is a design pattern that encourages loose coupling between components of an application by allowing one object to satisfy the dependencies of another. DI is a critical method in ASP.NET Core for controlling object instantiation and lifespan.

AddTransient: Short-lived Instances
AddTransient is used to register services that are created each time they are requested. In the context of repository registration, this means a new instance of the repository is created every time it is injected into a component such as a controller or a service. Transient services are suitable for lightweight, stateless services or repositories that don’t store any client-specific data.

services.AddTransient<IRepository, Repository>();

AddScoped: Scoped Instances

In contrast, AddScoped generates a single instance of the service for each scope. Each HTTP request generates a scope in the context of web applications. This means that all components sharing the same scoped instance of a service will use the same instance of that service within a single HTTP request. Scoped services are useful for stateful components such as database contexts or repositories that require state to be maintained across several areas of the application within a single request.

services.AddScoped<IRepository, Repository>();

Selecting AddTransient vs. AddScoped

The decision between AddTransient and AddScoped comes down to the desired behavior of your repositories:

When should you use AddTransient?

Statelessness is essential: Using AddTransient is useful if your repository is stateless and does not save any data between method calls. Each method call is assigned a repository instance.
Transient services are appropriate for lightweight operations when the expense of producing a new instance is small in comparison to the benefits of having a fresh instance each time.

Use AddScoped When:
Stateful Operations: If your repository or service maintains state throughout the duration of an HTTP request, using AddScoped ensures that all parts of your application that need the repository within the same request share the same instance.
Database Contexts: When dealing with Entity Framework Core’s DbContext, using AddScoped is crucial. DbContext instances should typically be scoped to the lifetime of a request to ensure data consistency and proper unit of work pattern.

Performance and Memory Usage Considerations
AddTransient is often faster in terms of performance because it does not use tracking scopes. However, in most situations, the difference may be minimal, and the ease and safety afforded by AddScoped frequently outweigh any minor performance improvements.

In terms of memory utilization, AddTransient can cause a greater number of instances to be created, thereby straining memory resources, particularly in high-traffic applications. AddScoped can improve memory usage by reusing instances inside the scope of a request.

The choice between AddTransient and AddScoped for repository registration in ASP.NET Core is determined by your application's individual requirements and characteristics. Understanding the fundamental distinctions and consequences of these technologies is critical for developing efficient, high-performance, and maintainable online applications. You can ensure that your services and repositories operate as intended by selecting the proper lifespan method, resulting in a seamless user experience and optimal resource use.

HostForLIFE ASP.NET Core Hosting

European best, cheap and reliable ASP.NET hosting with instant activation. HostForLIFE.eu is #1 Recommended Windows and ASP.NET hosting in European Continent. With 99.99% Uptime Guaranteed of Relibility, Stability and Performace. HostForLIFE.eu security team is constantly monitoring the entire network for unusual behaviour. We deliver hosting solution including Shared hosting, Cloud hosting, Reseller hosting, Dedicated Servers, and IT as Service for companies of all size.



European ASP.NET Core Hosting - HostForLIFE :: Dependency Injection And Service Lifetime in ASP.NET Core

clock September 19, 2023 08:34 by author Peter

Dependency injection is a technique for getting a dependant object from somewhere other than the class that was created with the new keyword.

Pros

  • It improved modularity.
  • It boosts testability.
  • Place the dependent in a central location.
  • Uncouple the system

The dependency injection (DI) software design pattern, which is a mechanism for accomplishing Inversion of Control (IoC) between classes and their dependencies, is supported by ASP.NET Core.

  • Constructor Injection: The most common method of injecting dependencies into a class by giving them as constructor parameters.
  • Method Injection is the process of injecting dependencies into a method as parameters.
  • Property Injection is the process of populating a class's properties with the necessary dependencies.

We must provide the dependency's lifespan when we register it with DI Container (IServiceCollection).

Service Duration
The service lifetime determines how long an object lives once it is generated by the container. When registering, use the following method on the IServiceColletion to create the lifetime.

  • Services are transient since they are produced each time they are requested.
  • For example, with transitory tea makers, each customer gets a different tea. They get a one-of-a-kind tea experience because a new tea maker arrives for each order and serving.
  • Services are created just once per request.
  • In a teashop, for example, scored tea makers are equivalent to having one tea maker assigned to each table or group, giving the same type of tea to everyone within the group. When a new group arrives, they are assigned a tea maker.
  • Singleton: A service is created only once for the duration of the program. For example, having a singleton tea maker in a teashop is equivalent to having a renowned tea master who provides the same tea to every customer. This tea master is constantly there, remembers all orders, and regularly serves everyone the same tea.

Let's now dive into the code to further explain this concept.

TeaService
public class TeaService : ITeaService
{
        private readonly int _randomId ;
        private readonly Dictionary<int, string> _teaDictionary = new()
        {
            { 1, "Normal Tea ☕️" },
            { 2, "Lemon Tea ☕️" },
            { 3, "Green Tea ☕️" },
            { 4, "Masala Chai ☕️" },
            { 5, "Ginger Tea ☕️" }
        };
 public TeaService()
 {
      _randomId = new Random().Next(1, 5);
  }
  public string GetTea()
   {
      return _teaDictionary[_randomId];

    }
}
public interface ITeaService
{
        string GetTea();
}

RestaurantService: which injects TeaService.
public class RestaurantService : IRestaurantService
{
        private readonly ITeaService _teaService;
        public RestaurantService(ITeaService teaService)
        {
            _teaService = teaService;
        }

        public string GetTea()
        {
            return _teaService.GetTea();
        }
}
public interface IRestaurantService
{
     string GetTea();
 }

Tea Controller: which is injecting TeaService and RestaurantService.
[Route("api/[controller]")]
[ApiController]
public class TeaController : ControllerBase
{
  private readonly ITeaService _teaService;
  private readonly IRestaurantService _restaurantService;

  public TeaController(ITeaService teaService,
   IRestaurantService restaurantService)
  {
      _teaService = teaService;
      _restaurantService = restaurantService;
   }

   [HttpGet]
   public IActionResult Get()
   {
      var tea = _teaService.GetTea();
      var teaFromRestra = _restaurantService.GetTea();
      return Ok($"From TeaService : {tea}
               \nFrom RestaurantService : {teaFromRestra}");
    }
}


Register services to DI Container.

a. Transient
// Add the below line to configure service in Statup.cs
services.AddTransient<ITeaService, TeaService>();
services.AddTransient<IRestaurantService, RestaurantService>();


Output

b. Scoped
// Add the below line to configure service in Statup.cs
services.AddScoped<ITeaService, TeaService>();
services.AddScoped<IRestaurantService, RestaurantService>();


Output

c: Singleton
// Add the below line to configure service in Statup.cs
services.AddSingleton<ITeaService, TeaService>();
services.AddSingleton<IRestaurantService, RestaurantService>();


Output

HostForLIFE ASP.NET Core Hosting

European best, cheap and reliable ASP.NET hosting with instant activation. HostForLIFE.eu is #1 Recommended Windows and ASP.NET hosting in European Continent. With 99.99% Uptime Guaranteed of Relibility, Stability and Performace. HostForLIFE.eu security team is constantly monitoring the entire network for unusual behaviour. We deliver hosting solution including Shared hosting, Cloud hosting, Reseller hosting, Dedicated Servers, and IT as Service for companies of all size.

 



European ASP.NET Core Hosting - HostForLIFE :: Pattern Matching in C# for Simplifying Code

clock September 11, 2023 08:50 by author Peter

Pattern matching is a functional programming feature that is already present in several prominent languages, including Scala, Rust, Python, Haskell, Prolog, and others. It is used to test expressions for certain circumstances while also testing the kinds.

It enables you to check if a value matches a specific pattern and then execute code based on that match in an efficient and simple manner. This capability is very handy when working with complex data structures like collections and when simplifying conditional expressions.

Pattern Matching was introduced in C# 7.

Benefits- Patterns Matching

  • Type-Testing
  • Nullable-type checking
  • Typecasting and assignment
  • High readability
  • Concise syntax Less convoluted code.


Usages

Pattern matching can be used in 2 places.
'is' expressions
'switch' expressions

Patterns Matching Types through C# Versions

C# 7
Type Pattern
Declaration Pattern
Constant Pattern
Null Pattern
Var Pattern

C# 8
Property Pattern
Discard Pattern
Positional Pattern
Discard Pattern

C# 9
Type Pattern
Relative Pattern
Logical Pattern (Combinators)
Negated Null Constant Pattern
Parenthesized Pattern

C# 10
Extended Property Pattern

C# 11
List Pattern

Type Pattern
A type pattern in C# allows you to check whether an object is of a specific type and, if it is, cast it to that type while declaring a new variable.

using System;

public class Program
{
    public static void Main()
    {
        object someObject = "Hello, World!";

        if (someObject is string stringValue)
        {
            // stringValue is now a strongly-typed variable of type string
            Console.WriteLine($"Length of the string: {stringValue.Length}");
        }
        else
        {
            Console.WriteLine("someObject is not a string.");
        }
    }
}

Pattern of Declaration
In C#, a declaration pattern is one that not only examines whether an expression matches a given pattern but also declares a new variable with the matched value. This pattern is frequently used in conjunction with is expressions to accomplish pattern matching as well as variable declaration in a single action.

C# 7.0 added declaration patterns, which provided a handy approach to simplify code.

using System;

public class Program
{
    public static void Main()
    {
        object someObject = 42;

        if (someObject is int intValue)
        {
            // intValue is now a strongly-typed variable of type int
            Console.WriteLine($"The value is an integer: {intValue}");
        }
        else
        {
            Console.WriteLine("The value is not an integer.");
        }
    }
}

Recurring pattern
Testing against a constant value, which can be an int, float, char, string, bool, enum, const-declared field, or null.
It's frequently used in switch statements and pattern-matching contexts to conduct different actions based on an expression's value.

using System;

public class Program
{
    public static void Main()
    {
        object someObject = 42;

        if (someObject is int intValue)
        {
            // intValue is now a strongly-typed variable of type int
            Console.WriteLine($"The value is an integer: {intValue}");
        }
        else
        {
            Console.WriteLine("The value is not an integer.");
        }
    }
}


Null Pattern
Check if a reference or nullable type is null.
It is particularly useful for safely handling null values and reducing null reference exceptions.
Null pattern matching was introduced in C# 9.0 as part of the language's pattern-matching enhancements.

Var Pattern
Similar to the type pattern, the var pattern matches an expression and checks for null, as well as assigns a value to the variable.

The var type is declared based on the matched expression’s compile-time type.

using System;

public class Program
{
    public static void Main()
    {
        object someObject = (42, "Hello, Peter!");

        if (someObject is var (number, message) && number is int && message is string)
        {
            Console.WriteLine($"Number: {number}, Message: {message}");
        }
        else
        {
            Console.WriteLine("Pattern match failed.");
        }
    }
}


Property Pattern
Property pattern matching in C# is a feature that allows you to match objects based on the values of their properties or fields.
It simplifies code by enabling you to specify patterns that involve property values directly in pattern-matching expressions.
Property pattern matching was introduced in C# 8.0 and is a powerful way to work with complex data structures.
using System;

public class Person
{
    public string Name { get; set; }
    public int Age { get; set; }
}

public class Program
{
    public static void Main()
    {
        Person person = new Person { Name = "Alice", Age = 30 };

        if (person is { Name: "Alice", Age: 30 })
        {
            Console.WriteLine("It's Alice, age 30!");
        }
        else
        {
            Console.WriteLine("It's someone else.");
        }
    }
}


Discard Pattern
discard pattern in C# allows you to match a pattern but discard the matched value.
It's represented by the underscore (_) and is especially useful when you want to indicate that you're not interested in the value that matches a pattern, which can help improve code clarity and readability. Discard patterns were introduced in C# 7.0.

using System;

public class Program
{
    public static void Main()
    {
        object someObject = "Hello, World!";

        if (someObject is string _)
        {
            Console.WriteLine("The object is a string, but we're not interested in its value.");
        }
        else
        {
            Console.WriteLine("The object is not a string.");
        }
    }
}


Positional Pattern
Positional patterns in C# allow you to match objects based on the values of their elements in a specific order, making it easier to work with complex data structures like arrays, tuples, or user-defined types.
This feature was introduced in C# 8.0 and provides a concise way to match objects by their elements' positions.

using System;

public class Program
{
    public static void Main()
    {
        Point point = new Point(3, 4);

        string location = DescribePoint(point);

        Console.WriteLine(location);
    }

    public static string DescribePoint(Point point)
    {
        return point switch
        {
            (0, 0) => "The point is at the origin (0, 0).",
            (var x, var y) when x == y => $"The point is on the diagonal at ({x}, {y}).",
            (var x, var y) => $"The point is at ({x}, {y}).",
            _ => "Unknown location."
        };
    }
}

public record Point(int X, int Y);


Tuple Pattern
Tuple patterns in C# allow you to match objects against specific tuple structures. This feature simplifies the process of deconstructing and matching tuples in pattern-matching expressions.
Tuple patterns were introduced in C# 8.0 and make it easier to work with complex data structures involving tuples.

using System;

public class Program
{
    public static void Main()
    {
        var point = (3, 4);

        string location = DescribePoint(point);

        Console.WriteLine(location);
    }

    public static string DescribePoint((int X, int Y) point)
    {
        return point switch
        {
            (0, 0) => "The point is at the origin (0, 0).",
            (_, 0) => "The point is on the x-axis.",
            (0, _) => "The point is on the y-axis.",
            var (x, y) when x == y => $"The point is on the diagonal at ({x}, {y}).",
            var (x, y) => $"The point is at ({x}, {y}).",
        };
    }
}


var person = ("Alice", 30);

var description = person switch
{
    ("Alice", 30) => "This is Alice, age 30.",
    ("Bob", var age) => $"This is Bob, age {age}.",
    _ => "Unknown person."
};

C#
 ‘Enhanced’ Type Pattern

    You can do type checking in switch expressions without using the discards with each type

public string CheckValueType(object value)=> value switch
{
  int => "integer number",
  decimal => "decimal number",
  double => "double number",
  _ => throw new InvalidNumberException(value)
};


Pattern matching is a powerful feature in C# that simplifies code by allowing you to match objects and structures based on patterns. Whether you're checking types, values, or even properties, pattern matching makes your code more concise and readable.

Pattern matching in C# streamlines your code, reduces errors, and enhances readability, making it a valuable tool for developers.

HostForLIFE ASP.NET Core Hosting

European best, cheap and reliable ASP.NET hosting with instant activation. HostForLIFE.eu is #1 Recommended Windows and ASP.NET hosting in European Continent. With 99.99% Uptime Guaranteed of Relibility, Stability and Performace. HostForLIFE.eu security team is constantly monitoring the entire network for unusual behaviour. We deliver hosting solution including Shared hosting, Cloud hosting, Reseller hosting, Dedicated Servers, and IT as Service for companies of all size.

 




European ASP.NET Core Hosting - HostForLIFE :: Using the NavigationPage in.NET MAUI

clock September 5, 2023 08:40 by author Peter

This tutorial will teach us about the NavigationPage in.NET MAUI. If you are new to MAUI, I recommend that you read the articles in this series listed below. One of the most important components of developing an application is navigation. The NavigationPage class in.NET MAUI provides a hierarchical navigation experience for navigating through pages. The navigation is provided as a LIFO (Last-In, First-Out) stack of page objects by NavigationPage. To demonstrate, I'll add three ContentPages to the.NET MAUI project and demonstrate how to navigate from one page to the next. The most frequent page type in.NET MAUI is the ContentPage, which is a single view, and a single.NET MAUI application can contain numerous pages derived from the ContentPage.

Let's create three.NET MAUI ContentPages (XAML) in a.NET MAUI project. I called the three ContentPages HomePage, ProductPage, and ProductDetails page.

A root page is required for every app with several pages. Now, let's make the HomePage the Navigation stack's root page. To accomplish this, we must associate the App.Main page property with the NavigationPage object, which constructor accepts the root page as a parameter, i.e. the App's HomePage.

Now, add a button (named btnGoToProductPage) to navigate from the HomePage to ProductPage.

HomePage.xaml

<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="NavigationPageDemo.HomePage"
             Title="Home Page">
    <VerticalStackLayout>
        <Label Text="Home Page Content"
               VerticalOptions="Center"
               HorizontalOptions="Center"
               Margin="10" />
        <Button x:Name="btnGoToProductPage"
                Text="Go to Product Page"
                Clicked="btnGoToProductPage_Clicked"
                Margin="10" />
    </VerticalStackLayout>
</ContentPage>


A page can be navigated by calling the PushAsync method on the Navigation property of the Current Page. In the below example, ProductPage is pushed onto the Navigation stack where it becomes the active page.

HomePage.xaml.cs
using System;
using Microsoft.Maui.Controls;
namespace NavigationPageDemo
{
    public partial class HomePage : ContentPage
    {
        public HomePage()
        {
            InitializeComponent();
        }
        private void btnGoToProductPage_Clicked(object sender, EventArgs e)
        {
            Navigation.PushAsync(new ProductPage());
        }
    }
}


In ProductPage, I have added two buttons named “btnGoToProductDetails” and ”btnGoBackToHomePage”. On clicking on btnGoToProductDetails, the ProductDetails page will be added to the navigation stack, and it will become the active page. On clicking on btnGoBackToHomePage, the PopAsync method will remove the current page i.e., Product Page, from the navigation stack, and the topmost page of the stack will become the active page.

ProductPage.xaml
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="NavigationPageDemo.ProductPage"
             Title="Product Page">
    <VerticalStackLayout>
        <Label Text="Product Page"
               VerticalOptions="Center"
               HorizontalOptions="Center"
               Margin="10" />
        <Button x:Name="btnGoToProductDetails"
                Text="Go to Product Details"
                Clicked="btnGoToProductDetails_Clicked"
                Margin="10" />
        <Button x:Name="btnGoBackToHomePage"
                Text="Go back to Home Page"
                Clicked="btnGoBackToHomePage_Clicked"
                Margin="10" />
    </VerticalStackLayout>
</ContentPage>

ProductPage.xaml.cs
using System;
using Microsoft.Maui.Controls;
namespace NavigationPageDemo
{
    public partial class ProductPage : ContentPage
    {
        public ProductPage()
        {
            InitializeComponent();
        }
        private void btnGoToProductDetails_Clicked(object sender, EventArgs e)
        {
            Navigation.PushAsync(new ProductDetails());
        }
        private void btnGoBackToHomePage_Clicked(object sender, EventArgs e)
        {
            Navigation.PopAsync();
        }
    }
}

On the ProductDetails Page, I have added a button i.e. btnGoBackToProductPage. On Clicking, it will remove the current page from the navigation stack with the PopAsync method call.

ProductDetails.xaml

<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="NavigationPageDemo.ProductDetails"
             Title="Product Details">
    <VerticalStackLayout>
        <Label Text="Product Details"
               VerticalOptions="Center"
               HorizontalOptions="Center"
               Margin="10" />
        <Button x:Name="btnGoBackToProductPage"
                Text="Go back to Product Page"
                Clicked="btnGoBackToProductPage_Clicked"
                Margin="10" />
    </VerticalStackLayout>
</ContentPage>


ProductDetails.xaml.cs

using System;
using Microsoft.Maui.Controls;
namespace NavigationPageDemo
{
    public partial class ProductDetails : ContentPage
    {
        public ProductDetails()
        {
            InitializeComponent();
        }
        private void btnGoBackToProductPage_Clicked(object sender, EventArgs e)
        {
            Navigation.PopAsync();
        }
    }
}


Working Preview on Android

Preview on Windows

The navigation property of the page also provides the InsertPageBefore and RemovePage methods for manipulating the Stack by inserting the pages or removing them.

.NET MAUI also supports Modal navigation. A modal page encourages users to complete a self-contained task that cannot be navigated away until the task is completed or canceled. PushModalAsync and PopModalAsync are the methods to push and pop pages from the modal stack.

NavigationPage has several properties; a few are listed below. (For more details, you can refer to the documentation on Microsoft's official website)
1. BarBackgroundColor: Specifies the background color of the Navigation Bar.
2. BarTextColor: Specifies the Text color of the Navigation Bar
3. HasNavigationBar: Specifies whether a navigation bar is present on the NavigationPage. Its default value is true.
4. HasBackButton: Represent whether the navigation bar includes the back button. The default value of this property is true.

Let’s try to change the navigation bar and text color. Use the below code in the App class; we can change the BarBackground and BarTextColor.


Preview on Android

Preview on Windows


HostForLIFE ASP.NET Core Hosting

European best, cheap and reliable ASP.NET hosting with instant activation. HostForLIFE.eu is #1 Recommended Windows and ASP.NET hosting in European Continent. With 99.99% Uptime Guaranteed of Relibility, Stability and Performace. HostForLIFE.eu security team is constantly monitoring the entire network for unusual behaviour. We deliver hosting solution including Shared hosting, Cloud hosting, Reseller hosting, Dedicated Servers, and IT as Service for companies of all size.


 



European ASP.NET Core Hosting - HostForLIFE :: Using ASP.NET Core 7.0 to Create a Bulk Email Sending Console App

clock August 28, 2023 07:35 by author Peter

We will look at how to build a powerful console application for sending bulk emails with the latest ASP.NET Core 7.0 framework and smtp server. Businesses frequently want a streamlined approach to send emails to a big number of recipients due to the ever-increasing necessity for effective communication. You will learn how to use the features of ASP.NET Core 7.0 to create a dependable bulk email sending solution by following this step-by-step guide.

Step 1: Install Any Necessary Software
Make sure your system has Visual Studio Community 2022 and SQL Server Management Studio (SSMS) installed. You can get them through Microsoft's official websites.

Step 2. Create a New Console Application

  • Navigate to Visual Studio Community 2022.
  • Select "Create a new project."
  • Search for "Console" in the "Create a new project" dialog's search field.
  • Choose "Console App (.NET Core)" as the template.
  • Give your project a name and a location, then click "Create."

3. Launch SQL Server Management Studio.

  • On your computer, launch SQL Server Management Studio.
  • Connect to your SQL Server instance by using the proper server name and authentication method (Windows or SQL Server).

Step 4: Make a New Database.

  • Right-click on "Databases" in the Object Explorer window and select "New Database."
  • In the "New Database" window, in the "Database name" area, provide a name for your database.
  • If necessary, configure other parameters such as data file locations.
  • To build the database, click the "OK" button.

Here's an example

CREATE DATABASE bulkEmailDemoDB;

Step 5. Create a New TableExpand the newly created database in the Object Explorer window.Right-click on "Tables" within your database, and then select "New Table."In the

Table Designer window:
Define the columns for your table. For each column, specify a name, data type, length (if applicable), and other properties.
Click the "Save" icon (or press Ctrl + S) to save the table.
Provide a name for your table and click the "OK" button to create it.

Here's an example
Choose the table name as per your requirement
CREATE TABLE ClientMailReminder (
    ClientCode VARCHAR(255),
    EmailId VARCHAR(255) NOT NULL,
    PhoneNumber VARCHAR(20) NOT NULL,
    Status VARCHAR(50)
);


Now insert the dummy data for demo purposes. In your table, you can insert genuine record
INSERT INTO ClientMailReminder (ClientCode, EmailId, PhoneNumber, Status)
VALUES
    ('CLNT001', '[email protected]', '1234567890', 'Active'),
    ('CLNT002', '[email protected]', '9876543210', 'Inactive'),
    -- ... (continue for the remaining records)
    ('CLNT020', '[email protected]', '5555555555', 'Active');


Create a model class.
public class ClientMailRemainder
{
    public string? ClientCode { get; set; }
    public string EmailId { get; set; }
    public string PhoneNumber { get; set; }
    public string? Status { get; set; }
}

Let's Install Required NuGet Packages:
    Microsoft.EntityFrameworkCore
    Microsoft.EntityFrameworkCore.SqlServer

Create BulkEmailContext Class:
Next, create a class named BulkEmailContext that inherits from DbContext. This class represents your database context and provides the DbSet properties for your entities.
using Microsoft.EntityFrameworkCore;

public class BulkEmailContext : DbContext
{
    public BulkEmailContext(DbContextOptions<BulkEmailContext> options) : base(options)
    {
    }

    // DbSet properties for your entities
    public DbSet<ClientMailReminder> ClientMailReminders { get; set; }

}


Configure Program.cs (for ASP.NET Core 7.0):
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Hosting;

namespace Yournamespace;

class Program
{

    static async Task Main(string[] args)
    {
        HostApplicationBuilder builder = Host.CreateApplicationBuilder(args);

        var options = new DbContextOptionsBuilder<EmailDbContext>().UseSqlServer("your connection string").Options;
        using (var context = new EmailDbContext(options)) // Create your EmailDbContext instance
        {
            await BulkEmail.GetEmailAsync(context); // Call the static method

            Console.WriteLine("Bulk email and mobile sending completed."); // Optional: Print a message
        }



    }
}


Create a BulkEmail.cs file
public static async Task GetEmailAndMobileNumberAsync(EmailDbContext context)
{
    var activeUserEmails = await _context.ClientMailRemainder
    .Where(e => e.Status == "Active")
    .Select(e => e.EmailId)
    .ToListAsync();

    string subject = " DotNet Reminder";
    string content = "<html><body>DotNet meetup reminder</body></html>";
    List<string> emailRecipients = activeUsers.Select(user => user.Email).ToList();
    int counts = context.ClientMailRemainder.Count();
    await SendEmailsInBatchesAsync(counts, emailRecipients, subject, content);
}


Implementing SendEmailsInBatchesAsync method
public static async Task SendEmailsInBatchesAsync(int count,List<string> emailAddresses, string subject, string content, int batchSize = 100)
{
    ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12 | SecurityProtocolType.Tls13;

    var smtpClients = new List<SmtpClient>();

    // Determine the total number of rows in the database table
    int totalRowCount = count; // To count table record

    // Calculate the number of batches needed
    int totalBatches = (int)Math.Ceiling((double)totalRowCount / batchSize);

    for (int i = 0; i < totalBatches; i++)
    {
        SmtpClient smtpClient = new SmtpClient("your");
        smtpClient.Port = 587;
        smtpClient.Credentials = new NetworkCredential("your", "your");
        smtpClients.Add(smtpClient);
    }

    var tasks = new List<Task>();

    int emailsSentCount = 0;

    for (int batchIndex = 0; batchIndex < totalBatches; batchIndex++)
    {
        var batch = emailAddresses.Skip(batchIndex * batchSize).Take(batchSize).ToList();
        int startIndex = batchIndex * batchSize;

        tasks.Add(Task.Run(async () =>
        {
            int clientIndex = startIndex / batchSize;

            using (var client = smtpClients[clientIndex])
            {
                for (int j = 0; j < batch.Count; j++)
                {
                    var emailAddress = batch[j];
                    var clientCode = clientCodes[startIndex + j];

                    using (var message = new MailMessage())
                    {
                        message.From = new MailAddress("your");
                        message.Subject = subject;
                        message.Body = content;
                        message.IsBodyHtml = true;
                        message.To.Add(emailAddress);

                        try
                        {
                            await client.SendMailAsync(message);
                            Interlocked.Add(ref emailsSentCount, 1);
                            Console.WriteLine($"Email sent successfully to: {emailAddress}");
                            //emailsSentCount++;
                            Console.WriteLine($"Total emails sent: {emailsSentCount}");
                        }
                        catch (Exception ex)
                        {
                            Console.WriteLine($"An error occurred while sending email to {emailAddress}: {ex.Message}");
                        }
                    }
                }
            }
        }));
    }

    await Task.WhenAll(tasks);

    // Dispose all SmtpClient instances
    foreach (var client in smtpClients)
    {
        client.Dispose();
    }
}


The formula (int)Math.Ceiling((double)totalRowCount / batchSize) calculates how many batches you'll need, ensuring you round up to cover all emails.

Loop Through Batches and Initialize SMTP Clients
The code then enters a loop that runs for the total number of batches calculated. Inside the loop, an instance of the SmtpClient class is created and configured for each batch. we are  attempting to distribute the work of sending emails among multiple SMTP clients (perhaps to parallelize the process),

Inside the Task.Run delegate, the code manages sending emails within a batch. It gets the SMTP client based on the batch index, iterates through the batch of email addresses, and sends emails.

The Interlocked.Add(ref emailsSentCount, 1); line ensures that the emailsSentCount is incremented in a thread-safe manner, as multiple tasks might be updating it simultaneously.
 await Task.WhenAll(tasks); waits for all the asynchronous email sending tasks to complete before moving on.

After all the email sending tasks have completed, the code disposes of the SMTP client instances to release resources.



About HostForLIFE

HostForLIFE is European Windows Hosting Provider which focuses on Windows Platform only. We deliver on-demand hosting solutions including Shared hosting, Reseller Hosting, Cloud Hosting, Dedicated Servers, and IT as a Service for companies of all sizes.

We have offered the latest Windows 2019 Hosting, ASP.NET 5 Hosting, ASP.NET MVC 6 Hosting and SQL 2019 Hosting.


Month List

Tag cloud

Sign in