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 :: .NET Core NUGET packages

clock July 6, 2021 06:40 by author Peter

.Net core development is based on the open-source NuGet packages. NuGet will reduce work and manage the application very easily. We need to select the NuGet based on the purpose otherwise it will impact the application performance as well as application size also.

As part of the development lifecycle, we need to select different libraries at each stage. 

While creating a new service, we need to inform what kind of APIs will be available and what fields will belong to that each APIs. It will provide high-level information about the service. So we need clear documentation at the first phase of development itself. We can create documentation either manually or code-wise. Manual documentation will double the work. In code wise we can generate the document by code and based on the needs we can update it later. We can create high-level API documentation using Swashbuckle at the initial stage of development.

Swashbuckle

We need to share the API specs while developing a restful API. Swashbuckle provides documentation for the API in JSON object format. The document contains the resource URL, request and response object, corresponding content format, and different status code types with the response object. It provides a built-in UI and loads the results into that. We can load the swagger YAML file into any open API application. It will be easy to understand and validate the API specs.

Once we have done the high level of documentation we need to start the API development. Each API will have a set of inputs. We need to validate the input before the processing logic. So we need to add a different set of validation rules based on the needs. We can add the validation to our API inputs using the Fluent validation library.

Fluent Validation

It contains .NET libraries and the validation is performed using the Lambda expression. We can add different types of custom validation to the input. We can build our custom validation rules based on the needs.

Once we have validated our inputs we need to store the data into a database based on our business. We need to convert the input model based on the data layer. So data conversion layer is required to map the user input to a data model. We can use AutoMapper to convert the user input objects to data objects and vice versa.

Automapper

It's a popular object-to-object mapping library that can be used to map objects belonging to dissimilar types. AutoMapper saves you the tedious effort of having to manually map one or more properties of such incompatible types.

Once data has been converted to data layer format we need to store the data into the database. So we need to establish the connection and form the query to run on the database. We need some mediators to establish a connection between the data context layer to the database. ORM serve this purpose using a different set of libraries

ORM

Data access is an important part of almost any software application. ASP.NET Core supports a variety of data access options and can work with any .NET data access framework. The choice of which data access framework to use depends on the application's needs. Dapper and Entity are used in most of the .net core apps. I have used both ORM into a single service based on the need to achieve better results in terms of performance and simplicity.

Once we have developed our APIs we need to check the application flow. We can identify the flows using logs. Logs will have information about the request, what will be the response for that request. Logs are mainly used to trace the application flows while debugging the errors. We can use ILogger to enable the logging mechanism to our services.

ILogger

It provides a set of features to store the application level logs to track the application flow. We can configure any logging providers like Serilog or Nlog and we can log any level of logs like information, warning, and errors. We can customize it based on our needs.

Based on the logs we can identify the root cause of errors. Sometimes due to network or data unavailability, the request will get failed. So we need to retry the request or retry after a while. It will increase the application's reliability while serving the request. We can enable the retry mechanism using the Polly library.

Polly

Polly is a .NET resilience and transient-fault-handling library that allows developers to express policies such as Retry, Circuit Breaker, Timeout in a fluent and thread-safe manner.

Service will serve the request as per the user's needs. After a while service might be get stopped due to some errors. We need to get the information once the service is stopped due to some errors. We need some kind of monitor to ensure our service is working as expected. .Net Core provides Diagnostics health checks libraries. Using this we can monitors service heartbeats at frequent intervals.

HealthChecks

Microservices-based applications often use heartbeats or health checks to enable their performance monitors, schedulers, and orchestrators to keep track of the multitude of services. Microsoft.AspNetCore.Diagnostics.HealthChecks package is referenced implicitly for ASP.NET Core apps

Once we have developed the API we need to test the new unit is working as expected. We shouldn't break the existing functions because of the new addition. So we need to test the unit of code before release to testing. We can do by adding unit test as part of development.

Unit Test

It's a type of software testing where individual units or components of the software are tested. The purpose is to validate that each unit of the software code performs as expected. Unit Testing is done during the development (coding phase) of an application by the developers. We can do the Unit testing by XUNIT or NUnit. I have used XUNIT for unit testing and open cover Nuget to generate the unit test reports.

Once we have developed our service we need to deploy it. Our service might be a web service or hosted service. While deploying multiple services it will be better to forward the request via a single endpoint using a gateway pattern. It will hide the request and forward it to internal services. We can implement API gateway using ocelot in .net core

Ocelot

It's a .NET API gateway library. It provides a single entry point to the system that is running multiple microservices and service-oriented services. It acts as a reverse proxy. Its supports HTTPS, HTTP, and WebSockets protocol. It provides gateway features like authentication, authorization, routing, query-string, and header transformation and aggregation. It's lightweight and provides better results while managing multiple services.

Some of the alternative libraries are available at each stage but we need to select them based on our needs. Choosing correct libraries will ease the development, increase the application performance and reduce the development time.



European ASP.NET Core Hosting :: SOLID With .Net Core

clock July 5, 2021 07:44 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("@hostforlifeasp.net"))    
            {    
                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("@hostforlifeasp.net"))    
                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 PeterString(this string normalString)    
        {    
            return "peter'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;    
        }    
    }

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);    
    }



European ASP.NET Core Hosting :: Instrumenting ASP.NET Core Application for exporting metrics to Prometheus

clock June 28, 2021 08:02 by author Peter

Prometheus is an open-source system monitoring and alerting toolkit. With this tool, we can monitor our application/services in production mode. In this article, we will create a simple ASP.NET Core application and will try to export some key metrics to the Prometheus server.


If you don't have any prior knowledge of Prometheus or you don't have Prometheus installed in Docker, please go through my other blog post "System Monitoring And Alerting With Prometheus (Docker)" where I have tried to give some general idea about Prometheus and the docker installation process.

First, we will create an ASP.NET Core Web API Project.

From this service, we want to expose a basic set of metrics. The available .NET library is prometheus-net that comes with a companion ASP.NET Core Package. Run the following commands in the package manager console to install prometheus-net.
Install-Package prometheus-net

Bash
Install-Package prometheus-net.AspNetCore

Bash
We can now start exposing a default set of metrics adding the following code inside the "Configure" method of the "Startup.cs" file.

N.B. Make sure to place this before the app.UseEndPoints() otherwise it may cause missing some important HTTP metrics.


If we start our service and navigate to the "/metrics" endpoint, we can see a default set of metrics exposed by our service.


We can export HTTP metrics to Prometheus. For this, we need to add HttpMetrics middleware provided by "pormetheus-net".


After adding this middleware if we navigate to the "/metrics" endpoint we can see the HTTP metrics have been exposed.


