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 :: 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.



European ASP.NET Core Hosting - HostForLIFE :: Improving the Performance of Your.NET Core Application

clock August 25, 2023 07:45 by author Peter

In this post, we will look at the best techniques for increasing the speed of your.NET core application.

It is critical to optimize the performance of your.NET Core application to ensure that it provides a responsive and efficient user experience. Here are some suggested practices for optimizing the performance of your.NET Core application:

1. Make Use of Profiling Tools

Profiling tools like as Visual Studio Profiler, JetBrains dotTrace, and PerfView can assist you in locating bottlenecks and performance issues in your code.
Using a stopwatch to measure method performance is an example.
using System;
using System.Diagnostics;

class Program
{
    static void Main(string[] args)
    {
        Stopwatch stopwatch = new Stopwatch();
        stopwatch.Start();

        // Code to profile

        stopwatch.Stop();
        Console.WriteLine($"Elapsed Time: {stopwatch.ElapsedMilliseconds} ms");
    }
}

2. Caching
Implement caching for frequently accessed data to reduce database load and improve response times. .NET Core has a variety of caching methods, including as in-memory caching and distributed caching using libraries such as Memory Cache or Redis.

Example: Using MemoryCache for in-memory caching.

using System;
using Microsoft.Extensions.Caching.Memory;

class Program
{
    static void Main(string[] args)
    {
        IMemoryCache cache = new MemoryCache(new MemoryCacheOptions());

        // Store data in cache
        cache.Set("myKey", "myValue", TimeSpan.FromMinutes(10));

        // Retrieve data from cache
        if (cache.TryGetValue("myKey", out string value))
        {
            Console.WriteLine($"Cached Value: {value}");
        }
    }
}

3. Database Optimization
Optimize your database queries using proper indexing, query optimization techniques, and stored procedures.
Implement connection pooling to reuse database connections and reduce overhead.

Example: Using proper indexing in Entity Framework Core.

using System;
using System.Linq;
using Microsoft.EntityFrameworkCore;

class Program
{
    static void Main(string[] args)
    {
        var options = new DbContextOptionsBuilder<MyDbContext>()
            .UseSqlServer(connectionString)
            .Options;

        using (var context = new MyDbContext(options))
        {
            // Apply indexing to optimize queries
            var results = context.Orders.Where(o => o.CustomerId == 123).ToList();
        }
    }
}

4. Asynchronous Programming
Use asynchronous programming (async/await) to offload CPU-bound work and improve responsiveness, especially in I/O-bound scenarios.
Utilize asynchronous database drivers and libraries for improved database performance.

Example: Using async/await to perform I/O-bound tasks asynchronously.
using System;
using System.Net.Http;
using System.Threading.Tasks;

class Program
{
    static async Task Main(string[] args)
    {
        using (HttpClient client = new HttpClient())
        {
            HttpResponseMessage response = await client.GetAsync("https://example.com");
            string content = await response.Content.ReadAsStringAsync();
            Console.WriteLine(content);
        }
    }
}

5. Use Entity Framework Core Wisely
If you're using Entity Framework Core for database access, be mindful of the queries it generates. Use eager loading, projections, and optimizations like compiled queries.

Example: Using compiled queries in Entity Framework Core.

using System;
using System.Linq;
using Microsoft.EntityFrameworkCore;

class Program
{
    static void Main(string[] args)
    {
        var options = new DbContextOptionsBuilder<MyDbContext>()
            .UseSqlServer(connectionString)
            .Options;

        using (var context = new MyDbContext(options))
        {
            var compiledQuery = EF.CompileQuery((MyDbContext db, int customerId) =>
                db.Orders.Where(o => o.CustomerId == customerId).ToList());

            var results = compiledQuery(context, 123);
        }
    }
}

6. Memory Management
Minimize object allocations and memory usage. Use value types where appropriate and be cautious with large object graphs.
Utilize the Dispose pattern or use statements for resources like database connections or streams to ensure timely cleanup.
Example: Disposing resources using the Dispose pattern.

using System;

class MyResource : IDisposable
{
    private bool disposed = false;

    public void Dispose()
    {
        Dispose(true);
        GC.SuppressFinalize(this);
    }

    protected virtual void Dispose(bool disposing)
    {
        if (!disposed)
        {
            if (disposing)
            {
                // Release managed resources
            }

            // Release unmanaged resources

            disposed = true;
        }
    }

    ~MyResource()
    {
        Dispose(false);
    }
}

