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 :: Ways To Optimize Performance In ASP.NET Core Applications

clock May 15, 2023 09:17 by author Peter

Distributed cache plays a significant role in optimizing the efficacy of the application by caching data in memory and reducing database calls. Simply put, caching is the act of storing the result of an operation so that subsequent requests deliver results more quickly.

When do we perform caching?

  • When the processing is sluggish.
  • Multiple computations will be performed.
  • When the output is identical for a given input, we know we do not need to recompute it because it will always be the same.
  • When your host charges for database access. By caching the response and decreasing the number of superfluous server requests, you can save money. For instance, the Google APP engine provides a fixed number of reads and writes to the data repository per day; if you exceed this limit, you must pay, even if the website does not receive a great deal of traffic.  

With NCache, there are numerous methods to optimize performance in ASP.NET Core applications.

  • Response Storage
  • Dispersed Caching
  • Object Caching Session Caching
  • SignalR

What exactly is NCache?
NCache is an open-source distributed cache for.NET, Java, and Node.js that operates in memory. NCache is incredibly quick and scalable, and it caches application data to minimize database access. NCache is utilized to address the performance issues associated with data storage, databases, and the scalability of.NET, Java, and Node.js applications.

To get started with NCache, kindly follow the installation instructions.

Response Caching
Response caching will cache the server responses for a request so that the subsequent request can access the data from the cache instead of hitting a server. For example, assume we have a country and state cascading  dropdown list  in our web form, so based on the country selected, the request will pass to the server, and we use it to get a respective state list,

In this case, the country and state data will never change frequently, so it is unnecessary to make country and state requests to the server whenever the web form loads; initially, we can save the response in the cache and for the consecutive calls instead of hitting the server we can get a saved response from a cache. We can cache any response from the HTTP request; it can be XML, Text, JSON, or HTML. We will get complete control over cached response using the cache-control property; for example, if cache-control: max-age=45 implies that the server response is valid for 45 seconds.

There are different ways to cache the response.

In-memory
Response cache via HTTP Header
Distributed Caching

1. In-Memory
In this approach, the response content will be cached in-memory on the server side and served for all subsequent calls. We can use built-in <cache> tags to define the section of the views to be cached.
Since the content is cached in-memory, it will be cleared on the application restarts.

2. Response cache via HTTP Header

This approach caches the response content on the browser's end. It can reduce the server hits because the browser cache serves the subsequent calls.

3. Distributed Caching
In this approach, the response cache is distributed across several servers in a web farm that is external to an application. For subsequent calls, any server can be responded to. NCache provides a powerful distributed cache service to implement this approach, improving the application's performance by reducing server hits.
NCache as a response caching middleware

NCache is one of the best response caching middleware for .NET web applications, providing the following benefits as a distributed cache.

  • 100% .NET- It is one of the distributed caches in the market, which is entirely built with .NET.
  • Fast and Scalable- It is very fast since it uses an in-memory distributed cache. We can scale it linearly, so NCache will be a great choice when we experience performance challenges in our ASP.NET Core application during high traffic.
  • High Availability- It supports peer clustering architecture, so there is no data loss when the cache server is down.

Distributed Caching
Distributed Caching is used to overcome the drawbacks of in-memory caching mechanisms regarding reliability and scalability. It will improve the application's performance when cloud services host the app. In the distributed cache, the cache is shared by multiple app servers and maintained as an external service.

It has several advantages,
    It doesn't use local memory
    Reliability -The cached data is available in the different data center
    It's consistency across requests to multiple servers

By default, ASP.NET Core has a distributed caching mechanism that persists the data in memory. The main drawback is the memory limit; the cached data will be cleared during the server restarts. Another approach is using the SQL Server, which has a drawback in performance; it will impact the application's performance when the load is high. So, the best approach is distributed caching with NCache. NCache is one of the distributed caching service providers. Using NCache, we can configure the ASP.NET Core application locally and in Azure as a distributed cache cluster.

The AddNCacheDistributedCache extension method configures NCache as a provider for Distributed Caching for the ASP.NET Core web application.

Download the NuGet package and add the below code to the program.cs file.
builder.Services.AddNCacheDistributedCache(configuration => {
    configuration.CacheName = "democache";
    configuration.EnableLogs = true;
    configuration.ExceptionsEnabled = true;
});


If there is any update in the record from the database, it will cache the new data.

Session Storage in ASP.NET Core using NCache

HTTP is a stateless protocol, which means the information will not persist across multiple requests; we need to use a session storage mechanism for the ASP.NET Core application to persist the information across multiple requests. By default, ASP.NET Core will use in-memory storage to store the session information, this is fine to some extend, but whenever there is high traffic, this session storage may fail due to some limitations.

Memory Limitation
Since the session information is directly stored in-memory, memory space might be a major concern here; if the memory space exceeds more than the limitation, the session storage will fail.

Session Loss
If the application server goes down, the session loss occurs.

ASP.NET Core provides two options to perform session caching,
    Session storage provider and  
    IDistributedCache interface

Both of them are fast in managing the session information; however, both are stand-alone caches with a single point of failure and no option for data replication when the server goes down.

So, the perfect solution to overcome this issue is storing the session information in distributed session storage. NCache is an in-memory distributed Cache provider developed natively in .NET and .NET Core; it's fast and scalable.

Configuring the NCache on the default Sessions Storage provider and IDistributed Cache interface is simple. Know more about session caching in NCache here.
Advantages of using NCache

1. Data replication capability

NCache provides data replication capability so that the session information will be available in the different centers for different regions; if any region went down, it would reroute the traffic from one region to another.

2. It also offers session sharing between separate cache clusters.
Configuring NCache as a Session Storage Provider

1. Install the following NuGet Package Manager
a.    For Open source
Install-Package AspNetCore.Session.NCache.OpenSource

b.    For Professional
Install-Package AspNetCore.Session.NCache.Professional

c.    For Enterprise
Install-Package AspNetCore.Session.NCache

2. Configure the session using the AddNCacheSession extension method, and add the below code to the program.cs file.
builder.Services.AddNCacheSession(configuration => {
    configuration.CacheName = "[your clustered cache name]";
    configuration.EnableLogs = true;
    configuration.SessionAppId = "demoAppSession";
    configuration.SessionOptions.IdleTimeout = 5;
    configuration.SessionOptions.CookieName = "AspNetCore.Session";
});


3. Configure the NCache settings in appsettings.cs file
{
  "NCacheSettings": {
    "SessionAppId": "demoAppSession",
    "SessionOptions": {
      "CookieName": "AspNetCore.Session",
      "CookieDomain": null,
      "CookiePath": "/",
      "CookieHttpOnly": "True",
      "IdleTimeout": "5",
      "CookieSecure": "None",
     "useJsonSerialization": true,
    },

    "CacheName": "demoClusteredCache",
    "EnableLogs": "True",
    "RequestTimeout": "90"
  },
}

Reference: ASP.NET Core Session Provider Configuration | NCache Docs (alachisoft.com)

Object Caching
Object Caching is one of the techniques to cache the object data to improve the ASP.NET Core application performance.
Assume we have an ASP.NET Core Web API service that returns a list of available countries in the world; in this case, whenever there is a request from the client, the service will fetch the country list from the database and return it to the client. In this case, we know the Country object data will not be frequently updated. So, caching this object in a distributed cache will avoid unnecessary database trips and improve the application's performance.

NCache provides two APIs to achieve object caching,
    NCache API
    IDistributedCache API