N.B. Like this HTTP Metrics, we can even export different Health Status Metrics, Network Health Status Metrics, .Net Core Runtime Metrics. But for simplicity's purpose, I am skipping it. But if you are interested you can go through these Nuget package documentation to have a clear understanding.

    prometheus-net.AspNetCore.HealthChecks
    prometheus-net.AspNetCore.HealthChecks
    AspNetCore.HealthChecks.SqlServer
    AspNetCore.HealthChecks.Network
    prometheus-net.SystemMetrics

We can even export some Custom Metrics from our application. For example, we will create a very basic metric to track how many times any specific method is executed.

For this, we will simply go to one of our controllers and put the following code. By this code, we can track how many times this "Get()" method has been executed.


Now as we have instrumented our application with Prometheus and the metrics have been ready now we just need to send these metrics to the Prometheus(Docker) server. For this, we need to dockerize our application. For this, we need to add a "Dockerfile" in the root directory of our application. Dockerfile should contain the following code.

#See https://aka.ms/containerfastmode to understand how Visual Studio uses this Dockerfile to build your images for faster debugging.
FROM mcr.microsoft.com/dotnet/core/aspnet:3.1-buster-slim AS base
WORKDIR /app
EXPOSE 80
EXPOSE 443

FROM mcr.microsoft.com/dotnet/core/sdk:3.1-buster AS build
WORKDIR /src
COPY ["PormetheusMetrics/PormetheusMetrics.csproj", "PormetheusMetrics/"]
RUN dotnet restore "PormetheusMetrics/PormetheusMetrics.csproj"
COPY . .
WORKDIR "/src/PormetheusMetrics"
RUN dotnet build "PormetheusMetrics.csproj" -c Release -o /app/build

FROM build AS publish
RUN dotnet publish "PormetheusMetrics.csproj" -c Release -o /app/publish

FROM base AS final
WORKDIR /app
COPY --from=publish /app/publish .
ENTRYPOINT ["dotnet", "PormetheusMetrics.dll"]


Docker

And then need to run the following docker command from the root directory of our application. This command will dockerize our application in docker port 8085.

docker build -t netcore_prom .
docker run -d -p 8085:80 --name netcore_prom netcore_prom

Bash

After the application has been dockerized. We need to set this application as a target in our Prometheus server. For this, we need to do some changes in prometheus.yml file[Please follow my previous blog System Monitoring And Alerting With Prometheus (Docker)]. The prometheus.yml file should be edited as follows.

global:
  scrape_interval: 30s
  scrape_timeout: 10s

rule_files:
scrape_configs:
  - job_name: services
    metrics_path: /metrics
    static_configs:
      - targets: ['prometheus:9090']
  - job_name: 'my-app'
    static_configs:
      - targets: ['host.docker.internal:8085']

YAML
Now if we re-run the Prometheus container as we have updated the "prometheus.yml",
docker-compose up -d

Bash

Now if we go to our Prometheus Web UI(http://localhost:9090) and click on the Targets we can see all our targets and their current status.


 

So here we can see that our Application (my-app) service is up and running.
We can even query for our exposed metrics in the Prometheus Web UI and see metrics.

Just like this, we can query all the metrics that we have exposed from our application.

And with this, we finally export our metrics to the Prometheus server. Though this is a huge topic I just tried to keep this as simple as possible. But if you are interested further I would recommend going through the official website of the Prometheus there you will get to learn more about this.

In the next article, I will try to describe integrating Alert Manager with Prometheus.



European ASP.NET Core Hosting :: Send Email Using ASP.NET Core 5 Web API

clock June 21, 2021 07:08 by author Peter

In this article, we will learn how to send an email in ASP.Net Core Web API. We will code the endpoint that will send the email to a user of your business customers. I am implementing the Cloud Native Microservices architecture in my project. And this service is one of the microservices of my project and I will extend this Microservice to handle all types of emails in my project.

Create the ASP.Net Core Web API Project
First, you need to create the ASP.Net core web project using the ASP.Net core 5 web API.
Install the MailKit Nuget Package

Right click on your Solution File. Now click on select the option Nuget Package and then find the MailKit Library for your project configuration. After the installation of this library, add the reference in the code.

Install-Package NETCore.MailKit

C#

You need to include the following namespaces in your code for the correct configuration.
using MailKit.Net.Smtp;
using MailKit.Security;

Add the Folder Model
After the creation of the Model, now create the class MailRequest with the following information.
using Microsoft.AspNetCore.Http;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;

namespace _101SendEmailNotificationDoNetCoreWebAPI.Model
{
    public class MailRequest
    {
        public string ToEmail { get; set; }
        public string Subject { get; set; }
        public string Body { get; set; }
        public List<IFormFile> Attachments { get; set; }
    }
}


Not Add the Folder Services
After the creation of the folder now add the following classes.

IMailService
using _101SendEmailNotificationDoNetCoreWebAPI.Model;
using System.Threading.Tasks;
namespace _101SendEmailNotificationDoNetCoreWebAPI.Services
{
    public interface IMailService
    {
        Task SendEmailAsync(MailRequest mailRequest);

    }
}


using MimeKit;
using System.IO;
using System.Threading.Tasks;
using MailKit.Net.Smtp;
using MailKit.Security;
using Microsoft.Extensions.Options;
using _101SendEmailNotificationDoNetCoreWebAPI.Settings;
using _101SendEmailNotificationDoNetCoreWebAPI.Model;
namespace _101SendEmailNotificationDoNetCoreWebAPI.Services
{
    public class MailService : IMailService
    {
        private readonly MailSettings _mailSettings;
        public MailService(IOptions<MailSettings> mailSettings)
        {
            _mailSettings = mailSettings.Value;
        }
        public async Task SendEmailAsync(MailRequest mailRequest)
        {
            var email = new MimeMessage();
            email.Sender = MailboxAddress.Parse(_mailSettings.Mail);
            email.To.Add(MailboxAddress.Parse(mailRequest.ToEmail));
            email.Subject = mailRequest.Subject;
            var builder = new BodyBuilder();
            if (mailRequest.Attachments != null)
            {
                byte[] fileBytes;
                foreach (var file in mailRequest.Attachments)
                {
                    if (file.Length > 0)
                    {
                        using (var ms = new MemoryStream())
                        {
                            file.CopyTo(ms);
                            fileBytes = ms.ToArray();
                        }
                        builder.Attachments.Add(file.FileName, fileBytes, ContentType.Parse(file.ContentType));
                    }
                }
            }
            builder.HtmlBody = mailRequest.Body;
            email.Body = builder.ToMessageBody();
            using var smtp = new SmtpClient();
            smtp.Connect(_mailSettings.Host, _mailSettings.Port, SecureSocketOptions.StartTls);
            smtp.Authenticate(_mailSettings.Mail, _mailSettings.Password);
            await smtp.SendAsync(email);
            smtp.Disconnect(true);
        }
    }
}


Add the Folder Settings
Add the class setting in which you define the following Properties.
namespace _101SendEmailNotificationDoNetCoreWebAPI.Settings
{
    public class MailSettings
    {
        public string Mail { get; set; }
        public string DisplayName { get; set; }
        public string Password { get; set; }
        public string Host { get; set; }
        public int Port { get; set; }
    }
}


Add the Controller in the project
Create the Email Controller in which you define the endpoint. Send Email is responsible for sending the email to your business customers.
using _101SendEmailNotificationDoNetCoreWebAPI.Model;
using _101SendEmailNotificationDoNetCoreWebAPI.Services;
using Microsoft.AspNetCore.Mvc;
using System;
using System.Threading.Tasks;

namespace _101SendEmailNotificationDoNetCoreWebAPI.Controllers
{
    [ApiController]
    [Route("api/[controller]")]
    public class EmailController : Controller
    {

        private readonly IMailService mailService;
        public EmailController(IMailService mailService)
        {
            this.mailService = mailService;
        }

        [HttpPost("Send")]
        public async Task<IActionResult> Send([FromForm] MailRequest request)
        {
            try
            {
                await mailService.SendEmailAsync(request);
                return Ok();
            }
            catch (Exception ex)
            {

                throw ex;
            }

        }


    }
}


Configure Each Service In Start-up Class
using _101SendEmailNotificationDoNetCoreWebAPI.Services;
using _101SendEmailNotificationDoNetCoreWebAPI.Settings;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.HttpsPolicy;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
using Microsoft.OpenApi.Models;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;

namespace _101SendEmailNotificationDoNetCoreWebAPI
{
    public class Startup
    {
        public Startup(IConfiguration configuration)
        {
            Configuration = configuration;
        }

        public IConfiguration Configuration { get; }

        // This method gets called by the runtime. Use this method to add services to the container.
        public void ConfigureServices(IServiceCollection services)
        {
            services.Configure<MailSettings>(Configuration.GetSection("MailSettings"));
            services.AddTransient<IMailService, Services.MailService>();

            services.AddControllers();
            services.AddSwaggerGen(c =>
            {
                c.SwaggerDoc("v1", new OpenApiInfo { Title = "_101SendEmailNotificationDoNetCoreWebAPI", Version = "v1" });
            });
            services.AddCors(c =>
            {
                c.AddPolicy("AllowOrigin", options => options.AllowAnyOrigin());
            });
        }

        // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
        public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
        {
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
                app.UseSwagger();
                app.UseSwaggerUI(c => c.SwaggerEndpoint("/swagger/v1/swagger.json", "_101SendEmailNotificationDoNetCoreWebAPI v1"));
            }

            app.UseHttpsRedirection();

            app.UseRouting();

            app.UseAuthorization();

            app.UseEndpoints(endpoints =>
            {
                endpoints.MapControllers();
            });
        }
    }
}