7. HTTP Caching
Leverage HTTP caching mechanisms (ETags, Last-Modified headers) to reduce unnecessary data transfers in web applications.
Example: Adding caching headers to HTTP responses.

using Microsoft.AspNetCore.Mvc;
public class MyController : Controller
{
    [HttpGet]
    [ResponseCache(Duration = 300)] // Cache for 5 minutes
    public IActionResult Index()
    {
        // Generate and return response
    }
}

8. Minimize Round-Trips
Reduce the number of HTTP requests and database round-trips. Combine multiple requests when possible.
Example: Combining multiple database queries into a single query.

using System;
using System.Linq;
using Microsoft.EntityFrameworkCore;

class Program
{
    static void Main(string[] args)
    {
        var options = new DbContextOptionsBuilder<MyDbContext>()
            .UseSqlServer(connectionString)
            .Options;

        using (var context = new MyDbContext(options))
        {
            var orders = context.Orders
                .Include(o => o.Customer)
                .Include(o => o.Products)
                .Where(o => o.CustomerId == 123)
                .ToList();
        }
    }
}

9. Content Delivery Networks (CDNs)
Offload static assets (CSS, JavaScript, images) to CDNs for faster delivery to users.
Example: Using a CDN for delivering static assets.

<!-- Link to static asset on CDN -->
<link rel="stylesheet" href="https://cdn.example.com/styles.css">

10. Compression
Enable GZIP or Brotli compression for HTTP responses to reduce data transfer size.
Example: Enabling GZIP compression for HTTP responses.

using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.ResponseCompression;

public void ConfigureServices(IServiceCollection services)
{
    services.AddResponseCompression(options =>
    {
        options.EnableForHttps = true;
        options.Providers.Add<GzipCompressionProvider>();
    });
}

11. Logging and Tracing
Use logging levels wisely. Avoid excessive logging in production.
Implement distributed tracing to monitor performance across microservices.

Example: Using a distributed tracing library for monitoring.
using Microsoft.ApplicationInsights;
using Microsoft.ApplicationInsights.Extensibility;

var configuration = TelemetryConfiguration.Active;
var telemetryClient = new TelemetryClient(configuration);

using (var operation = telemetryClient.StartOperation<RequestTelemetry>("MyOperation"))
{
// Perform operation

operation.Telemetry.Success = true;
}


12. Code Analysis and Reviews
Regularly review your codebase for performance issues. Use tools like ReSharper or SonarQube for static code analysis.

code analysis and reviews are essential practices for identifying and addressing code quality, maintainability, and performance issues in your .NET Core application. Code analysis involves using automated tools and manual inspection to review your codebase for potential problems, while code reviews involve the collaborative evaluation of code changes by your development team.

Here's a more detailed explanation of code analysis and reviews:

Code Analysis
Code analysis involves using specialized tools to automatically scan your codebase for potential issues, violations of coding standards, and best practices. These tools can help identify bugs, security vulnerabilities, performance bottlenecks, and other code quality concerns.

Benefits of Code Analysis
Consistency: Code analysis enforces coding standards, ensuring a consistent codebase across your application.
Early Detection: It helps catch issues early in the development process, reducing the likelihood of bugs reaching production.
Efficiency: Automated tools can quickly identify common issues, saving time during manual reviews.
Maintainability: Code analysis improves the long-term maintainability of your application by identifying areas that might become problematic.

Example (Using Roslyn Code Analysis)
The Roslyn compiler platform includes built-in analyzers that can be used to perform code analysis in Visual Studio. You can install additional analyzers from NuGet packages.

Example: Applying code analysis recommendations with ReSharper.
// Example of a code analysis warning

public class ExampleClass
{
public void DoSomething(string input)
{
    if (input == null) // CA1062: Validate arguments of public methods
    {
        throw new ArgumentNullException(nameof(input));
    }

    // Code logic
}
}

13. Parallelism and Concurrency
Utilize parallelism and multithreading for CPU-bound tasks using Parallel class or Task Parallel Library (TPL).
Be cautious with thread synchronization to avoid deadlocks and contention.
Example: Using parallelism for CPU-bound tasks.

Parallel.For(0, 10, i =>
{
// Perform parallelized work
});

14. Resource Optimization
Optimize images and assets for the web to reduce load times.
Minimize the number of external dependencies and libraries.

Example: Optimizing images for the web.
<!-- Optimized image tag -->
<img src="images/my-image.jpg" alt="My Image">