1. NCache API
NCache API has an extension method GetCache which is used to connect to an instance of the NCache within the application.

2. IDistributedCache API
If your application already uses the default distributed cache, the IDistributedCache API of NCache can be easily configured on top of the default one.

We already discussed IDistributedCache in the above DistributedCache section.

What is ASP.NET Core SignalR?

SignalR is used to fetch the content from the server side to clients instantly and manages the connection seamlessly. It is an open-source Microsoft API. It uses remove procedure call shortened to RPC to call the client from the server. Hubs establish a core connection between the server and the client, and it will have complete control over the connections.  

Use cases for SignalR,
    Real-time monitoring applications
    Chat application
    Scoreboard application
    IoT Device control and so on.  

SignalR Backplane
It is a shared bus or repository. We can configure a Webfarm as a backplane so that instead of sending a message from a web server to the clients, the backplane can be broadcast to all the web servers with all the servers connected to the backplane.

Main bottlenecks with SignalR Backplane,
    Database as SignalR Backplane is slow; it cannot scale out with increasing applied load.
    The database can slow down under high load, which may led to single-point failure sometime.

Integrating a scalable NCache In-memory Distributed Cache to our ASP.NET Core SignalR application can overcome all these bottlenecks and improve performance.

Configuring NCache as a backplane for ASP.NET Core SignalR application,

1. Download and install the NCache Nuget Package
dotnet add package AspNetCore.SignalR.NCache --version 5.3.1

2. Configure NCache settings in appsettings.json
"NCacheConfiguration": {
  "CacheName": "myLocalCache",
  "ApplicationID": "chatApplication"
},

3. Using the AddNCache extension method, we can easily configure our application and add the below code in the program.cs.
builder.Services.AddSignalR().AddNCache(ncacheOptions => {
    ncacheOptions.CacheName = Configuration["NCacheConfiguration:CacheName"];
    ncacheOptions.ApplicationID = Configuration["NCacheConfiguration:ApplicationID"];
});

We have seen a different technique for improving the performance of the ASP.NET Core applications using response cache, distributed cache, SignalR cache, and session and object cache with NCache. We also saw the overview of response, distributed, SignalR, session, and object cache on what, why, and the advantages of using this caching mechanism with NCache, which is super-fast and linearly scalable, and it is built on .NET to overcome the performance bottleneck in our ASP.NET Core web applications.

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 :: Encryption and Decryption Using C# in an ASP.NET Windows Console Application

clock May 9, 2023 07:53 by author Peter

This article describes how to encrypt and decrypt text using the AES Encryption standard.

Using C# to implement encryption and decryption in an ASP.NET Windows console application
Open Visual Studio, Create a new console application.

Provide a project name, select the storage location, and then click next.

Select the.Net framework based on the needs of your project, then select Create.

Once the project has been created, then Right Click on the project name, choose to add, and click on the new item.
Add the class file to the existing project.

From the C# node, choose the class definition and provide the class file name like Encrypt and decrypt file.cs.
After we added the class file to our project solution.

Once the class file is created successfully, we can write the  Encryption and decryption methods in the class file.

Use the below method to encrypt the given text input.

public static string EncryptString(string plainText)
       {
           byte[] array;
           using (Aes aes = Aes.Create())
           {
               aes.KeySize = 256;
               aes.Key = new byte[32];
               aes.IV = new byte[16];
               aes.Padding = PaddingMode.PKCS7;
               ICryptoTransform encryptor = aes.CreateEncryptor(aes.Key, aes.IV);
               using (MemoryStream memoryStream = new MemoryStream())
               {
                   using (CryptoStream cryptoStream = new CryptoStream((Stream)memoryStream, encryptor, CryptoStreamMode.Write))
                   {
                       using (StreamWriter streamWriter = new StreamWriter((Stream)cryptoStream))
                       {
                           streamWriter.Write(plainText);
                       }
                       array = memoryStream.ToArray();
                   }
               }
           }
           return Convert.ToBase64String(array);
       }


Use the below Decrypt method to decrypt the encrypted text input.
public static string DecryptString(string cipherText)
       {
           byte[] buffer = Convert.FromBase64String(cipherText);
           using (Aes aes = Aes.Create())
           {
               aes.Padding = PaddingMode.PKCS7;
               aes.KeySize = 256;
               aes.Key = new byte[32];
               aes.IV = new byte[16];
               ICryptoTransform decryptor = aes.CreateDecryptor(aes.Key, aes.IV);
               using (MemoryStream memoryStream = new MemoryStream(buffer))
               {
                   using (CryptoStream cryptoStream = new CryptoStream((Stream)memoryStream, decryptor, CryptoStreamMode.Read))
                   {
                       using (StreamReader streamReader = new StreamReader((Stream)cryptoStream))
                       {
                           return streamReader.ReadToEnd();
                       }
                   }
               }
           }
       }


The full code implementation is like in "Program.cs".
using System;
using Encrypt__Decrypt__AES_Operation__file;

namespace EncryptionDecryptionUsingSymmetricKey
{
    class Program
    {
        public static void Main(string[] args)
        {
            while (true)
            {
                ProcessEncryptDecrypt();
            }
        }
        public static void ProcessEncryptDecrypt()
        {
            int iChoice = 0;
            string strPwd = string.Empty;
            var encryptedString = string.Empty;
            Console.WriteLine("Enter your choice:");
            Console.WriteLine("1.Decryption   2.Encryption  3.Exit ");
            Console.WriteLine("******************************");
            iChoice = Convert.ToInt32(Console.ReadLine());
            if (iChoice == 1)
            {
                Console.WriteLine("Enter the Password:");
                strPwd = Convert.ToString(Console.ReadLine());
                encryptedString = AesOperation.EncryptString(strPwd);
                Console.WriteLine($"encrypted string : {encryptedString}");


            }
            else if (iChoice == 2)
            {
                Console.WriteLine("Enter the Password:");
                strPwd = Convert.ToString(Console.ReadLine());
                var decryptedString = AesOperation.DecryptString(strPwd);
                Console.WriteLine($"decrypted string : {decryptedString}");
            }
            else
            {
                Environment.Exit(0);
            }
        }

    }
}


And run the application. Happy Coding!

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 :: App Trim in .NET Core

clock May 8, 2023 12:24 by author Peter

In ASP.NET Core, App Trim refers to a feature that automatically removes unused assemblies from the application's memory during runtime. This helps to reduce the memory footprint of the application and improve its overall performance.

What is Trimming?
When an ASP.NET Core application starts up, it loads all the required assemblies into memory. However, not all the assemblies may be needed throughout the lifetime of the application. App Trim identifies and removes the assemblies that are no longer required by the application. This process is called trimming.

The trimming process is done automatically by the .NET runtime, and it works by analyzing the code paths in the application to determine which assemblies are required and which ones are not. The unused assemblies are then removed from memory, freeing up space for other tasks.

App Trim is particularly useful in scenarios where memory usage is critical, such as in cloud-based environments where resources are limited and scaling can be expensive. It can also be used to improve the startup time of the application.

App Trim is available in ASP.NET Core 3.0 and later versions, and it is enabled by default in ASP.NET Core projects created with the .NET Core 3.0 SDK or later. However, it can be disabled or customized using the PublishTrimmed property in the project file or by using command-line options during the publishing process.

Trimming Options

PublishTrimmed, which enables trimming during the publishing process, was first introduced in .NET Core 3.0. However, the other options for trimming during publishing are only available in .NET 5 and newer versions.