Configure the Mail Setting in AppSetting.Json
Configure the SMTP Setting in AppSetting.Json in the following way,

"MailSettings": {
    "Mail": "[email protected]",
    "DisplayName": "Your Brand Name",
    "Password": "YourPassword",
    "Host": "SMTP Host",
    "Port": 587
  },

  •  Mail Define your email Address
  •  Display Name is your Brand Name
  •  The password of your SMTP Server
  •  The host is your SMTP Host
  •  Port No is Your SMTP PORT No

Run your Project and hit the End Point. Now Swagger UI Exposes the End Point


After hitting the endpoint now add the required information in the request body of the endpoint.


Now click on the execute button when the endpoint successfully sends the request then the status is == 200 so our email is successfully sent to the required email address.


In the case of the GMAIL address now click on the Spam folder and your email is there.

In the case of an Outlook/Microsoft Account, just click your Inbox and receive your email there.

Now, check your Email address inbox folder.



European ASP.NET Core Hosting :: Manage Primary Key And Foreign Key Relationship During Migration

clock June 14, 2021 07:14 by author Peter

In this article, we will learn how to create models for database table migration. When we build a simple database for our project, then it is easy to build class models. But when we develop a complex database for our project, then it's hard to maintain PK & FK relationship over the model. It is not easy to maintain, the string length and datatypes over the model.

So, let's see a few points while creating a model class.
Okay, here are the three tables, names - UserDetails, Customer, and Order. Here, we want to create the ID column as the primary key and a foreign key to the UserId column with the AspNetUser table. Like in the database here, also we want to restrict columns with string length. And also want to create two primary keys in a single model.
like below,
 
 Manage Primary Key And Foreign Key Relationship During Migration  Manage Primary Key And Foreign Key Relationship During Migration
 
 Manage Primary Key And Foreign Key Relationship During Migration
 
Here, Firstly I am going to create the UserDetails table. In which few properties and a foreign key relationship exit with the AspnetUser table.
    public class UserDetails {  
        [Key]  
        public int Id {  
            get;  
            set;  
        }  
        [StringLength(100)]  
        [Column(TypeName = "varchar(100)")]  
        public string Name {  
            get;  
            set;  
        }  
        [StringLength(50)]  
        [Column(TypeName = "varchar(50)")]  
        public string Email {  
            get;  
            set;  
        }  
        [StringLength(1)]  
        [Column(TypeName = "char(1)")]  
        public string Gender {  
            get;  
            set;  
        }  
        public string ProfilePic {  
            get;  
            set;  
        }  
        [ForeignKey("IdentityUser")]  
        public string UserId {  
            get;  
            set;  
        }  
        public virtual IdentityUser IdentityUser {  
            get;  
            set;  
        }  
        public byte Role {  
            get;  
            set;  
        }  
        public DateTime ? CreatedOn {  
            get;  
            set;  
        }  
        public bool ? IsActive {  
            get;  
            set;  
        }  
    }   


Here are a few packages for model attribute properties, which we will use to decorate class properties.

    using System.ComponentModel.DataAnnotations;  
    using System.ComponentModel.DataAnnotations.Schema;  

In this model, we are making a Foreign Key relationship with IdentityUser class, which is available in the database with the name AspnetUsers.

    using Microsoft.AspNetCore.Identity;  

If we want to set the string length of 100/50 or something else varchar characters in the database of the Name property, then we define attribute like this,
    [StringLength(100)]    
    [Column(TypeName = "varchar(100)")]    
    public string Name { get; set; }    


If we desire to set the string length of 1 character only in the database of the Gender property, then we define attribute like this,
    [StringLength(1)]    
    [Column(TypeName = "char(1)")]    
    public string Gender { get; set; }   