15. Benchmarking and Load Testing
Perform benchmarking and load testing to identify performance bottlenecks and determine how your application performs under different loads.

Benchmarking involves measuring the performance of specific components or functions, while load testing simulates various levels of user traffic to evaluate how well your application handles the load. Both practices help identify bottlenecks, scalability issues, and potential improvements.

Here's a more detailed explanation of benchmarking and load testing:

Benchmarking

Benchmarking involves running specific tests on critical parts of your application to measure their performance. The goal is to establish a baseline and identify areas for improvement. For example, you might benchmark a specific algorithm, database query, or code snippet to compare different implementations and determine which one performs better.

Steps for Benchmarking

  • Identify the specific component, function, or operation you want to benchmark.
  • Design a set of controlled tests that exercise the component under different scenarios.
  • Measure and record performance metrics such as execution time, memory usage, CPU utilization, etc.
  • Analyze the results and identify opportunities for optimization.

Example: Using a load testing tool to simulate traffic.

Benchmarking an Algorithm

public class AlgorithmBenchmark
{
public void RunBenchmark()
{
    Stopwatch stopwatch = new Stopwatch();

    stopwatch.Start();

    // Run the algorithm multiple times and measure the time taken
    for (int i = 0; i < 10000; i++)
    {
        // Call the algorithm being benchmarked
        SomeAlgorithm.Perform();
    }

    stopwatch.Stop();

    Console.WriteLine($"Time taken: {stopwatch.ElapsedMilliseconds} ms");
}
}


16. Deployment and Infrastructure
Use containerization (Docker) to ensure consistent deployment environments.
Leverage cloud services and auto-scaling for handling varying traffic loads.
Example: Deploying an application using Docker.

17. Regular Updates
Keep your dependencies, frameworks, and libraries up to date to benefit from performance improvements and bug fixes.
Example: Keeping NuGet packages up to date.

18. Code Profiling and Performance Monitoring

Continuously monitor your application's performance in production using tools like Application Insights, New Relic, or Dynatrace.
Example: Integrating Application Insights for monitoring.
using Microsoft.ApplicationInsights;
using Microsoft.ApplicationInsights.Extensibility;

var configuration = TelemetryConfiguration.Active;
var telemetryClient = new TelemetryClient(configuration);

// Track custom telemetry events
telemetryClient.TrackEvent("CustomEventName");


Here are some additional tips

  • Use the latest version of .NET Core.
  • Use a lightweight framework.
  • Use a good IDE.
  • Write clean and well-structured code.
  • Use a debugger to find and fix performance problems.
  • Monitor the application's performance and make changes as needed.

Remember that the specific optimizations needed for your application may vary based on its nature and requirements. It's important to profile, measure, and test your application to ensure that the changes you make have a positive impact on its performance.

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 :: ASP.NET Core 7.0 Document Viewer Capabilities

clock August 21, 2023 07:54 by author Peter

This post will show you how to use Visual Studio Community 2022 to construct a Document Viewer in an Asp.Net Core 7.0 application.

What exactly is GroupDocs.Viewer?

GroupDocs.Viewer is a document viewing and rendering package created by GroupDocs, a business that specializes in document manipulation and conversion APIs for.NET and Java. GroupDocs.Viewer is intended to assist developers in incorporating document viewing capabilities into their applications, allowing users to read a variety of documents right within the application's interface without the need to download or open them with other software.

Let's get started with the document viewer.
In _Layout.html, import the bootstrap 5 cdn.

Install the Nuget Package GroupDocs.Viewer

Make a fresh ASP.NET CORE MVC project.
DocumentViewer.Application is the name of the project.
In the DocumentViewer.Application project, add a new controller.

public class DocViewerController : Controller
{
    private readonly IHostingEnvironment _hostingEnvironment;
    private string projectRootPath;
    private string outputPath;
    private string storagePath;
    List<string> lstFiles;

    public DocViewerController(IHostingEnvironment hostingEnvironment)
    {
        _hostingEnvironment = hostingEnvironment;
        projectRootPath = _hostingEnvironment.ContentRootPath;
        outputPath = Path.Combine(projectRootPath, "wwwroot/Content");
        storagePath = Path.Combine(projectRootPath, "storage");
        lstFiles = new List<string>();
    }