To enable App Trim in the project file, open the .csproj file of your ASP.NET Core project and add the following property:
<PropertyGroup>
  <PublishTrimmed>true</PublishTrimmed>
</PropertyGroup>

Note:
    In .NET 6 and newer versions, trimming is fully supported. However, in .NET Core 3.1 and .NET 5, it was considered an experimental feature.
    It's worth noting that trimming is only available for applications that are published as self-contained deployments.

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 :: WebAPI Unit Testing in.Net 7 using the MSTest Project

clock May 4, 2023 10:49 by author Peter

Hello, In.Net 7 today, I'll build the ASP.NET Web API, and I'll use the MSTest Unit Testing Project to test the module.

Microsoft's Visual Studio includes the native unit testing library MsTest.

I'll build a calculator service using the add/subtract/multiply/divide method in this tutorial. I'll make a Rest API that the Client uses to correlate to each Method.

Let's begin WebAPI Unit Testing with the.Net 7 MSTest Project.

1. From VS 2022, choose the ASP.Net Core Web API project.

 

2. Use .Net7 STS

3. Now WEB API project has been created. I must add CalculatorService and ICalculatorService interface to implement the Repository Design Pattern.

public interface ICalculatorService
{
    public int Add(int a, int b);

    public int Subtract(int a, int b);

    public int Multiply(int a, int b);

    public int Divide(int a, int b);
}
public class CalculatorService:ICalculatorService
{
    public int Add(int a, int b)
    {
        return a + b;
    }
    public int Subtract(int a, int b)
    {
        return a - b;
    }
    public int Multiply(int a, int b)
    {
        return a * b;
    }
    public int Divide(int a, int b)
    {
        return a / b;
    }
}

4. Now Add Service to the Dependency Injection container.
The below three methods define the lifetime of the services,

    AddTransient
    Transient lifetime services are created each time they are requested. This lifetime works best for lightweight, stateless services.
     
    AddScoped
    Scoped lifetime services are created once per request.
     
    AddSingleton
    Singleton lifetime services are created the first time they are requested (or when ConfigureServices is run if you specify an instance there), and then every subsequent request will use the same instance.

But here we use AddSingleton as per requirement.
builder.Services.AddSingleton<ICalculatorService, CalculatorService>();

5. Create the CalculatorController and Inject ICalculatorService via Constructor Injection. And created the Add/Subtract/Multiply/Divide API Method.
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;

namespace WebApiCore7.Controllers
{
    [Route("api/[controller]")]
    [ApiController]
    public class CalculatorController : ControllerBase
    {
        private ICalculatorService _calculatorService;
        public CalculatorController(ICalculatorService calculatorService)
        {
            _calculatorService = calculatorService;
        }
        // GET: api/<CalculatorController>


        // GET api/<CalculatorController>/5
        [HttpGet("Add")]
        public int Get(int a, int b)
        {
            return _calculatorService.Add(a, b);
        }

        [HttpGet("Subtract")]
        public int Subtract(int a, int b)
        {
            return _calculatorService.Subtract(a, b);
        }

        [HttpGet("Multiply")]
        public int Multiply(int a, int b)
        {
            return _calculatorService.Multiply(a, b);
        }

        [HttpGet("Divide")]
        public int Divide(int a, int b)
        {
            return _calculatorService.Divide(a, b);
        }
    }
}

6. It's time to build and run the Web API project. We will test using the SWAGGER tool.
Swagger is an open-source framework for designing and describing APIs. Swagger's journey started in 2010 when it was developed by Reverb Technologies (formerly called Wordnik) to solve the need for keeping the API design and documentation in sync. Fast forward 6 years, and Swagger has become the de-facto standard for designing and describing RESTful APIs used by millions of developers and organizations for developing their APIs, be it internal or client facing.


7. Testing ADD API using Swagger


Till Now, we have developed the Web API, which implements the Calculator functionality.

It's time to add the MSUnit Test project to unit test the Calculator Service.

8. Right-click on Solution Explorer and Add Project and select MSTest Test Project.


9. Set the Project Name


WebAPI Unit Testing with MSTest Project in .Net 7

 

10. Set the Framework as .Net 7 STS

11. Right-click on the UnitTest Project and add the WebAPIcore7 Project dependency As we have to Test the Calculator Service.

12. Add CalculatorUT Class and Decorate the class with TestClass and Method with TestMethod.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using WebApiCore7;
namespace UnitTestProject
{
    [TestClass]
    public class CalculatorUT
    {
        private ICalculatorService _calculatorService;
        public CalculatorUT()
        {
            _calculatorService = new CalculatorService();
        }

        [TestMethod]
        public void AddWithPass()
        {
            int actual = 5;
            int expected = _calculatorService.Add(3, 2);
            Assert.AreEqual(actual, expected);
        }
        [TestMethod]
        public void AddWithFail()
        {
            int actual = 5;
            int expected = _calculatorService.Add(3, 3);
            Assert.AreEqual(actual, expected);
        }

        [TestMethod]
        public void MultiplyWithPass()
        {
            int actual = 80;
            int expected = _calculatorService.Multiply(20, 4);
            Assert.AreEqual(actual, expected);
        }
    }
}

13. It's time to build and test our unit test cases.
Hit the test button on the top menu. Test showing in Green color are passed.

14. Those method that are tested are shown in the API project like this(Green/Red color).


Unit testing helps identify all kinds of issues with the software at a very early stage. Software developers can then work on those issues first before progressing any further. The main advantage of this is when the issues are resolved at an early stage, no other part of the software is impacted.

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 :: How to build a multi-tenant applications with ASP.NET Core?

clock April 18, 2023 07:59 by author Peter

Tenant application in ASP.NET Core
First of all, we have to know what a tenant is. Simply tenant is a customer. Meaning each customer is called a tenant.

Multi-tenant application in ASP.NET Core
Multi-tenancy is an architecture in which a single software application instance serves multiple customers.

In this case, a single software will manage multiple customer databases. But you have needed a tenant database for multiple tenants. This process is also called SaaS (Software as a Service).

Moreover, you can also manage the software design style by multi-tenant architecture. In the case of a single tenant, every software-service instance has a separate database. Otherwise, in the case of multi-tenant only one software service instance, but there are multiple databases.

Tenant Database
I have to maintain a Tenant database to manage multiple customer Databases. I am using two tables, Like
CREATE DATABASE [TenantDB]


USE [TenantDB]
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TABLE [dbo].[Tenants](
    [CustomerId] [int] NOT NULL,
    [Customer] [varchar](50) NOT NULL,
    [Host] [varchar](50) NULL,
    [SubDomain] [varchar](50) NOT NULL,
    [Logo] [varchar](50) NULL,
    [ThemeColor] [varchar](50) NULL,
    [ConnectionString] [varchar](max) NOT NULL,
 CONSTRAINT [PK_Customer] PRIMARY KEY CLUSTERED
(
    [CustomerId] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, OPTIMIZE_FOR_SEQUENTIAL_KEY = OFF) ON [PRIMARY]
) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]
GO

USE [TenantDB]
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TABLE [dbo].[TenantUsers](
    [Id] [int] NOT NULL,
    [CustomerId] [int] NOT NULL,
    [Email] [varchar](50) NOT NULL,
 CONSTRAINT [PK_User] PRIMARY KEY CLUSTERED
(
    [Id] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, OPTIMIZE_FOR_SEQUENTIAL_KEY = OFF) ON [PRIMARY]
) ON [PRIMARY]
GO