If we desire to set the DateTime datatype with nullable constraint in the database of the CreatedOn property, then we define attribute like this,
    public DateTime? CreatedOn { get; set; }  

If we desire to make a foreign Key relationship with IdentityUser and store the IdentityUser table Id in the UserId column, then we define attribute like this,
    [ForeignKey("IdentityUser")]  
    public string UserId { get; set; }  
    public virtual IdentityUser IdentityUser { get; set; }  


Now, we will create the customer table. Which contains FullName, Description & Address properties, and the one foreign Key relationship with UserDetails table in the UserDetailsId column.
    public class Customer {  
        [Key]  
        public int Id {  
            get;  
            set;  
        }  
        [StringLength(100)]  
        [Column(TypeName = "varchar(100)")]  
        public string FullName {  
            get;  
            set;  
        }  
        [StringLength(500)]  
        [Column(TypeName = "varchar(500)")]  
        public string Description {  
            get;  
            set;  
        }  
        [StringLength(500)]  
        [Column(TypeName = "varchar(500)")]  
        public string Address {  
            get;  
            set;  
        }  
        [ForeignKey("UserDetails")]  
        public virtual int UserDetailsId {  
            get;  
            set;  
        }  
        public virtual UserDetails UserDetails {  
            get;  
            set;  
        }  
    }   


If we wish to create two foreign Keys in a single table like UserDetailsId, CustomerId in the Order table, then we write two properties for a single foreign key like this,
    public class Order  
       {  
           [Key]  
           public int Id { get; set; }  
      
           [StringLength(100)]  
           [Column(TypeName = "varchar(100)")]  
           public string OrderNumber { get; set; }  
      
           [ForeignKey("Customer")]  
           public virtual int CustomerId { get; set; }  
           public virtual Customer Customer { get; set; }  
      
           [ForeignKey("UserDetails")]  
           public virtual int UserDetailsId { get; set; }  
           public virtual UserDetails UserDetails { get; set; }  
       }  


Register all tables in ApplicationDbContext class set the proper connection string in appsettings.json, register properly this class to Startup.cs class, and then run migration by migration command.
 
ApplicationDbContex.cs class
    public class ApplicationDbContext: IdentityDbContext {  
        public ApplicationDbContext(DbContextOptions < ApplicationDbContext > options): base(options) {}  
        public DbSet < UserDetails > UserDetails {  
            get;  
            set;  
        }  
        public DbSet < Customer > Customer {  
            get;  
            set;  
        }  
        public DbSet < Order > Order {  
            get;  
            set;  
        }  
    }   

appsettings.json class
    "ConnectionStrings": {  
       "DefaultConnection": "Server=MyServer;Database=db_A;user=sa;password=admin@1234;Trusted_Connection=False;"  
     },  