    public IActionResult Index()
    {
        var files = Directory.GetFiles(storagePath);
        foreach (var file in files)
        {
            lstFiles.Add(Path.GetFileName(file));
        }
        ViewBag.lstFiles = lstFiles;
        return View();
    }
    [HttpPost]
    public IActionResult OnPost(string FileName)
    {
        int pageCount = 0;
        string imageFilesFolder = Path.Combine(outputPath, Path.GetFileName(FileName).Replace(".", "_"));
        if (!Directory.Exists(imageFilesFolder))
        {
            Directory.CreateDirectory(imageFilesFolder);
        }
        string imageFilesPath = Path.Combine(imageFilesFolder, "page-{0}.png");
        using (Viewer viewer = new Viewer(Path.Combine(storagePath, FileName)))
        {
            //Get document info
            ViewInfo info = viewer.GetViewInfo(ViewInfoOptions.ForPngView(false));
            pageCount = info.Pages.Count;
            //Set options and render document
            PngViewOptions options = new PngViewOptions(imageFilesPath);
            viewer.View(options);
        }
        return new JsonResult(pageCount);
    }
}

The method marked with the [HttpPost] tag, which indicates that it responds to HTTP POST requests, lies at the heart of this code. The method accepts a FileName parameter, which is the name of the uploaded file. The method returns an IActionResult, which allows for the return of many forms of replies, such as JSON, views, or redirects.

The code starts by creating a folder in which to save the created PNG images. The name of the folder is determined by the FileName option, with any dots in the filename replaced by underscores. If the folder does not already exist, the code uses the Directory to create it.The method CreateDirectory.

By combining the storage location and the FileName parameter, the using block is utilized to generate a Viewer object. This Viewer object is responsible for interacting with the document file.

For saving images, a PngViewOptions object is created and specified using the imageFilesPath pattern. The created choices are then passed to the View method of the viewer. This phase transforms the pages of the document as PNG images and saves them to the chosen folder.

The pageCount variable, which reflects the total number of pages in the document, is returned in the JSON response. The client or caller can utilize this JSON response to obtain this information.

Create an Index.cshtml file now.
In index.cshtml, we use an Ajax call.

@{
}


<script src="http://code.jquery.com/jquery-1.8.2.js"></script>
<script>
    function ViewDocument(file) {
        $("#loader").fadeIn();
        var data = { FileName: file };
        $.ajax({
            type: "POST",
            url: '/DocViewer/OnPost',
            data: data,
            dataType: "text"
        }).done(function (data) {
            var folderName = file.replace(".", "_");
            $("#content").empty();
            for (var i = 1; i <= data; i++) {
                $("#content").append("<img class='img-fluid' src='Content/" + folderName + "/page-" + i + ".png'/>");

            }
            $("#loader").fadeOut();
        })
    }
</script>
<script type="text/javascript">
    $(window).load(function () {
        $("#loader").fadeOut(1000);
    });
</script>
<div class="container">
    <div class="row">
        <div class="col-md-3">
            <div class="sidenav bg-light p-3">
                <div id="loader"></div>
                <h2 class="ps-3">Files</h2>
                @if (ViewBag.lstFiles != null)
                {
                    @foreach (string file in ViewBag.lstFiles)
                    {
                        <a href="#" onclick="ViewDocument('@file')" class="d-block">@file</a>
                    }
                }
            </div>
        </div>
        <div class="col-md-9">
            <h2>Preview</h2>
            <div id="content" class="border p-3"></div>
        </div>
    </div>
</div>


Output:
Image preview

Document file preview


GroupDocs.Viewer is a software development tool that offers APIs and libraries for viewing and visualizing different sorts of documents and files within applications. It enables developers to incorporate document viewing features into their apps without requiring users to install the native applications that generated those documents. The application supports a variety of document formats, including PDF, Microsoft Office (Word, Excel, PowerPoint), pictures, AutoCAD files, and others.

 

 



European ASP.NET Core Hosting :: How to Build Simple and Organized APIs in.NET 7 Using Minimal APIs and MapGroup() ?

clock August 16, 2023 09:19 by author Peter

The current version of Microsoft's popular cross-platform programming framework is.NET 7. Minimal APIs, a new technique to construct lightweight, quick, and simple APIs with just a few lines of code, is one of the new features introduced in.NET 7. In this post, we'll look at how to use Minimal APIs in.NET 7, as well as how to add MapGroup() to a static class.

What exactly are Minimal APIs?

Minimal APIs are a new type of API introduced in.NET 7, allowing developers to construct APIs with minimal overhead and optimal efficiency. They are lightweight and simple to use, with an emphasis on simplicity and ease of development.How to create a Minimal API in .NET 7?