USE [TenantDB]
GO
INSERT [dbo].[Tenants] ([CustomerId], [Customer], [Host], [SubDomain], [Logo], [ThemeColor], [ConnectionString]) VALUES (1, N'Red Customer', N'localhost:5057', N'rc', NULL, N'Red', N'Server=Rohol;Database=App-DB1; user id=sa; password=123456; MultipleActiveResultSets=true')
GO
INSERT [dbo].[Tenants] ([CustomerId], [Customer], [Host], [SubDomain], [Logo], [ThemeColor], [ConnectionString]) VALUES (2, N'Green Customer', N'localhost:5057', N'gc', NULL, N'Green', N'Server=Rohol;Database=App-DB2; user id=sa; password=123456; MultipleActiveResultSets=true')
GO
INSERT [dbo].[TenantUsers] ([Id], [CustomerId], [Email]) VALUES (1, 1, N'[email protected]')
GO
INSERT [dbo].[TenantUsers] ([Id], [CustomerId], [Email]) VALUES (2, 2, N'[email protected]')
GO

Application Database
Now I will add two application databases; these databases will access by a single web portal. Databases are like App-DB1 and App-DB2. Each database has one table, like Users.

CREATE Database [App-DB1]
GO
USE [App-DB1]
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TABLE [dbo].[Users](
    [UserId] [int] NOT NULL,
    [UserName] [varchar](50) NULL,
    [UserEmail] [varchar](50) NULL,
    [Password] [varchar](50) NULL,
 CONSTRAINT [PK_User] PRIMARY KEY CLUSTERED
(
    [UserId] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, OPTIMIZE_FOR_SEQUENTIAL_KEY = OFF) ON [PRIMARY]
) ON [PRIMARY]
GO

USE [App-DB1]
GO
INSERT [dbo].[Users] ([UserId], [UserName], [UserEmail], [Password]) VALUES (1, N'Red Customer', N'[email protected]', N'123456')
GO