Startup.cs class
    public void ConfigureServices(IServiceCollection services) {  
        services.AddDbContext < ApplicationDbContext > (options => options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection")));  
        services.AddDefaultIdentity < IdentityUser > (options => options.SignIn.RequireConfirmedAccount = true).AddEntityFrameworkStores < ApplicationDbContext > ();  
        services.AddControllersWithViews();  
        services.AddRazorPages();  
    } 



European ASP.NET Core Hosting :: A Peek Into .NET 6's DateOnly And TimeOnly Structure

clock June 7, 2021 08:26 by author Peter

If there was a poll to find that one little feature every C# developer would love to have in .Net, then it is most likely the ability to store Date and Time individually. For years now, we had to use DateTime to represent Date when the Time part of the object had to be ignored. The same thing happened when we wanted to save time and had to ignore the Date of the DateTime component.
 

And with .Net 6, that long agonizing wait has come to an end. .Net 6 has now introduced DateOnly and TimeOnly Structures which could store Date and Time components.
 
DateOnly
The DateOnly structure allows you to save a Date property with a more explicit structure rather than using the DateTime and ignoring the Time part.
    var dateOnlyFirst = new DateOnly(2020, 2, 16);  
    var dateOnlySecond = DateOnly.FromDateTime(DateTime.Now);  
    Console.WriteLine(dateOnlyFirst);  
    Console.WriteLine(dateOnlySecond);  
    // Output  
    16-02-2020  
    04-06-2021  


We could create the instance either using the Constructors or static helper methods like DateOnly.FromDateTime. It is also interesting to know what happens behinds the scenes. Internally, the DateOnly structure stores the value in an Int32 field that represents the number of days since 1/1/0001. The field is designed to store values from 1 Jan,0001 to 31st Dec 9999. If you take a glimpse of code in the .Net Github source code for DateOnly, you could find some of the following,
    private readonly int _dayNumber;  
    // Maps to Jan 1st year 1  
    private const int MinDayNumber = 0;  
    // Maps to December 31 year 9999. The value calculated from "new DateTime(9999, 12, 31).Ticks / TimeSpan.TicksPerDay"  
    private const int MaxDayNumber = 3_652_058;  
    public DateOnly(int year, int month, int day) => _dayNumber = DayNumberFromDateTime(new DateTime(year, month, day));  
    public static DateOnly FromDateTime(DateTime dateTime) => new DateOnly(DayNumberFromDateTime(dateTime));  
    private static int DayNumberFromDateTime(DateTime dt) => (int)(dt.Ticks / TimeSpan.TicksPerDay);  

The DateOnly provides most of the (applicable) functionality that DateTime provides including AddDays(),AddMonths(),AddYears, ParseExact and many more.
 
TimeOnly
TimeOnly Quite similar to DateOnly, the TimeOnly structure provides a way to represent the Time component effectively in .Net.
    var timeOnlyFirst = new TimeOnly(10,10,10);  
    var timeOnlySecond = TimeOnly.FromDateTime(DateTime.Now);  
    Console.WriteLine(timeOnlyFirst);  
    Console.WriteLine(timeOnlySecond);  
    //Output  
    10:10  
    05:35  


Internally, TimeOnly uses a long to represent the ticks elapsed since midnight. Let us know to take a glimpse of the internal code of TimeOnly.
     // represent the number of ticks map to the time of the day. 1 ticks = 100-nanosecond in time measurements.  
    private readonly long _ticks;  
    // MinTimeTicks is the ticks for the midnight time 00:00:00.000 AM  
    private const long MinTimeTicks = 0;  
    // MaxTimeTicks is the max tick value for the time in the day. It is calculated using DateTime.Today.AddTicks(-1).TimeOfDay.Ticks.  
    private const long MaxTimeTicks = 863_999_999_999;  
    public TimeOnly(int hour, int minute, int second) : this(DateTime.TimeToTicks(hour, minute, second, 0)) {}  
    public TimeOnly(long ticks)  
       {  
          if ((ulong)ticks > MaxTimeTicks)  
          {  
             throw new ArgumentOutOfRangeException(nameof(ticks), SR.ArgumentOutOfRange_TimeOnlyBadTicks);  
          }  
       _ticks = ticks;  
    }  

As with the DateOnly structure, the TimeOnly too comes in with a lot of helper methods that would aid the developer.
 
It is quite safe to assume that a lot of developers would be quite happy with the introduction of these structures. These would definitely improve the code base a lot and make the representations more explicit, rather than using DateTime and ignoring a part of it.



European ASP.NET Core Hosting :: What Is AutoMapper In ASP.NET Core ?

clock June 2, 2021 08:14 by author Peter

In this article, we are going to see what is AutoMapper in .NET core, what problems it solves, how to use AutoMapper, AutoMapper ForMember method, AutoMapper ReverseMap method, and Conditional Mappings.

What is AutoMapper?
AutoMapper is a simple C# library that transforms one object type to another object type, which means, it’s a mapper between two objects. AutoMapper is the convention-based object to object mapper. It maps the properties of two different objects by transforming the input object of one type to the output object of another type.
 
How to add AutoMapper?
The first step is to install the corresponding NuGet package in the Package Manager console, using the command “Install-Package Automapper.Extensions.Microsoft.DependencyInjection”. This command will install all AutoMapper Packages.
 
The next step configures the AutoMapper services into our application. Open startup.cs class file, add “services.AddAutoMapper(typeof(Startup))” in configure services method.
 
Now the AutoMapper Package was installed and configured in our project.
 
How to use Automapper?
Let's take a new user model class, this class will have several properties.
    Public class User {  
        Public int Id {  
            get;  
            set;  
        }  
        Public string FirstName {  
            get;  
            set;  
        }  
        Public string LastName {  
            get;  
            set;  
        }  
        Public string Email {  
            get;  
            set;  
        }  
        Public string Address {  
            get;  
            set;  
        }  
        Public int Age {  
            get;  
            set;  
        }  
    }  


Let’s create a new user view model class, and display the user information,
    Public class UserViewModel {  
        Public string FirstName {  
            get;  
            set;  
        }  
        Public string LastName {  
            get;  
            set;  
        }  
        Public string Email {  
            get;  
            set;  
        }  
    }  


Now let’s see how to convert our domain object to a view model. By using the concept called Profiles, we can organize our mapping configurations.
 
Let’s create a new user profile class, in this class, we can create the mapping configuration inside the constructor.
    Public class UserProfile: Profile // this class inherits from AutoMapper profile class  
    {  
        CreateMap < User, UserViewModel > ();  
    }  


So, basically, we create the mapping from our User domain object to the UserViewModel. That’s it.
 
As soon as our application starts AutoMapper service will scan the application and look for classes that inherit from the profile class and load their mapping configurations.
 
Now, let’s create new controller with the name UserController,
    Public class UserController: controller {  
        Private readonly IMapper _mapper;  
        Public UserController(IMapper mapper) {  
            _mapper = mapper;  
        }  
        Public IActionResult Index() {  
            var userInfo = GetUserInfo();  
            var userViewModel = _mapper.map < UserViewModel > (userInfo);  
            return View(userViewModel);  
        }  
        Private static User GetUserInfo() {  
            Return new User {  
                Id = 1,  
                    FirstName = “John”,  
                    LastName = “Smith”,  
                    Email = “john.smith @gmail.com”  
            }  
        }  
    }  


Now if we run the application (localhost:5001/user), we can see the below result,
 

That’s all, our AutoMapper was successfully converting from the User domain model object to the UserViewModel object. Very simple isn’t it?
 
But if we have different property names in our source object and destination object ??
 
Here comes the ForMember Method concept.
 
Let’s modify the property names in the above userviewmodel class,
    Public class UserViewModel {  
        Public string FName {  
            get;  
            set;  
        } // previously FirstName  
        Public string LName {  
            get;  
            set;  
        } // previously LastName  
        Public string Email {  
            get;  
            set;  
        }  
    }  


So, now we must map user FirstName to FName and user LastName to LName, to make this work we have to change the mapping in the UserProfile class file.
    Public class UserProfile : Profile // this class inherits from AutoMapper profile class  
    {  
    CreateMap<User, UserViewModel>()  
        .ForMember(dest =>  
            dest.Fname,  
            opt => opt.MapFrom(src => src.FirstName))  
        .ForMember(dest =>  
            dest.Lname,  
            opt => opt.MapFrom(src => src.LastName));  
    }  


Above, we customized the configuration for individual members, we can use the ForMember method which has the destination member parameter of type expression and member options parameter of type action.
 
So far we have only looked at one-directional mapping, which means if we have two types, typeA, and typeB then we only map type A to type B.
 
But by using automatic Reverse mapping (using ReverseMap method), it’s possible to achieve Bi-Directional mapping.

    Public class UserProfile : Profile // this class inherits from AutoMapper profile class  
    {  
    CreateMap<User, UserViewModel>()  
        .ForMember(dest =>  
            dest.Fname,  
            opt => opt.MapFrom(src => src.FirstName))  
        .ForMember(dest =>  
            dest.Lname,  
            opt => opt.MapFrom(src => src.LastName))  
        .ReverseMap();  
    }  

Once the reverse map is configured, we can map back from destination to source type.
 
UserController.cs
    Public IActionResult Index() {  
        var userInfo = GetUserInfo();  
        var userViewModel = _mapper.map < UserViewModel > (userInfo);  
        var userViewModelReverse = _mapper.map < Userl > (userViewModel); // Bi-directional Mapping  
        return View(userViewModel);  
    }  


AutoMapper allows you to add Conditional Mapping to properties that must be met before that property will be mapped.
    Public class UserProfile : Profile // this class inherits from AutoMapper profile class  
    {  
    CreateMap<User, UserViewModel>()  
        .ForMember(dest =>  
            dest.Fname,  
            opt => opt.MapFrom(src => src.FirstName))  
        .ForMember(dest =>  
            dest.Lname,  
            opt => opt.MapFrom(src => src.LastName))  
        .ForMember(dest =>  
            dest.IsAdult,  
            opt => opt.Condition (src => src.Age > 18 ? true:false))  
        .ReverseMap();  
    }  


In the above example, the IsAdult property value is based on the condition of Age > 18.
In this article, we have seen what is AutoMapper, how to install and Configure, AutoMapper ForMember method, AutoMapper ReverseMap method, and Conditional Mappings.
Also, AutoMapper provides so many other features to simplify complex mappings. You can check the complete AutoMapper documentation. I hope this article will help you to understand the AutoMapper in ASP.NET Core.



European ASP.NET Core Hosting :: Authorization In Razor Pages ASP.NET Core

clock May 31, 2021 07:03 by author Peter

Authorization is a process that determines what a user is able to do. For example, an Admin user is allowed to install/remove a software from a computer and a non-Admin user can use the software from the computer. It is independent and orthogonal from authentication. However, authorization requires an authentication mechanism. For applications, the first step is always authentication and then authorization.

Using AuthorizeFilter, we can control the access in our MVC / Web API application by specifying this attribute in controller or action method. Similarly, there is a way to control access in our Razor pages, i.e., to use authorization conventions at startup. These conventions allow us to authorize users to access individual pages or folders of the pages. In the same way, these conventions allow anonymous users to access individual pages or folders of pages.
 
To demonstrate the concept, I have created an application with ASP.NET Core Identity. For guidance on how to create an application with ASP.NET Core Identity, please refer to my article "Overview Of Identity In ASP.NET Core 2.0" .
 
Using AddRazorPagesOptions, we can add an AuthorizeFilter to the page at the specified path. With AddRazorPagesOptions, we have a couple of methods that can be used to authorize or allow anonymous access to the page or folder.
 
AuthorizePage
This adds an AuthorizeFilter to the specified page. There are two extension methods: one is "to accept the page name" and other one is " to accept page name and authorization policy".
    public static PageConventionCollection AuthorizePage(this PageConventionCollection conventions, string pageName)  
    public static PageConventionCollection AuthorizePage(this PageConventionCollection conventions, string pageName, string policy)  


AuthorizeFolder
This adds AuthorizeFilter to all pages under a specified folder. There are two extension methods - accept the folder path, and accept the folder path and authorization policy.
    public static PageConventionCollection AuthorizeFolder(this PageConventionCollection conventions, string folderPath)  
    public static PageConventionCollection AuthorizeFolder(this PageConventionCollection conventions, string folderPath, string policy)  


AllowAnonymousToPage
This adds AllowAnonymousFilter to the specified page.
    public static PageConventionCollection AllowAnonymousToPage(this PageConventionCollection conventions, string pageName)  

AllowAnonymousToFolder
This adds AllowAnonymousFilter to all the pages under the specified folder.
    public static PageConventionCollection AllowAnonymousToFolder(this PageConventionCollection conventions, string folderPath)  

AuthorizeAreaPage
This is the same as AuthorizePage method. It adds AuthorizeFilter to the specified page under the specified Area. It also has an extension method that accepts the authorization policy.
    public static PageConventionCollection AuthorizeAreaPage(this PageConventionCollection conventions, string areaName, string pageName)  
    public static PageConventionCollection AuthorizeAreaPage(this PageConventionCollection conventions, string areaName, string pageName, string policy)  

AuthorizeAreaFolder
This is the same as the AuthorizeFolder method. It adds AuthorizeFilter to the all the pages under the specified folder under the specified Area. It also has extension method that accepts the authorization policy.
    public static PageConventionCollection AuthorizeAreaFolder(this PageConventionCollection conventions, string areaName, string folderPath)  
    public static PageConventionCollection AuthorizeAreaFolder(this PageConventionCollection conventions, string areaName, string folderPath, string policy)  

AllowAnonymousToAreaPage

This adds AllowAnonymousFilter to the specified page that is located under the specified area.
    public static PageConventionCollection AllowAnonymousToAreaPage(this PageConventionCollection conventions, string areaName, string pageName)  

AllowAnonymousToAreaFolder

This adds AllowAnonymousFilter to all the pages that are located under the specified area folder.
    public static PageConventionCollection AllowAnonymousToAreaFolder(this PageConventionCollection conventions, string areaName, string folderPath)  

Example
To demonstrate the concept, I have created a few pages and the following snippet shows the folder structure of defined authorization in the project.


    public void ConfigureServices(IServiceCollection services)  
    {  
        ....  
        ....  
        services.AddMvc().AddRazorPagesOptions(options =>  
        {  
            options.Conventions.AuthorizePage("/Page3");  
            options.Conventions.AuthorizeFolder("/Public");  
            options.Conventions.AllowAnonymousToPage("/page4");  
            options.Conventions.AllowAnonymousToFolder("Private");  
      
            options.Conventions.AuthorizeAreaPage("MyFeature", "/AuthPage1");  
            options.Conventions.AllowAnonymousToAreaPage("MyFeature", "/AuthPage2");  
        })  
        .SetCompatibilityVersion(CompatibilityVersion.Version_2_1);  
    }  


The authorization conventions can be also applied to Razor class Library.

    public void ConfigureServices(IServiceCollection services)  
    {  
        ....  
        ....  
        services.AddMvc().AddRazorPagesOptions(options =>  
        {  
            ....  
            ....  
            //This page defined in Razor Class Library project  
            options.Conventions.AuthorizeAreaPage("MyFeature", "/Page1");  
            ....  
            ....  
        })  
        .SetCompatibilityVersion(CompatibilityVersion.Version_2_1);  
    }  

Combining authorized and anonymous access
 
We can also specify authorization for the folder and within this folder it allows anonymous access.

    services.AddMvc()  
        .AddRazorPagesOptions(options =>  
        {  
            ....  
            options.Conventions.AuthorizeFolder("/Private").AllowAnonymousToPage("/Private/page8");  
            ....  
        }).SetCompatibilityVersion(CompatibilityVersion.Version_2_1);  


The reverse case is not allowed; i.e., we cannot define folder for anonymous access and specify a page within it for authorization. In this case, AllowAnonymousFilter is always applied and AuthorizeFilter is ignored.

    .AllowAnonymousToFolder("/Private").AuthorizePage("/Private/page8");  

Summary
 
Using this authorization convention, we can apply authorization on Razor pages. This convention can also be applied to Razor class Library (RCL) project if we use it in our project. In the case of RCL, the conventions are defined in the project that used RCL.



European ASP.NET Core Hosting :: Email Send Using ASP.NET With C#

clock May 25, 2021 07:10 by author Peter

In this article, you will learn how to send email using ASP.NET C# through the various SMTP servers. In this article, I also explained the way of sending emails from the HostForLIFE server.

 

 
Below is the step to send an email using ASP.NET C#,
 
Step 1
Create a new website.
 
Step 2
Create a webform aspx page.
 
Step 3
Add CSS file as attached in source code.
 
Step 4
Add reference of AjaxToolKit as attached in source code.
 
Step 5
Design the webpage like below,
    <!DOCTYPE html>  
    <html  
        xmlns="http://www.w3.org/1999/xhtml">  
        <head id="Head1" runat="server">  
            <title>Email Send Sample</title>  
            <link href="bootstrap.min.css" rel="stylesheet" />  
        </head>  
        <body>  
            <form id="form1" runat="server">  
                <div class="container">  
                    <div class="row">  
                        <div class="col-md-4 col-md-offset-4">  
                            <div class="panel panel-primary">  
                                <div class="panel-heading">  
                                    <h3 class="panel-title">Send Email Sample</h3>  
                                </div>  
                                <div class="panel-body">  
                                    <label>Name</label>  
                                    <asp:TextBox ID="txtname" runat="server" CssClass="form-control" placeholder="Name"></asp:TextBox>  
                                    <asp:RequiredFieldValidator ID="RequiredFieldValidator1" runat="server" ErrorMessage="Please Provide Name" ControlToValidate="txtname" ForeColor="Red"></asp:RequiredFieldValidator>  
                                    <br />  
                                    <label>Subject</label>  
                                    <asp:TextBox ID="txtbody" runat="server" CssClass="form-control" placeholder="Subject"></asp:TextBox>  
                                    <asp:RequiredFieldValidator ID="RequiredFieldValidator2" runat="server" ErrorMessage="Please Provide Subject" ControlToValidate="txtbody" ForeColor="Red"></asp:RequiredFieldValidator>  
                                    <br />  
                                    <label>Email([email protected]</label>  
                                    <asp:TextBox ID="txtemail" runat="server" CssClass="form-control" placeholder="Email"></asp:TextBox>  
                                    <asp:RequiredFieldValidator ID="RequiredFieldValidator4" runat="server" ErrorMessage="Please Provide Email-ID" ControlToValidate="txtemail" ForeColor="Red"></asp:RequiredFieldValidator>  
                                    <br />  
                                    <asp:RegularExpressionValidator ID="RegularExpressionValidator1" runat="server" ErrorMessage="Please Proide Valid Email-ID" ControlToValidate="txtemail" ForeColor="Red" ValidationExpression="\w+([-+.']\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*"></asp:RegularExpressionValidator>  
                                    <br />  
                                    <asp:Button ID="Button1" runat="server" Text="Send Email" CssClass="btn btn-block btn-primary" OnClick="Button1_Click" />  
                                    <asp:Button ID="Button2" runat="server" Text="Send Email from HostForLIFE" CssClass="btn btn-block btn-primary" OnClick="Button2_Click" />  
                                    <asp:Label ID="lblmsg" runat="server" Text=""></asp:Label>  
                                </div>  
                            </div>  
                        </div>  
                    </div>  
                </div>  
            </form>  
        </body>  
    </html>  


Step 6
Add Server-side validation for every field as name validation, email validation as written in the above webpage source code.
 
Step 7
Add Server-side RegularExpressionValidator to valid the correct email id.
 
Step 8
Added below namespace in .aspx.cs page,
    using System.Net;  
    using System.Net.Mail;  

Step 9
Add the below source code on button click event of the webpage.
 
Send email from local server,
    string to = txtemail.Text; //To address  
    string from = "[email protected]"; //From address  
    MailMessage message = new MailMessage(from, to);  
    string mailbody = message.Subject = "This article will help you on how to send email using asp.net c# code";  
    message.Body = mailbody;  
    message.IsBodyHtml = false;  
    SmtpClient client = new SmtpClient();  
    client.Host = "smtp.gmail.com";  
    client.Port = 587;  
    System.Net.NetworkCredential basicCredential1 = new  
    System.Net.NetworkCredential("[email protected]", "password");  
    client.EnableSsl = false;  
    client.UseDefaultCredentials = false;  
    // client.Credentials = basicCredential1;  
    try {  
        client.Send(message);  
        lblmsg.Text = "Email Send Successfully";  
    } catch (Exception ex) {}  

Send email from HostForLIFE Server,
    string to = txtemail.Text; //To address  
    string from = "[email protected]"; //From address  
    MailMessage message = new MailMessage(from, to);  
    string mailbody = "This article will help you on how to send email using asp.net c# code";  
    message.Subject = txtbody.Text;  
    message.Body = mailbody;  
    message.IsBodyHtml = false;  
    SmtpClient client = new SmtpClient();  
    client.Host = "relay-hosting.secureserver.net"; //This is code SMTP Host server name  
    client.Port = 25; //This is default port  
    client.EnableSsl = false;  
    client.UseDefaultCredentials = false;  
    try {  
        client.Send(message);  
        lblmsg.Text = "Email Send Successfully";  
    } catch (Exception ex) {}  

Step 10
Run the application.
If you get the below error then follow step 11.
 
WebForms UnobtrusiveValidationMode requires a ScriptResourceMapping for 'jquery'. Please add a ScriptResourceMapping named jquery(case-sensitive).
 
Step 11
Add the below code in web.config,
    <appSettings>  
       <add key="ValidationSettings:UnobtrusiveValidationMode" value="None" />  
    </appSettings>  


Step 12
Run the website and you will get the below screen. Fill in all the details and click on the button Send Email for Local server email like Gmail and Click on Send Email from HostForLIFE to send email from HostForLIFE server that will not work from local work only on the HostForLIFE server.

Step 13
Once you click on the button after filling in the data you get the message "Email Send Successfully".
 
Some of SMTP Class Properties,
    Host
    SMTP Server( Here you need to give the SMTP server name from where the email going to send).

    Enable SSL
    Check your host accepted SSL Connections Value is either True or False.

    Port
    SMTP Server Port (Here you need to give SMTP server port from where the email going to send).

    Credentials
    SMTP servers login credentials such as Email and Password.

    UseDefaultCredentials
    When we set to True in UseDefaultCredentials then that specifies to allow authentication based on the credentials of the account used to send emails.

In this article, we learned how to send email using ASP.NET C# through the SMTP server. I hope this article is useful for those who want to send email using ASP.NET C#.



European ASP.NET Core Hosting :: Elegant API Versioning In ASP.NET Core

clock May 17, 2021 07:37 by author Peter

In this tutorial, we are going to learn how to develop simple Asp Net Core 3.1 Web API and API Versioning techniques such as URL-based, header-based, and Query string-based versioning.

 
What Is Web API Versioning? And Why Do We Need It?
Assume that we have an API available in the production box and a few clients are already consuming it. Post-production deployment, we should be very careful with any new changes. These changes should not impact the existing customer applications that are already consuming our API. It is not a good practice to advise clients to change the API calls in each of their applications where our API has been integrated. In order to address such issues, API versioning came into the picture.
 
API versions ensure that the integrity and availability of data for our existing client applications.
 
To Begin with,
 
Step 1

Create a simple ASP.NET Core 3.1 API Project.
 
Step 2
Add a model ProductResponse.cs
    namespace AspNetCoreVersioning.Contracts {  
        public class ProductResponse {  
            public Guid Id {  
                get;  
                set;  
            }  
            public string Name {  
                get;  
                set;  
            }  
        }  
    }  

Step 3
Add a Controller ProductsController.cs
    namespace AspNetCoreVersioning.Controllers {  
        [ApiController]  
        [Route("api/products")]  
        public class ProductsController: ControllerBase {  
            [HttpGet("{productId}")]  
            public IActionResult GetProduct([FromRoute] Guid productId) {  
                var product = new ProductResponse {  
                    Id = productId,  
                        Name = "Sanitizer"  
                };  
                return Ok(product);  
            }  
        }  
    }  


Let us test this API, According to your environment, the port number will vary.
https://localhost:12345/api/products/00000000-0000-0000-0000-000000000000
 
Result
    {"id":"00000000-0000-0000-0000-000000000000","name":"Sanitizer"}   

We have received the expected result.
 
Assume that we need to make a breaking change on our API, but we don’t want to break anything in our existing API which our customers are already using. How can we achieve this? Let us go and resolve a NuGet package Microsoft.AspNetCore.Mvc.Versioning.
 
Use the below command from the package manager console,
 
Install-Package Microsoft.AspNetCore.Mvc.Versioning
 
Once the package installation complete, let us configure the API to support versioning. This package basically has everything that we need.
Without any delay, let us go to class Startup.cs, where we are going to update the method ConfigurationServices as below
    public void ConfigureServices(IServiceCollection services) {  
        services.AddControllers();  
        services.AddApiVersioning();  
    }  


By adding these services.AddApiVersioning() method, we have some sort of versioning. However, we haven’t really told ASP.NETCore how we versioning the API. Without making any additional changes, let us run the API, we will get the below error message
    {"error":{"code":"ApiVersionUnspecified","message":"An API version is required, but was not specified.","innerError":null}}   

This is because we haven’t configured our API versioning to a default version. For us the first version apparently V1 or V1.0. The default way of this works in ASP.NET Core is to have the “API-version” query string parameter as below.
https://localhost:12345/api/products/00000000-0000-0000-0000-000000000000?api-version=1
 
Result will as below,
    {"id":"00000000-0000-0000-0000-000000000000","name":"Sanitizer"}   

This would work fine. However, this is not ideal because if we make this “api-version” query string is mandatory, many of our consumers’ code break. What we want to do instead is we want to enable the API versioning default to a version. How we can achieve this? Let us to the Startup.cs class again and make the below changes.
    public void ConfigureServices(IServiceCollection services) {  
        services.AddControllers();  
        services.AddApiVersioning(options => {  
            options.AssumeDefaultVersionWhenUnspecified = true;  
        });  
    }  

Let us execute the API again,
https://localhost:12345/api/products/00000000-0000-0000-0000-000000000000

    Result: {"id":"00000000-0000-0000-0000-000000000000","name":"Sanitizer"}   


Assume that, if we want to have a different version instead of V1.0 or V1. How can we achieve this?
 
First, we will make the below changes in Startup.cs class as below,
    public void ConfigureServices(IServiceCollection services) {  
        services.AddControllers();  
        services.AddApiVersioning(options => {  
            options.AssumeDefaultVersionWhenUnspecified = true;  
            options.DefaultApiVersion = ApiVersion.Default;  
        });  
    }  


Then make the below two changes.
 
Step 1
Add the below models in ProductResponse.cs Class,
    namespace AspNetCoreVersioning.Contracts {  
        public class ProductResponseV1 {  
            public Guid Id {  
                get;  
                set;  
            }  
            public string Name {  
                get;  
                set;  
            }  
        }  
        public class ProductResponseV2 {  
            public Guid Id {  
                get;  
                set;  
            }  
            public string ProductName {  
                get;  
                set;  
            }  
        }  
    }  

Step 2
Make the below changes into ProductsController.cs Class
    namespace AspNetCoreVersioning.Controllers {  
            [ApiController]  
            [Route("api/products")]  
            public class ProductsController: ControllerBase {  
                [HttpGet("{productId}")]  
                public IActionResult GetProductV1([FromRoute] Guid productId) {  
                        var product = new ProductResponseV1 {  
                            Id = productId,  
                                Name = "Sanitizer"  
                        };  
                        return Ok(product);  
                    }  
                    [HttpGet("{productId}")]  
                public IActionResult GetProductV2([FromRoute] Guid productId) {  
                    var product = new ProductResponseV2 {  
                        Id = productId,  
                            ProductName = "Sanitizer"  
                    };  
                    return Ok(product);  
                }  
            }  

Now Run the API. You will get the below Exception.
 
An unhandled exception occurred while processing the request.
 
AmbiguousMatchException: The request matched multiple endpoints. Matches,
    AspNetCoreVersioning.Controllers.ProductsController.GetProductV2 (AspNetCoreVersioning)  
    AspNetCoreVersioning.Controllers.ProductsController.GetProductV1 (AspNetCoreVersioning)  
    Microsoft.AspNetCore.Routing.Matching.DefaultEndpointSelector.ReportAmbiguity(CandidateState[] candidateState)
 

In order to resolve this error message, we need to make some configuration changes at ProductsController.cs Class as below,
    namespace AspNetCoreVersioning.Controllers {  
        [ApiController]  
        [Route("api/products")]  
        [ApiVersion("1.0")]  
        [ApiVersion("2.0")]  
        public class ProductsController: ControllerBase {  
            [HttpGet("{productId}")]  
            public IActionResult GetProductV1([FromRoute] Guid productId) {  
                    var product = new ProductResponseV1 {  
                        Id = productId,  
                            Name = "Sanitizer"  
                    };  
                    return Ok(product);  
                }  
                [HttpGet("{productId}")]  
                [MapToApiVersion("2.0")]  
            public IActionResult GetProductV2([FromRoute] Guid productId) {  
                var product = new ProductResponseV2 {  
                    Id = productId,  
                        ProductName = "Sanitizer"  
                };  
                return Ok(product);  
            }  
        }  
    }  


Now Run the API as below,
https://localhost:12345/api/products/00000000-0000-0000-0000-000000000000?api-version=1

    Result: {"id":"00000000-0000-0000-0000-000000000000","name":"Sanitizer"}   

https://localhost:12345/api/products/00000000-0000-0000-0000-000000000000?api-version=2

    Result: {"id":"00000000-0000-0000-0000-000000000000","productName":"Sanitizer"}   

I will be covering URL based and Header based versioning in the upcoming sessions. Thanks for reading my article. I appreciate your feedback in the comment section below.



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