Creating a Minimal API in .NET 7 is simple. Here’s an example of how to create a Minimal API that returns “Hello World!” when you make a GET request to the root URL:
var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();
app.MapGet("/", () => "Hello World!");
app.Run();

In this example, we’ve used the WebApplication class to create a new Minimal API. We've then used the MapGet() method to map a GET request to the root URL ("/") and return "Hello World!".
Adding MapGroup() to a static class

MapGroup() allows you to group similar endpoints and apply shared middleware or configuration to them. To add MapGroup() to a static class, follow these steps:

1. Create a static class for your endpoints
public static class MyEndpoints
{
    public static void MapGroup(this IEndpointRouteBuilder endpoints)
    {
        endpoints.MapGet("/", Get).WithName("Get").WithOpenApi();

        endpoints.MapGet("/api/customers", GetCustomers).WithName("Customers").WithOpenApi();

        // Add more endpoints here
    }

    private static IResult Get()
    {
        return Results.Ok("Hello World!");
    }

    private static IResult GetCustomers()
    {
        return Results.Ok("List of customers");
    }
}


2. Add a MapGroup() call your endpoint configuration in the Startup class, and configure OpenAPI and Swagger services.
var builder = WebApplication.CreateBuilder(args);

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

var app = builder.Build();

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

app.UseHttpsRedirection();
app.MapGroup();
app.Run();


In this example, we’ve added a call to MapGroup() and passed in an empty string as the group prefix and the MapGroup() method from our MyEndpoints static class.

Now, all the endpoints defined in MyEndpoints the class will be grouped under the specified prefix, which in this case, is an empty string. You can add a different prefix to group endpoints together and use the same prefix in your middleware or configuration for all endpoints in the group.

With MapGroup(), you can create modular and organized APIs with shared middleware and configuration for groups of endpoints.

Minimal APIs in.NET 7 make it simple to write lightweight, quick APIs with only a few lines of code. You can group comparable endpoints and apply shared middleware or configuration to them by adding MapGroup() to a static class. You can use these characteristics to construct simple and organized APIs that are straightforward to design and maintain.



European ASP.NET Core Hosting :: Action Injection in WebAPI

clock August 7, 2023 10:30 by author Peter

In ASP.NET Core WebAPI, action injection refers to the process of injecting services directly into a controller's action methods. It enables you to get the services needed for a specific action method without having to inject them into the controller's constructor.

Services are often injected into a controller's constructor and are available for use throughout all action methods inside that controller in traditional dependency injection (DI). However, there may be times when you simply require a service within a specific action method. In such cases, action injection can be used to directly inject the required service into the method's argument.

In ASP.NET Core, the attribute '[FromServices]' is used to inject services straight into action methods of your controllers.

The [FromServices] attribute for action injection has been available since the initial release of ASP.NET Core, which is ASP.NET Core 1.0. It has been a part of the framework since its inception and is used to inject services directly into action methods within controllers.

Here is a way to employ the [FromServices] attribute within an ASP.NET Core WebAPI controller:

The tools which I have leveraged for this tutorial.
    VS 2022 Community Edition
    .NET 6.0
    Web API
Define a service interface and its implementation:
public interface IMyService
{
    string GetServiceInfo();
}

public class MyService : IMyService
{
    public string GetServiceInfo()
    {
        return "Example on Action Injection";
    }
}


Configure the service in your Program.cs:
builder.Services.AddTransient<IMyService, MyService>();

Use [FromServices] attribute in your controller action method:
namespace ActionInjection.Controllers
{
    [Route("api/[controller]")]
    [ApiController]
    public class MyController : ControllerBase
    {
        [HttpGet("info")]
        public IActionResult GetInfo([FromServices] IMyService myService)
        {
            var info = myService.GetServiceInfo();
            return Ok(info);
        }
    }
}


In this example, the GetServiceInfo action method uses [FromServices] attribute to directly inject the IMyService instance into the method parameter. ASP.NET Core will automatically resolve the service and provide it to the action method.

It's important to recognize that while leveraging [FromServices] can be advantageous under specific circumstances, the preferred approach for enhanced maintainability and testability—especially when a service is required across multiple action methods—is to opt for constructor injection (the constructor of the [Controller]).



European ASP.NET Core Hosting :: Fluent Validation ASP.NET Core Web API

clock August 1, 2023 08:31 by author Peter

FluentValidation is a very popular .NET library for building strongly-typed validation rules. It helps us use validation in a very easy manner. It is a small validation library that uses a fluent interface and lambda expressions for building validation rules.