CREATE Database [App-DB2]
GO
USE [App-DB2]
GO
/****** Object:  Table [dbo].[Users]    Script Date: 04/15/23 5:26:26 PM ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TABLE [dbo].[Users](
    [UserId] [int] NOT NULL,
    [UserName] [varchar](50) NULL,
    [UserEmail] [varchar](50) NULL,
    [Password] [varchar](50) NULL,
 CONSTRAINT [PK_User] PRIMARY KEY CLUSTERED
(
    [UserId] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, OPTIMIZE_FOR_SEQUENTIAL_KEY = OFF) ON [PRIMARY]
) ON [PRIMARY]
GO

USE [App-DB2]
GO
INSERT [dbo].[Users] ([UserId], [UserName], [UserEmail], [Password]) VALUES (1, N'Green Customer', N'[email protected]', N'123456')
GO

Create a Multi-tenant Application
Open visual studio editor 2022 and choose an ASP.Net Core Web App (MVC).

 

 

Install SaasKit.Multitenancy
Go to the NuGet Package Manager and install the SaasKit.Multitenancypackage

This SaasKit.Multitenancy package will manage a multi-tenancy strategy.

Now add two classes, Tenants and TenantUsers.
public class Tenants
    {
        [Key]
        public int CustomerId { get; set; }
        public string Customer { get; set; }
        public string Host { get; set; }
        public string SubDomain { get; set; }
        public string Logo { get; set; }
        public string ThemeColor { get; set; }
        public string ConnectionString { get; set; }
    }

C#

public class TenantUsers
   {
       [Key]
       public int Id { get; set; }
       public int CustomerId { get; set; }
       public string Email { get; set; }
   }


Now add another class like TenantResolver. Here I will use TenantContext, which is come from SaasKit.Multitenancy package.
public interface ITenantResolver
    {
        Task<TenantContext<Tenants>> ResolveAsync(HttpContext context);
    }
public class TenantResolver : ITenantResolver<Tenants>
    {
      public async Task<TenantContext<Tenants>> ResolveAsync(HttpContext context)
        {
         throw new NotImplementedException();
        }
    }

Service Registration
Go to the program file and register the Tenant class with TenantResolver class
// Multitenancy
builder.Services.AddMultitenancy<Tenants, TenantResolver>();

Middleware Setup
app.UseMuttitenancy<Tenant>();

This Tenant middleware will call with every HTTP request.

Install Entity Framework Core
I will useEFCore ORM to access SQL Database. So, we need to install the required packages. Like

After installing these three packages, I will add Two database contexts. One context is for Tenant-Database and another for App-Database. Like

TenantDBConnection
{
  "ConnectionStrings": {
    "TenantConnection": "Server=Rohol;Database=TenantDB; user id=sa; password=123456; MultipleActiveResultSets=true"
  },
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft.AspNetCore": "Warning"
    }
  },
  "AllowedHosts": "*"
}

// Sql Server TenantDb Connection
builder.Services.AddDbContextPool<TenantDbContext>(options => options.
        UseSqlServer(builder.Configuration.GetConnectionString("TenantConnection")));

Now add Signin and Users class in the Models folder. Like
public class Signin
    {
        [Required(ErrorMessage ="email address is required")]
        [EmailAddress]
        public string Email { get; set; }
        [DataType(DataType.Password)]
        public string? Password { get; set; }
    }


public class Users
    {
        [System.ComponentModel.DataAnnotations.Key]
        public int UserId { get; set; }
        [Required]
        public string UserName { get; set; }
        [Required]
        public string UserEmail { get; set; }
        [Required]
        public string Password { get; set; }

    }


DB context Implementation
Now time to implement Db contexts. Like
public class TenantDbContext : DbContext
    {
        public TenantDbContext(DbContextOptions<TenantDbContext> option) : base(option)
        {
        }

        public DbSet<Tenants> Tenants { get; set; }
        public DbSet<TenantUsers> TenantUsers { get; set; }

    }


public class AppDbContext : DbContext
    {
        private readonly Tenants tenant;

        public AppDbContext(DbContextOptions<AppDbContext> options, Tenants tenant):base(options)
        {
            this.tenant = tenant;
        }

        protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
        {
            optionsBuilder.UseSqlServer(tenant.ConnectionString);
        }

        public DbSet<Users> Users { get; set; }

    }

Add Services
I have used two services for this application. One for tenant operation and another for application operation.

namespace MultiTenantApp.Services
{
    public interface ITenantService
    {
       Tenants GetTenantBySubDomain(string subDomain);
       Tenants GetTenantByEmail(string email);
    }

    public class TenantService : ITenantService
    {
        private readonly TenantDbContext tdbc;

        public TenantService(TenantDbContext tdbc)
        {
            this.tdbc = tdbc;
        }

        public Tenants GetTenantByEmail(string email)
        {
         throw new NotImplementedException();
        }

        public Tenants GetTenantBySubDomain(string subdomain)
        {
         throw new NotImplementedException();
        }
    }
}

    GetTenantBySubDomain()- This method will return a tenant by sub-domain.
    GetTenantByEmail ()- This method will return a tenant by email.

namespace MultiTenantApp.Services
{
    public interface IAppUserService
    {
        public string GetTenantByEmail(string email);
        public string Signin(Signin model);
    }
    public class AppUserService : IAppUserService
    {
        private readonly AppDbContext adbc;
        private readonly ITenantService tenantService;
        private readonly IHttpContextAccessor httpContextAccessor;

        public AppUserService(AppDbContext adbc, ITenantService tenantService, IHttpContextAccessor httpContextAccessor)
        {
            this.adbc = adbc;
            this.tenantService = tenantService;
            this.httpContextAccessor = httpContextAccessor;
        }

        public string GetTenantByEmail(string email)
        {
            throw new NotImplementedException();
        }

        public string Signin(Signin model)
        {
            throw new NotImplementedException();
        }
    }
}


    GetTenantByEmail()- Here, this method will return a valid URL with a sub-domain.
    Signin()- This method is used to sign in to this portal. It will return a URL as a string.

TenantResolver implementation
public async Task<TenantContext<Tenants>> ResolveAsync(HttpContext context)
        {   // get sub-domain form browser current url. if sub-domain is not exists then will set empty string
            string subDomainFromUrl = context.Request.Host.Value.ToLower().Split(".")[0] ?? string.Empty;
            // checking has any tenant by current sub-domain.
            var result = this.tenantService.GetTenantBySubDomain(subDomainFromUrl);
            Tenants tenant = new();
            // checking has any subdomain is exists in current url
            if (!string.IsNullOrEmpty(result.SubDomain))
            {
                // checking orginal sub-domain and current url sub-domain
                if (!result.SubDomain.Equals(subDomainFromUrl)) return null; // if sub-domain is different then return null
                else
                {
                    tenant.CustomerId = result.CustomerId;
                    tenant.Customer = result.Customer;
                    tenant.Host = result.Host;
                    tenant.SubDomain = result.SubDomain;
                    tenant.Logo = result.Logo;
                    tenant.ThemeColor = result.ThemeColor;
                    tenant.ConnectionString = result.ConnectionString;
                    return await Task.FromResult(new TenantContext<Tenants>(tenant));
                }
            }
            else return await Task.FromResult(new TenantContext<Tenants>(tenant));

        }

This resolver will resolve a multitenant strategy in each HTTP request. If the tenant is valid, then the HTTP request will execute else. The application will show an error. Here I am checking the sub-domain in each request. So, if the sub-domain exists and is valid, the app will work fine; otherwise shows an error. This is a demo and my logic and implementation so anyone can implement his logic.

Controller Implementation
Now add a Signin action in HomeController for view. Like,
public IActionResult Signin(string emailid="")
        {
            ViewBag.Email = emailid;
            return View();
        }

Also, add Signin Post Action for Signin. Like,
[HttpPost]
        public IActionResult Signin(Signin model)
        {
            // checking model state
            if (ModelState.IsValid)
            {
                // checking email at first time
                if (model.Password is null)
                {
                    // retrieve tenant information by user email
                    var result = this.appUserService.GetTenantByEmail(model.Email);
                    // if valid email then redirect for password
                    if (result is not null) return Redirect(result + "?emailid=" + model.Email);
                    else // if email is invalid then clear Email-ViewBag to stay same page and get again email
                    {
                        ViewBag.Email = string.Empty;
                        ViewBag.Error = "Provide valid email";
                    }
                }
                else // this block for password verification, when user provide password to signin
                {
                    var result = this.appUserService.Signin(model);
                    if (result is null) // if password is wrong then again provide valid password
                    {
                        ViewBag.Email = model.Email;
                        ViewBag.Error = "Provide valid password";
                    }
                    else return Redirect(result); // if password is valid then portal will open for user access
                }
            }
            else ViewBag.Email = ""; // if email is invalid then clear Email-ViewBag to stay same page and get again email
            return View();
        }

The detail I have implemented the into the source code. So don't worry; I have provided the source file.

Logout action
public IActionResult Logout()
        {
            return Redirect("http://localhost:5057");
        }


Go to the master _Layout.cshtml page and inject the Tenant class to access the required property. I will use the ThemeColor property to change the theme according to the user's colour. Like,
@inject Tenants tenants;

<body style="background-color:@tenants.ThemeColor">


Same as the index and privacy files. I will use the Customer name from the tenant class. Like
@inject Tenants tenants;
@{
    ViewData["Title"] = "Home Page";
}

<h1>@ViewData["Title"]</h1>

<h4>of @tenants.Customer</h4>


Run the project and sign in by different users. Like
First, for the red user

and second for green user


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 :: Razor In ASP.NET Core

clock April 13, 2023 07:16 by author Peter

Razor expressions are used to generate HTML content in views dynamically. Razor is a syntax for combining HTML markup with C# code to produce dynamic web pages. Razor expressions are enclosed in the @ symbol, including C# code, HTML markup, and another Razor-specific syntax. Razor expressions can perform conditional logic, loop over collections, display data, and format content.

Examples of Razor expressions,
1. Display a value
<p>The value of x is @x</p>

This expression uses the @ symbol to output the value of the x variable.

Perform a conditional check,
// Controller
public IActionResult Index() {
    bool isAdmin = true;
    return View(isAdmin);
}
// View
@model bool

@if (Model)
{
    <h1>Welcome Admin</h1>
}
else
{
    <h1>Welcome Guest</h1>
}

If the Model variable is true, the view will display an <h1> element with the "Welcome Admin" text. Otherwise, it will display an <h1> element with the "Welcome Guest" text. The value is True to show Welcome Admin in H1 Font.

2. List Data Bind in Table
// Model Class
public class ProductM {
    public int Id {
        get;
        set;
    }
    public string Name {
        get;
        set;
    }
    public string Description {
        get;
        set;
    }
    public decimal Price {
        get;
        set;
    }
}
// Controller
public ActionResult Product() {
    List < ProductM > products = new List < ProductM > {
        new ProductM {
            Id = 1, Name = "Laptop", Description = "Hp 5262 I5 ", Price = 55000
        },
        new ProductM {
            Id = 2, Name = "Laptop", Description = "Dell 52 I5 ", Price = 58000
        },
        new ProductM {
            Id = 3, Name = "Laptop", Description = "Lenovo 3", Price = 45000
        },
        new ProductM {
            Id = 4, Name = "Mobile", Description = "Nokia ", Price = 5000
        },
        new ProductM {
            Id = 5, Name = "Mobile", Description = "RealMe", Price = 58000
        },
        new ProductM {
            Id = 6, Name = "Mobile", Description = "MI", Price = 45000
        }
    };
    return View(products);
}
// View page


@using CSharpCornerTest.Models
@model List<ProductM>
@{
        ViewBag.Title = "Product";
}

<h2>Product</h2>

<table class="table table-striped">
    <thead>
        <tr>
            <th>ID</th>
            <th>Name</th>
            <th>Description</th>
            <th>Price</th>
        </tr>
    </thead>
    <tbody>
        @foreach (var product in Model)
        {
            <tr>
                <td>@product.Id</td>
                <td>@product.Name</td>
                <td>@product.Description</td>
                <td>@product.Price.ToString("C")</td>
            </tr>
        }
    </tbody>
</table>

3 . Perform a Switch Case
// View Page
@using CSharpCornerTest.Models
@model StatusM
@{
    ViewBag.Title = "StatusCode";
}

<style>
    span.badge.badge-primary {
        font-size: 48px;
        margin: -73px 0 0 139px;
    }
</style>

@switch (Model.Status)
{
    case "Open":
        <h1>Status :  </h1>
        <span class="badge badge-primary">Open</span>
        break;
    case "Closed":
        <span class="badge badge-secondary">Closed</span>
        break;
    default:
        <span class="badge badge-danger">Invalid</span>
        break;
}
// Class
public class StatusM {
    public string Status {
        get;
        set;
    }
}
// Controller
public ActionResult StatusCode() {
    var model = new StatusM {
        Status = "Open"
    };
    return View(model);
}


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 :: ControllerBase Class In ASP.NET Core

clock April 10, 2023 07:33 by author Peter

ASP.NET Core is a cross-platform, high-performance, open-source framework for building modern, cloud-based, internet-connected applications. One of the core building blocks of an ASP.NET Core application is the ControllerBase class, which serves as the base class for controllers that handle HTTP requests.

What is the ControllerBase class?
The ControllerBase class is a base class for controllers in ASP.NET Core that handles HTTP requests. It provides a set of common properties and methods controllers use to handle HTTP requests and generate HTTP responses. The ControllerBase class does not implement any specific behavior or logic but instead provides a set of common methods and properties that derived classes can use.

The ControllerBase class is defined in Microsoft.AspNetCore.Mvc namespace is part of the ASP.NET Core MVC framework. It is derived from the Controller class and provides a simpler, lighter-weight alternative for building APIs and microservices.

Key Features of the ControllerBase Class
The ControllerBase class provides several key features and functionalities essential for building web applications and APIs in ASP.NET Core. Some of the most important features of the ControllerBase class are:

Action Results
The ControllerBase class provides methods for generating action results that can be returned to the client in response to an HTTP request. These action results include:ViewResult: Renders a view to generate an HTML response.

    ViewResult- Renders a view to generate an HTML response
    PartialViewResult- Renders a partial view to generate an HTML response
    JsonResult- Serializes an object to JSON format and returns it as the response
    ContentResult- Returns a string or content as the response
    StatusCodeResult- Returns an HTTP status code as the response
    RedirectResult- Redirects the request to a different URL
    FileResult- Returns a file as the response
    ObjectResult- Serializes an object to a specified format (e.g., JSON, XML) and returns it as the response.

Routing
The ControllerBase class provides a set of attributes and methods for configuring routing for controllers and actions. These include:

    RouteAttribute- Used to specify the URL pattern for a controller or action
    HttpGetAttribute, HttpPostAttribute, HttpPutAttribute, HttpDeleteAttribute- Used to specify the HTTP method for an action
    RouteData- A property that provides access to the routing data for the current request

Model Binding
The ControllerBase class provides methods for binding HTTP request data to action parameters. These include:

    FromQueryAttribute- Binds data from the query string
    FromRouteAttribute- Binds data from the URL segment
    FromHeaderAttribute- Binds data from an HTTP header
    FromBodyAttribute- Binds data from the request body

Example Usage of the ControllerBase class
To illustrate how the ControllerBase class can be used in practice, let's look at a simple example. Suppose we want to build an API that returns a list of users. We can create a UserController class that derives from the ControllerBase class, like so:
using Microsoft.AspNetCore.Mvc;
using System.Collections.Generic;

[ApiController]
[Route("api/[controller]")]
public class UserController: ControllerBase {
    private readonly List < string > users = new List < string > {
        "Lalji Dhameliya"
    };
    [HttpGet]
    public IActionResult GetUsers() {
        return new JsonResult(users);
    }
}


Conclusion
The ControllerBase class is a core building block for controllers in ASP.NET Core and provides a rich set of features and functionalities for handling HTTP requests and generating HTTP responses. By leveraging the capabilities of the ControllerBase class, developers can build powerful, high-performance web applications and APIs that are easy to maintain.

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 :: How To Use MQTT Client In .Net 7?

clock April 3, 2023 08:40 by author Peter

MQTT (Message Queue Telemetry Transport) is a lightweight messaging protocol that is designed to be used in resource-constrained environments. MQTT is widely used in the Internet of Things (IoT) and machine-to-machine (M2M) communication.

This article will discuss how to implement an MQTT consumer in .NET 7. We will use the MQTTnet library, a high-performance MQTT client library in C#.

Setting up the Environment
To get started with .NET 7, you must install it on your system. You can download and install .NET 7 from the official website of .NET.

To use MQTTnet, you need to add the MQTTnet NuGet package to your project. You can do this using the NuGet package manager in Visual Studio or the dotnet CLI.
dotnet add package MQTTnet

Implementing an MQTT Consumer

You need to create a new console application to implement an MQTT consumer in .NET 7. In this example, we will subscribe to a topic and receive messages from the MQTT broker.
using System;
using System.Threading;
using System.Threading.Tasks;
using MQTTnet;
using MQTTnet.Client;
using MQTTnet.Client.Options;
using MQTTnet.Client.Subscribing;
using MQTTnet.Protocol;
class Program {
    static async Task Main(string[] args) {
        var factory = new MqttFactory();
        var client = factory.CreateMqttClient();
        var options = new MqttClientOptionsBuilder().WithTcpServer("localhost", 1883).WithClientId("mqtt_consumer").Build();
        client.UseConnectedHandler(async e => {
            Console.WriteLine("Connected to MQTT broker.");
            var topicFilter = new MqttTopicFilterBuilder().WithTopic("test/topic").Build();
            await client.SubscribeAsync(new MqttClientSubscribeOptionsBuilder().WithTopicFilter(topicFilter).Build());
        });
        client.UseDisconnectedHandler(async e => {
            Console.WriteLine("Disconnected from MQTT broker.");
            await Task.Delay(TimeSpan.FromSeconds(5));
            try {
                await client.ConnectAsync(options, CancellationToken.None);
            } catch {
                Console.WriteLine("Reconnecting to MQTT broker failed.");
            }
        });
        client.UseApplicationMessageReceivedHandler(e => {
            Console.WriteLine($ "Received message on topic '{e.ApplicationMessage.Topic}': {Encoding.UTF8.GetString(e.ApplicationMessage.Payload)}");
        });
        try {
            await client.ConnectAsync(options, CancellationToken.None);
        } catch {
            Console.WriteLine("Connecting to MQTT broker failed.");
        }
        Console.ReadLine();
    }
}

The above code creates a new MQTT client and subscribes to the "test/topic" topic. When a message is received on this topic, the UseApplicationMessageReceivedHandler method is called, and the message is displayed on the console.

The UseConnectedHandler and UseDisconnectedHandler methods handle the connection and disconnection events. The UseConnectedHandler method is called when the client is connected to the MQTT broker, and the UseDisconnectedHandler method is called when the client is disconnected from the MQTT broker.

Conclusion

In this article, we discussed how to implement an MQTT consumer in .NET 7 using the MQTTnet library. We created a console application that subscribes to a topic and receives messages from the MQTT broker.

MQTT is a powerful messaging protocol that can be used in a variety of applications, including IoT and M2M communication. With the MQTTnet library, it is easy to implement an MQTT client in .NET 7, and the library provides a range of features.

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 :: SOLID With .Net Core

clock March 28, 2023 07:25 by author Peter

This article will explain the SOLID principles, which one of those acronyms means alongside a practical example of an architectural problem that we could use in order to fix the problem.


What are the SOLID principles?
A SOLID principle is a group of 5 different design patterns whose main focus is to create loosely coupled architectures with a high level of maintainability. The name SOLID comes from the acronym of its five principles,
    S - Single Responsability Principle;
    O - Open-Closed Principle;
    L - Liskov Substitution Principle;
    I - Interface Segregation Principle;
    D - Dependency Inversion Principle.

If in your project you have the common problem to solve a bug and create two different bugs then you must start to think about using the SOLID principles in order to have a cleaner and more organized code, which does not break other features when you are working in a specific feature.

S - SRP - Single Responsibility Principle
"A class should have one, and only one, a reason to change."  (Robert C. Martin)

Avoiding Jack of all Trades' classes, the Single Responsibility Principle says that your class should have a single responsibility. This means that you should avoid, at all costs, having classes with multiple functionalities.

Imagine doing maintenance in a class with multiples functionalities, the risk of fixing one functionality but breaking other functionalities as a side-effect is extremely high. To overcome those kinds of situations you should apply the Single Responsibility Principle.

One great example of the Single Responsibility Principle being applied is the 3-tier projects architectures, where each tier is responsible only for their tasks. Ie.: the business layer is responsible to validate business logics where the repository layer is responsible to manipulate the database.


 

O - OCP - Open/Closed Principle
"A class is closed, since it may be compiled, stored in a library, baselined, and used by client classes. But it is also open, since any new class may use it as parent, adding new features. When a descendant class is defined, there is no need to change the original or to disturb its clients." (Bertrand Meyer)

The topic here is also to avoid Jack of All Trades' classes but in a different manner. The open-closed says that instead of modifying your base classes to add more features you should create a new class with those features, and this class will be inheriting the base class.

Imagine having a class that based on the input could go through one workflow or another workflow completely different, you will probably manage that with conditional statements.

Now, imagine when you need to do maintenance in one of those workflows. What is the risk of breaking, by mistake, the other ones?

The Open-Closed Principle says that you must have a base class that should not be modified to add new functionalities. Instead, you should have a new class inheriting the base class with those new functionalities. In this case, when you need to do maintenance in a specific workflow you are certain that will have no side effects in the others workflows.

L - LSP - Liskov Substitution Principle
"Subtypes must be substitutable for their base types." (Barbara Liskov)

The main point from the Liskov Substitution Principle is to create a base class in order to be inherited from its subtypes.

The Liskov Substitution Principle states that if we change our class for its base class we should not have different behaviour. Instead, if we change our subclasses by our base class without breaking the application because our base classes must behave in the same way as our subclasses. In this case, if we need to replace our subclasses for another subclass we would not need to refactor anything because it would be a simple substitution and everything would still be working the same.

I - ISP - Interface Segregation Principle
"No client should be forced to depend on methods it does not use." (Robert C. Martin)

This principle is not the best friend of laziness, it is the worst friend of those projects when you place all your needed contracts in a single place, with this we are not going to be able to reuse those interfaces or, even worse, we will not be using every method in the contract. Instead of creating an interface with many contracts on it, you should create as many interfaces as possible by grouping common behaviours.

The Interface Segregation Principle says that we should segregate interfaces in order to do not depend on interfaces with a contract that will not be implemented. We should have smaller interfaces and depend on more than one interface if needed.

D - DIP - Dependency Inversion Principle
"High-level modules should not depend upon low-level modules. Both should depend upon abstractions" (Robert C. Martin)

Here we have the best friend of loosely coupled applications and unit testing. If you have ever needed to replace one dependency and to do this you had to refactor every method that this dependency was being called then you should use the Dependency Inversion Principle.

The Dependency Inversion Principle says that our classes should not depend on low-level modules because this created a strong coupled application, making it very difficult to unit test and substitute dependencies. Instead, our classes should receive in their constructor the abstraction of their low-level dependencies, with this we may change our classes that implement the contract without breaking or needing to refactor the whole application. Also, we could easily mock our dependencies in order to create unit tests.

SOLID principles Practical Usage One-by-One
SRP - The Problem - Class that sum two numbers and log it
Here we have a problem that we can use the Single Responsability Principle to fix it. A class with two functionalities, the first is to sum two numbers and the second is to log this operation
class Problem
{
    public int Sum(int numberOne, int numberTwo)
    {
        int result = numberOne + numberTwo;
        LogCalculations("Sum Operation. Number one: " + numberOne + ", Number two: " + numberTwo + ". Result: " + result);
        return result;
    }

    private void LogCalculations(string message)
    {
        string path = Environment.GetFolderPath(Environment.SpecialFolder.Desktop) + @"\log.txt";
        using (StreamWriter sw = File.CreateText(path))
        {
            sw.WriteLine(message);
        }
    }
}


Applying the Single Responsibility Principle we would have two different classes:
class Solution
{
    public int Sum(int numberOne, int numberTwo)
    {
        int result = numberOne + numberTwo;
        Logging.Log("Sum Operation. Number one: " + numberOne + ", Number two: " + numberTwo + ". Result: " + result);
        return result;
    }
}
public static class Logging
{
    public static void Log(string message)
    {
        string path = Environment.GetFolderPath(Environment.SpecialFolder.Desktop) + @"\log.txt";
        using (StreamWriter sw = File.CreateText(path))
        {
            sw.WriteLine(message);
        }
    }
}


OCP - The Problem 1 - Class to do math calculations
In this class, we receive as input one enumeration with the operation type and return the result from this operation. If we need to add or modify one operation, we would need to modify the class.
public class MathCalculate
{
    public double Calculate(double numberA, double numberB, CalculationType calculationType)
    {
        double result = 0;
        switch (calculationType)
        {
            case CalculationType.addition:
                result = numberA + numberB;
                break;
            case CalculationType.multiplication:
                result = numberA * numberB;
                break;
            case CalculationType.subtraction:
                result = numberA - numberB;
                break;
            default:
                break;
        }
        return result;
    }
}

public enum CalculationType
{
    addition,
    multiplication,
    subtraction
}


Applying the Open-Closed Principle we would have a base class "Calculation" and each operation would be a new class, inheriting from this base class. If we need to add or modify a new operation, then we would need to work only in the class of this operation
public abstract class BaseCalculation
{
    public abstract double Calculate(double numberA, double numberB);
}

public class AdditionCalculation : BaseCalculation
{
    public override double Calculate(double numberA, double numberB)
    {
        return numberA + numberB;
    }
}
public class MultiplicationCalculation : BaseCalculation
{
    public override double Calculate(double numberA, double numberB)
    {
        return numberA * numberB;
    }
}

public class SubtractionCalculation : BaseCalculation
{
    public override double Calculate(double numberA, double numberB)
    {
        return numberA - numberB;
    }
}

public class DivisionCalculation : BaseCalculation
{
    public override double Calculate(double numberA, double numberB)
    {
        return numberA / numberB;
    }
}


OCP - The Problem 2 - Email sender with validations
If we need to add or modify the validations, we would need to modify the email sender class, risking to break the email sender functionality.
public class MailSender
{
    public void SendMail(string subject, string body, string recipient)
    {
        SmtpClient smtpClient = new SmtpClient("smtp.gmail.com")
        {
            Port = 587,
            Credentials = new NetworkCredential("email", "password"),
            EnableSsl = true,
        };

        //validate recipient's domain
        if (!recipient.ToString().EndsWith("@thiago.com"))
        {
            Console.WriteLine("Mail destinatary not in the domain");
            return;
        }

        //validate body
        if (string.IsNullOrEmpty(body))
        {
            Console.WriteLine("Mail body is empty.");
            return;
        }

        smtpClient.SendAsync("[email protected]", recipient, subject, body, null);
    }
}


Applying the open-closed principle to solve this problem we would have this email sender class receiving a list of validations. When we need to add or modify one of those validations would not be necessary to update the mail sender class:
public class MailClass
{
    public string Subject { get; set; }
    public string Body { get; set; }
    public string Recipient { get; set; }
}

public interface IValidation<T>
{
    bool Validate(T mail);
}


public class DomainValidation : IValidation<MailClass>
{
    public bool Validate(MailClass mail)
    {
        if (mail.Recipient.ToString().EndsWith("@thiago.com"))
            return false;

        return true;
    }
}
public class BodyValidation : IValidation<MailClass>
{
    public bool Validate(MailClass mail)
    {
        if (string.IsNullOrEmpty(mail.Body))
            return false;

        return true;
    }
}

public class Main
{
    public void SendMail(MailClass mailClass, List<IValidation<MailClass>> validations)
    {
        List<bool> validationsResult = new List<bool>();
        validations.ForEach(x => validationsResult.Add(x.Validate(mailClass)));

        if (!validationsResult.Any(x => !x))
        {
            SmtpClient smtpClient = new SmtpClient("smtp.gmail.com")
            {
                Port = 587,
                Credentials = new NetworkCredential("email", "password"),
                EnableSsl = true,
            };

            smtpClient.SendAsync("[email protected]", mailClass.Recipient, mailClass.Subject, mailClass.Body, null);
        };
    }
}


OCP - Extension Methods
We can also make usage of extension methods in order to extend objects without modifying their base behaviour. The following code extends the String object, adding this new method on it:
public static class SolutionThree
{
    public static string ThiagoString(this string normalString)
    {
        return "Thiago's String is: " + normalString;
    }
}

LSP - The Problem - Having a subtraction class inheriting from an addition class
In this example, we have an addition class working fine and then we extended it, wrongly, creating the subtraction class. If we replace the subtraction class with the base class (addition) our output will differ.
public class AdditionCalculation
{
    public AdditionCalculation(int numberA, int numberB)
    {
        this.NumberB = numberB;
        this.NumberA = numberA;
    }
    public int NumberA { get; set; }
    public int NumberB { get; set; }
    public virtual int Calculate()
    {
        return this.NumberA + NumberB;
    }
}
public class SubtractionCalculation : AdditionCalculation
{
    public SubtractionCalculation(int numberA, int numberB) : base(numberA, numberB)
    {
    }

    public new int Calculate()
    {
        return NumberA - NumberB;
    }
}

Applying the Liskov Substitution Principle to solve this problem we have a base class then we have the addition and subtraction classes inheriting from this base class. If we change our class with the base class our output is not going to be affected.
public abstract class MathCalculate
{
    public MathCalculate(int numberA, int numberB)
    {
        this.NumberB = numberB;
        this.NumberA = numberA;
    }
    public int NumberA { get; set; }
    public int NumberB { get; set; }

    public abstract int Calculate();
}
public class Addition : MathCalculate
{
    public Addition(int numberA, int numberB) : base(numberA, numberB)
    {
    }

    public override int Calculate()
    {
        return this.NumberA + NumberB;
    }
}
public class Subtraction : MathCalculate
{
    public Subtraction(int numberA, int numberB) : base(numberA, numberB)
    {
    }

    public override int Calculate()
    {
        return NumberA - NumberB;
    }
}

ISP - The Problem - A single interface for many type of classes
In this example, we have a single interface called IAnimal that is used for both Human and Whale classes. The problem is that not the whole contract fit both items because, as we all know, whales do not walk.
public interface IAnimal
{
    void Walk();
    void Breath();
    void Eat();
    void Argument();
}

public class Human : IAnimal
{
    public void Argument()
    {
        // Argumentation
    }

    public void Breath()
    {
        // Breathing
    }

    public void Eat()
    {
        // Eating
    }

    public void Walk()
    {
        // Walk
    }
}
public class Whale : IAnimal
{
    public void Argument()
    {
        // Argumentation
    }

    public void Breath()
    {
        // Breathing
    }

    public void Eat()
    {
        // Eating
    }

    public void Walk()
    {
        throw new NotImplementedException();
    }
}

Applying the Interface Segregation Principle we break the single interface in smaller interfaces with common methods and then we only use the interfaces that we need in our classes.
public interface IFeed {
    void Eat();
}

public interface IArgument
{
    void Argument();
}

public interface IGroundMoviment
{
    void Walk();
}
public interface IAirMoviment
{
    void Fly();
}
public interface IWaterMoviment
{
    void Swimm();
}

public class Human : IGroundMoviment, IArgument, IFeed
{
    public void Argument()
    {
        // Argument
    }

    public void Eat()
    {
        // Eat
    }

    public void Walk()
    {
        // Walk
    }
}
public class Whale : IWaterMoviment, IFeed
{
    public void Eat()
    {
        // Eat
    }

    public void Swimm()
    {
        // Swimm
    }
}


DIP - The Problem - Strong Coupled Application
In this example, we need to instantiate our dependency inside our method, creating a strong coupled application. If we want to replace this dependency we would need a lot of work, needing to change those dependencies at every method that is being used. Also, it is much more difficult to unit test this layer because it is much harder to mock this dependency.
public class BusinessLayer
{
    public void AddItem(int itemId)
    {
        RepositoryLayer repositoryLayer = new RepositoryLayer();
        if (!string.IsNullOrEmpty(repositoryLayer.GetItem(itemId)))
            repositoryLayer.Update();
        else
            repositoryLayer.Create();
    }
}
public class RepositoryLayer
{
    public void Create()
    {
        //save data into the Database
    }
    public void Delete()
    {
        //delete data from the Database
    }
    public void Update()
    {
        //update data in the Database
    }
    public string GetItem(int itemId)
    {
        //get item from the Database
        return "item";
    }
}

Applying the Dependency Inversion Principle, we receive the interface of our dependency in the class constructor. If we need to change the class that implements this dependency contract it would not be necessary to refactor any method where we use this dependency.
public class BusinessLayer
{
    private readonly IRepositoryLayer repositoryLayer;

    public BusinessLayer(IRepositoryLayer repositoryLayer)
    {
        this.repositoryLayer = repositoryLayer;
    }
    public void AddItem(int itemId)
    {
        if (!string.IsNullOrEmpty(repositoryLayer.GetItem(itemId)))
            repositoryLayer.Update();
        else
            repositoryLayer.Create();
    }
}
public interface IRepositoryLayer
{
    void Create();

    void Delete();

    void Update();

    string GetItem(int itemId);
}

Congratulations! You have successfully applied the SOLID principles using .Net Core.

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 :: Build Up Swagger In ASP.Net Core 2.2 Web API

clock March 27, 2023 09:16 by author Peter

What is Swagger?
Swagger is the largest framework for designing APIs using a common language and enabling the development across the whole API lifecycle, including documentation, design, testing, and deployment.

The framework provides a set of tools that help programmers generate client or server code and install self-generated documentation for web services.

What is Swashbuckle?
Swashbuckle is a handy library to easily bring Swagger support to your ASP.NET Core (or ASP.NET) application. It is especially handy when developing an HTTP based API. It creates a form of interactive documentation based on the OpenAPI Specification.

Add Swagger to ASP.NET Core 2.2 Web API
Create an ASP .NET Core 2.2 Web API project using Visual Studio 2019.

After creating the project, go to Nuget Package Manager and add Swashbuckle.AspNetCore package.

Open Startup.cs file to add swagger service to middleware. Like:

And enable the Swagger UI in Configure() method.

 

To open Swagger UI as your home page.In Debug tab from the properties of the solution, you will find a check box “Launch browser”. Change the value in a text box with “swagger”.

Now, when you run the application you should see Swagger UI for ValuesController.

Manage versions of APIs
You can manage different versions of your APIs, for example, you have v2 APIs as well and you need to enable that in Swagger then you just need to add a couple of steps.
First, add new SwaggerDoc in ConfigureService method and then add new endpoint in Configure method in Startup.cs


To Include XML Comments in Swagger, we recommend reading this article Include XML Comments in Swagger under ASP.NET Core 2.2.
The source code for this tutorial is available on GitHub.

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.



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