What is FluentValidation in ASP.NET Core?
Data Validation is essential for any Application. When it comes to Validating Models, developers usually use Data Annotations. There are a few issues with the Data Annotations approach:

  • Validation rules are tightly coupled with Entities.
  • Add complexity to Entities/DTOs.
  • Difficult to make dynamic and conditional validations.
  • Difficult to extend and scale.

FluentValidation is a replacement for the existing validation attributes (Data Annotations). It can turn up the validation game to a new level and gives total control. It separates the validation rules and/or logic from the Entity/DTO classes.

It is an open-source library that helps you make validations clean, easy to create, and maintain. It also works on external models that you don’t have access to. It makes the model classes clean and readable.

Configure Fluent Validation in ASP.NET Core

1. NuGet: To use FluentValidation, you need to install below NuGet packages.
Install-Package FluentValidation.AspNetCore
Install-Package FluentValidation.DependencyInjectionExtensions

2. Configuration: Automatic registration of validators is possible. You can make use of FluentValidation.DependencyInjectionExtensions package, which can be used to automatically find all the validators in a specific assembly using an extension method.
using FluantValidationDemoApp.Data;
using FluentValidation.AspNetCore;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;
using System.Configuration;
using System.Reflection;

var builder = WebApplication.CreateBuilder(args);

// Add services to the container.
builder.Services.AddControllers();

builder.Services.AddDbContext<ApplicationDBContext>(options =>
{
options.UseSqlite(builder.Configuration.GetConnectionString("DefaultConnection"));
});

builder.Services.AddControllers()
        .AddFluentValidation(v =>
        {
            v.ImplicitlyValidateChildProperties = true;
            v.ImplicitlyValidateRootCollectionElements = true;
            v.RegisterValidatorsFromAssembly(Assembly.GetExecutingAssembly());
        });

builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();

var app = builder.Build();

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

app.UseHttpsRedirection();
app.UseAuthorization();
app.MapControllers();
app.Run();


This adds FluentValidation to the pipeline for Controllers.

Validator Implementation
To define a set of validation rules for a particular object, you will need to create a class that inherits from AbstractValidator<T>, where T is the type of class that you wish to validate.

The validation rules themselves should be defined in the validator class’s constructor. To specify a validation rule for a particular property, call the RuleFor method, passing a lambda expression that indicates the property that you wish to validate.
using FluantValidationDemoApp.DTOs;
using FluentValidation;

namespace FluantValidationDemoApp.Validations
{
public class CustomerValidator : AbstractValidator<CustomerDTO>
{
    public CustomerValidator()
    {
        RuleFor(x => x.Name).NotNull().NotEmpty();
        RuleFor(x => x.Name).Length(20, 250);
        RuleFor(x => x.PhoneNumber).NotEmpty().WithMessage("Please specify a phone number.");
        RuleFor(x => x.Age).InclusiveBetween(18, 60);

        // Complex Properties
        RuleFor(x => x.Address).InjectValidator();

        // Other way
        //RuleFor(x => x.Address).SetValidator(new AddressValidator());

        // Collections of Complex Types
        //RuleForEach(x => x.Addresses).SetValidator(new AddressValidator());
    }
}
}


using FluantValidationDemoApp.DTOs;
using FluentValidation;

namespace FluantValidationDemoApp.Validations
{
public class AddressValidator : AbstractValidator<AddressDTO>
{
    public AddressValidator()
    {
        RuleFor(x => x.State)
            .NotNull()
            .NotEmpty();

        RuleFor(x => x.Country)
            .NotEmpty()
            .WithMessage("Please specify a Country.");

        RuleFor(x => x.Postcode)
            .NotNull()
            .Must(BeAValidPostcode)
            .WithMessage("Please specify a valid postcode");
    }

    private bool BeAValidPostcode(string postcode)
    {
        return postcode.Length == 6;
    }
}
}

Code Explanation
You can use the RuleForEach method to apply the same rule to multiple items in a collection.
You can also combine RuleForEach with SetValidator when the collection is of another complex object.
RuleSets allow you to group validation rules together, which can be executed together as a group whilst ignoring other rules.
Including Rules: You can include rules from other validators, provided they validate the same type. This allows you to split rules across multiple classes and compose them together.
Validators can be used with any dependency injection library. To inject a validator for a specific model, you should register the validator with the service provider as IValidator<T>. services.AddScoped<IValidator<Customer, CustomerValidator>();

namespace FluantValidationDemoApp.Entities
{
public class Customer
{
    public int Id { get; set; }
    public string Name { get; set; } = string.Empty;
    public int Age { get; set; }
    public string PhoneNumber { get; set; } = string.Empty;
    public bool IsAdult { get; set; }
    public Address? Address { get; set; }
}
}


namespace FluantValidationDemoApp.Entities
{
public class Address
{
    public int Id { get; set; }
    public string Line1 { get; set; } = string.Empty;
    public string Line2 { get; set; } = string.Empty;
    public string Town { get; set; } = string.Empty;
    public string Postcode { get; set; } = string.Empty;
    public string Country { get; set; } = string.Empty;
    public string State { get; set; } = string.Empty;
}
}


Usage: You don’t need to explicitly check the ModelState in controllers to see if the input is valid. The FluentValidation ASP.NET middleware will automatically find our validator, and if validation fails, it will prepare the ModelState, and our action will return a 400 response.
using FluantValidationDemoApp.Data;
using FluantValidationDemoApp.DTOs;
using FluantValidationDemoApp.Validations;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;

namespace FluantValidationDemoApp.Controllers
{
[Route("api/[controller]")]
[ApiController]
public class CustomerController : ControllerBase
{
    private readonly ApplicationDBContext _applicationDBContext;

    public CustomerController(ApplicationDBContext applicationDBContext)
    {
        _applicationDBContext = applicationDBContext;
    }

    [HttpPost("AddNewCustomer", Order = 0)]
    public IActionResult Add(CustomerDTO customer)
    {
        if (!ModelState.IsValid)
        {
            return BadRequest(ModelState);
        }

        _applicationDBContext.Add(customer);
        _applicationDBContext.SaveChanges();

        return Ok();
    }

    [HttpPost("UpdateNewCustomer", Order = 1)]
    public IActionResult Update(CustomerDTO customer)
    {
        CustomerValidator validator = new CustomerValidator();
        var validationResult = validator.Validate(customer);

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

        _applicationDBContext.Update(customer);
        _applicationDBContext.SaveChanges();

        return Ok();
    }
}
}

You can also explicitly validate the models anywhere. The Validate method returns a ValidationResult object. This contains two properties.

IsValid: a boolean that says whether the validation succeeded.
Errors: a collection of ValidationFailure objects containing details about any validation failures.

FluentValidation Features and Benefits

  • Built-in Validators: ships with several built-in validators like Regular Expression, Email, Credit Card, and many more.
  • Custom Validators: There are several ways to create a custom, reusable validator.
  • Localization: provides translations for the default validation messages in several languages.
  • Test Extensions: provides some extensions that can aid with testing your validator classes.
  • Asynchronous Validation: you can define asynchronous rules, for example, when working with an external API.
  • Transforming Values: you can apply a transformation to a property value prior to validation being performed against it.



European ASP.NET Core Hosting :: How to Use ASPX Files in .NET Core?

clock July 27, 2023 09:50 by author Peter

In .NET Core, there are problems such as the bad complexity of web programming and the vagueness of coding in the controller, and the destruction of the web programming structure on the server side. Also, one of the negative points of .NET Core is the lack of support for aspx files. An executable physical file (aspx) in the root makes your program more structured.

Introducing Code-Behind

This style is completely based on MVC, and in the near future, we will expand it in such a way that there is no need for coding the view part, such as for, foreach, and while loops.

Write code with Code-Behind
You can add aspx files in the wwwroot directory and its subdirectories.

An example of an aspx file based on Code-Behind.
<%@ Page Controller="YourProjectName.wwwroot.DefaultController" Model="YourProjectName.wwwroot.DefaultModel" %><!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8" />
    <title><%=model.PageTitle%></title>
</head>
<body>
    <%=model.BodyValue%>
</body>
</html>


An example of a controller class that is based on Code-Behind.
using CodeBehind;

namespace YourProjectName.wwwroot
{
    public partial class DefaultController : CodeBehindController
    {
        public DefaultModel model = new DefaultModel();
        public void PageLoad(HttpContext context)
        {
            model.PageTitle = "My Title";
            model.BodyValue = "HTML Body";
            View(model);
        }
    }
}


An example of a model class that is based on Code-Behind.
using CodeBehind;

namespace YourProjectName.wwwroot
{
    public partial class DefaultModel : CodeBehindModel
    {
        public string PageTitle { get; set; }
        public string BodyValue { get; set; }
    }
}


Program file and additional Code-Behind items.
using CodeBehind;
using SetCodeBehind;

var builder = WebApplication.CreateBuilder(args);

var app = builder.Build();

// Configure the HTTP request pipeline.
if (!app.Environment.IsDevelopment())
{
    app.UseExceptionHandler("/Error");
    // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
    app.UseHsts();
}

+ CodeBehindCompiler.Initialization();

app.Run(async context =>
{
+    CodeBehindExecute execute = new CodeBehindExecute();
+    await context.Response.WriteAsync(execute.Run(context));
});

app.UseHttpsRedirection();
app.UseStaticFiles();

app.UseRouting();

app.Run();


In the Program.cs class codes above, the three values marked with the + character must be added.

We show the codes separately for you.
CodeBehindCompiler.Initialization();

CodeBehindExecute execute = new CodeBehindExecute();
await context.Response.WriteAsync(execute.Run(context));


You can use the Write method in the model and controller classes; the Write method adds a string value to the ResponseText attribute; you can also change the values of the ResponseText attribute by accessing them directly.

In the controller class, there is an attribute named IgnoreViewAndModel attribute, and if you activate the IgnoreViewAndModel attribute, it will ignore the values of model and view, and you will only see a blank page; this feature allows you to display the values you need to the user and avoid multiple redirects and transfers.

To receive the information sent through the form, you can follow the instructions below.

public DefaultModel model = new DefaultModel();
public void PageLoad(HttpContext context)
{
    if (!string.IsNullOrEmpty(context.Request.Form["btn_Add"]))
        btn_Add_Click();

    View(model);
}

private void btn_Add_Click()
{
    model.PageTitle = "btn_Add Button Clicked";
}


Note. After running the program and compiling the aspx pages by Code-Behind, your program will no longer refer to any aspx files. If the scale of the program you are building is high or you need to act dynamically, using Code-Behind will definitely give you more freedom. If the scale of the program is low, using Code-Behind will simplify your program, and you will generate faster and more understandable code.

The following example shows the power of Code-Behind

aspx page
<%@ Page Controller="YourProjectName.wwwroot.DefaultController" Model="YourProjectName.wwwroot.DefaultModel" %><!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8" />
    <title><%=model.PageTitle%></title>
</head>
<body>
    <%=model.LeftMenuValue%>
    <div class="main_content">
        <%=model.MainContentValue%>
    </div>
    <%=model.RightMenuValue%>
</body>
</html>


Controller class
using CodeBehind;

namespace YourProjectName.wwwroot
{
    public partial class DefaultController : CodeBehindController
    {
        public DefaultModel model = new DefaultModel();

        public void PageLoad(HttpContext context)
        {
            model.PageTitle = "My Title";
            CodeBehindExecute execute = new CodeBehindExecute();

            // Add Left Menu Page
            context.Request.Path = "/menu/left.aspx";
            model.LeftMenuValue = execute.Run(context);

            // Add Right Menu Page
            context.Request.Path = "/menu/right.aspx";
            model.RightMenuValue = execute.Run(context);

            // Add Main Content Page
            context.Request.Path = "/pages/main.aspx";
            model.MainContentValue = execute.Run(context);

            View(model);
        }
    }
}


Each of the pages is left.aspx, right.aspx, and main.aspx can also call several other aspx files; these calls can definitely be dynamic, and an add-on can be executed that the kernel programmers don't even know about.

Enjoy Code-Behind, but be careful not to loop the program! (Don't call pages that call the current page).
What power does Code-Behind give you while running the program?

Accessing hypertext contents of pages and replacing some values before calling in other pages.

Microsoft usually ties your hands, so you cannot create a dynamic system.

By using the default architecture of Microsoft's ASP.NET Core, you will face some very big challenges. Creating a system with the ability to support plugins that both provides security and does not loop, and can call other pages on your pages is very challenging.

Suppose you have created an application using the default ASP.NET Core cshtml that has a main page that includes a right menu and a left menu. As shown in the code above, can you change the values of these menus to Fill the dynamic form with cshtml pages and replace the values obtained from the pages? It is definitely possible, but it is difficult.

Code-Behind will not even refer to the physical aspx file to call the aspx pages and will only call a method.

How do you manage events in ASP.NET Core?

For example, a route from your program requires several methods to be executed, and these methods do not exist in the core of your program! This work can be blinded with the default cshtml of .NET, but it is difficult.

For example, we should have an event before the request to the search page and not allow the user to do more than 2 searches per minute. Using Code-Behind, we only need to check an aspx page, then reject or allow the search request.



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