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 :: ASP.NET Core 6.0 Middleware

clock July 26, 2022 08:00 by author Peter

Middleware is a component that is assembled into an application pipeline to handle requests and responses. Middleware is linked one after the other, so each gets to choose whether to pass the request to the next middleware and work before and after the next component in the pipeline.

Middleware:
    Sits between the requestor and the target.
    Can directly modify the response.
    Can log things.
    Can use the data within the request to generate the response.

Take look at the diagram below:

ASP.NET 6.0 implements a pipeline consisting of a series of middleware classes.

  • Requests filter down the pipeline until they reach a point where the middleware class creates a response.
  • Responses filter back through the middleware in reverse order until they reach the requestor.

Middleware is a great place to do the following:
    Authorization
    Authentication
    Diagnostics
    Error handling and logging

Each middleware consists of a request delegate. This is a specific kind of object in .NET that can pass execution control to the next object. Let us create a simple Web API project. For this tutorial I’m using the tools below:
    Visual Studio Community Edition 2022 (64-bit) – Preview (Version 17.3.0 Preview 4.0)
    .NET 6.0
    Minimal Web API
    Swagger

Please find the program.cs file part of the minimal API:
var builder = WebApplication.CreateBuilder(args);
// Add services to the container.
// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();
var app = builder.Build();
// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment()) {
    app.UseSwagger();
    app.UseSwaggerUI();
}
//I have commented out the below codes as we are going to check Use(), Map() and Run()
/* var summaries = new[]
{
    "Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching"
};
app.MapGet("/weatherforecast", () =>
{
    var forecast = Enumerable.Range(1, 5).Select(index =>
        new WeatherForecast
        (
            DateTime.Now.AddDays(index),
            Random.Shared.Next(-20, 55),
            summaries[Random.Shared.Next(summaries.Length)]
        ))
        .ToArray();
    return forecast;
})
.WithName("GetWeatherForecast"); */
app.Run();
/*internal record WeatherForecast(DateTime Date, int TemperatureC, string? Summary)
{
    public int TemperatureF => 32 + (int)(TemperatureC / 0.5556);

} */


If we run this project, you should get the below output.

Now let's create simple middleware that will return “Hello Readers!” as response. In Program.cs, we add a new middleware using Run() method like below. We normally call it inline middleware.
// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment()) {
    app.Run(async context => {
        await context.Response.WriteAsync("Hello Readers!");
    });
    app.UseSwagger();
    app.UseSwaggerUI();
}


Run the application. You should get the below output:

While going through each line of code in Program.cs, generally we identify which parts of the code are considered middleware by looking at the methods used to add them to the pipeline. Those methods are Run(), Use() and Map().

Let's look at each method to understand the usage and differences between them.
Run()

This method only receives only context parameter and doesn’t know about the next middleware. These delegates are usually known as terminal delegates because they terminate or end the middleware pipeline.

Let us add another delegate as below and see how it behaves:
// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment()) {
    app.Run(async context => {
        await context.Response.WriteAsync("Hello Readers!");
    });
    app.Run(async context => {
        await context.Response.WriteAsync("We are learning Middlware!");
    });
    app.UseSwagger();
    app.UseSwaggerUI();
}


Go head and run the application. You should get the below output:

The second delegate didn’t invoke here because the first one terminated the pipeline.
Use()

The whole idea behind middleware is to link one after another. Let us take a look at the Use() method, which helps us to chain the delegates one after the other.

This method will accept two parameters, context and next. Let us create a inline middleware using the Use() method:
// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment()) {
    app.Use(async (context, next) => {
        await context.Response.WriteAsync($ "Before Request {Environment.NewLine}");
        await next();
        await context.Response.WriteAsync($ "After Request {Environment.NewLine}");
    });
    app.Run(async context => {
        await context.Response.WriteAsync($ "Hello Readers!{Environment.NewLine}");
    });
    app.UseSwagger();
    app.UseSwaggerUI();
}


The output is given below:

This will show us that the middleware has been changed, one after another. Here, the await next() triggered the next middleware, which was implemented using the method Run().

Notes:
    Don’t call next.invoke after the response has been sent to client.
    Writing to the response body after calling next may cause a protocol violation.
    Writing to the response body after calling next may cause the body format

Map()
Map extensions are used for branching the pipeline. Map extensions branch the request pipeline based on matching the given request path. If the request path starts with the given path, the branch is executed.

Let us see two middleware, as below:
// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment()) {
    app.UseSwagger();
    app.UseSwaggerUI();
}
app.Map("/BranchOne", MapBranchOne);
app.Map("/BranchTwo", MapBranchTwo);
app.Run();
static void MapBranchOne(IApplicationBuilder app) {
    app.Run(async context => {
        await context.Response.WriteAsync("You are on Branch One!");
    });
}
static void MapBranchTwo(IApplicationBuilder app) {
    app.Run(async context => {
        await context.Response.WriteAsync("You are on Branch Two!");
    });
}


The output should be as below:
http://localhost:1233/branchone

http://localhost:1234/branchtwo


We have covered the basics of middleware. In the upcoming tutorial, I will be covering custom middleware. Thank you for reading my article. Please leave your comments in the comment box below.

HostForLIFE.eu 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.



ASP.NET Core Hosting - HostForLIFE :: Testing The Exception Thrown In NUnit C#

clock July 25, 2022 10:11 by author Peter

In this article, we will learn how to test the exception thrown by the test code using NUnit in .Net. While doing Unit testing, we write test cases for every possible positive as well as the negative scenario. In several test cases, there might be a situation or condition which throws an exception. In order to test those scenarios, we have to use Asset.Throws method. Asset.Throws attempts to invoke a code snippet represented as a delegate in order to verify that it throws a particular exception.

For demonstration, I already created a sample application “BankingApp” which is basically a .Net Core Class Library project.

A Test project named “BankingApp.Test” is also added to the Solution. I am using NUnit for writing the Unit Test case. In the Account.cs class, I have a parameterized constructor and two methods in which one is for adding the amount i.e. depositAmount() method, and another for checking the balance amount (i.e. checkBalanceAmount() method). In case the amount to be deposited is either zero or less than that, an exception (ArgumentException) will be thrown.

In AccountTest.cs file, I have written a test case in which the amount to be deposited is “-100” i.e. less than zero.

Now, let’s run the test case from the Test Explorer.

On running the test case, an Argument exception with a message i.e., “Amount to be deposit must be greater than zero” is thrown.

Let’s use the Assert.Throws() method and pass method as a delegate which is throwing the exception. In our case, it is depositAmount(). Assert.Throws require the exact type of exception which can be thrown. It returns the exception as well. With StringAssert.Contains() method, we can verify the expected exception text with the actual exception text.

Now run the test case. You can see that our test case is passed. In this example, we verified that on passing the deposit amount 0 or less than zero, an exception is properly thrown to the user.

HostForLIFE.eu 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 :: Feature Flags In ASP.NET Core

clock July 19, 2022 08:17 by author Peter

Feature flags allow toggling multiple features of an application without having to redeploy the application. One or more feature flags can be defined declaratively as part of the application’s config file that can control feature availability. Feature flag is part of a broader concept of feature management. Feature management provides additional functionality like filtering feature availability based on user groups, devices etc., caching feature flags and managing their states. In this article, we will focus on implementing feature flags using ASP.NET Core feature management package.

Setup
Consider you have a simple ASP.NET 6 MVC application for creating a todo list. To keep this article focused on the subject, I will omit the steps for creating such application. Typically, the application would be capable of adding new todo items to a list of todos and displaying them on the screen.

To work with ASP.NET Core feature management, add Microsoft.FeatureManagement.AspNetCore nuget package to the application. Add the feature management service to the application inside Program.cs
using Microsoft.FeatureManagement;

namespace FeatureFlagDemo;

public class Program
{
    public static void Main(string[] args)
    {
        var builder = WebApplication.CreateBuilder(args);
        // Add services to the container.
        ...
        builder.Services.AddFeatureManagement();
        ...
        var app = builder.Build();
        ...
    }
}


Adding feature flags to the configuration
We will expose two feature flags – one for enabling edit of the todo item and another for enabling delete of the todo item. Add the feature flags to the appsettings.json file under FeatureManagement section as follows
{
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft.AspNetCore": "Warning"
    }
  },
  "FeatureManagement": {
    "Edit": false,
    "Delete": false
  },
  "AllowedHosts": "*"
}


Note both the features are disabled in the configuration file.

FeatureGate attribute
To enable the feature flags at controller or action level, we can use the FeatureGate attribute as shown below.
[HttpGet]
[FeatureGate("Edit")]
public ActionResult Edit(int id)
{
    ...
}

[HttpPost]
[FeatureGate("Edit")]
[ValidateAntiForgeryToken]
public ActionResult Edit(int id, TodoItem todoItem)
{
    ...
}


Applying the attribute for all actions related to the Edit feature will ensure that the actions are available only when the Edit feature flag is enabled.

Add similar code for handling Delete feature.
[HttpGet]
[FeatureGate("Delete")]
public ActionResult Delete(int id)
{
    ...
}

[HttpPost]
[FeatureGate("Delete")]
[ValidateAntiForgeryToken]
public ActionResult Delete(int id, TodoItem todoItem)
{
    ...
}


Note: Part of code is omitted for brevity and to remain focused on the topic. In production scenarios, consider appropriate measures for implementing the feature including security, performance etc.
<feature> tag helper

The <feature> tag can be used to conditionally render text on razor views depending upon the state of feature flags. Import the feature management tag helpers inside the _ViewImports.cshtml file.
@using FeatureFlagDemo
@using FeatureFlagDemo.Models
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
@addTagHelper *, Microsoft.FeatureManagement.AspNetCore


Inside razor view, use the <feature> tag as follows to conditionally render Edit and Delete options based on the state of their respective feature flags.
<feature name="Edit"><a asp-action="Edit" asp-route-id="@item.Id">Edit</a></feature>
<feature name="Delete"><a asp-action="Delete" asp-route-id="@item.Id">Delete</a></feature>


Toggling feature flags and testing
Initially both the feature flags are disabled. Upon running the application, none of the Actions (Edit / Delete) are visible on the razor view.

Enable Edit feature by toggling the Edit feature flag in the appsettings.json file
{
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft.AspNetCore": "Warning"
    }
  },
  "FeatureManagement": {
    "Edit": true,
    "Delete": false
  },
  "AllowedHosts": "*"
}


Refresh the page and you should be able to see Edit feature enabled. Upon clicking edit link you can also confirm that the actions related to edit feature are being executed as per the implementation.

Enable Delete feature by toggling the Delete feature flag in the appsettings.json file
{
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft.AspNetCore": "Warning"
    }
  },
  "FeatureManagement": {
    "Edit": true,
    "Delete": true
  },
  "AllowedHosts": "*"
}


Refresh the page and you should be able to see Delete feature enabled. Upon clicking delete link you can also confirm that the actions related to delete feature are being executed as per the implementation.

HostForLIFE.eu 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 :: Label Control In ASP.NET

clock July 15, 2022 08:39 by author Peter

In this article, you will learn how to use Label in ASP.NET Framework and how Label works.

What are Label Controls

    The label control is used to display text on a website.
    It is primarily used to generate captions for other controls such as textboxes.
    Labels typically assist the user in entering data into text boxes by providing written instructions.
    Labels are controls on the server-side.
    The Label class can be found in the System.Web.UI.WebControls namespace.

Adding Label Control
    To create a label, we can either write code or use Visual Studio's drag and drop feature.
    This is a server-side control, and asp provides its own tag for label creation.

The following is an example and syntax to add label control.
<asp:Label_ID="LabelNew" runat="'server" Text="Label_Control"></asp:Label>
here Runat='Server' Indicates the accessibility of the control at Serverside

Properties of Label Control
Label Control has its own properties that will be used to improve it. (Syntax for each label control property is given in ASP.NET code)

AccessKey

Accesskey is used to add the keyboard shortcut for the label.
<asp:webcontrol id="id" AccessKey="accessKey" runat="server" />

Tablndex
It determines the webserver's tab control index.
<asp:TextBox ID="txtName" runat="server" TabIndex="0"></asp:TextBox>

BackColor
This property is used to change the look and make it with different colours.
<asp:webcontrol id="id" BackColor="color" runat="server" />

BorderColor
We can use this property to change the colour of the label border.
<asp:webcontrol id="id" BorderColor="color" runat="server" />

BorderWidth
This property will allow us to specify the width of the label border.
<asp:webcontrol id="id" BorderWidth="length" runat="server" />

Font
This property will allow us to specify the width of the label border.
<asp:webcontrol id="id" font-subproperty="value" runat="server" />

Forecolor
It's used to change the colour of the label text.
<asp:webcontrol id="id" ForeColor="color" runat="server" />

Text
This property makes use of text that must be displayed for the label.
<asp:HyperLink Text="string" runat="server" />

ToolTip
It specifies the text that will be displayed when we move the mouse over a label.
<asp:webcontrol id="id" ToolTip="string" runat="server" />

Visible
It will allow us to customise the control's visibility on the web form.
<asp:webcontrol id="id" Visible="True|False" runat="server" />

Height
It allows us to customise the height of the label control.
<asp:Image ID="Image1" runat="server" Height="value" />

Width
It allows us to adjust the width of the label control.
<asp:Image ID="Image1" runat="server"  Width="value" />

BorderStyle
The border of the label control can be designed to meet the needs of the application.
<asp:webcontrol id="id" BorderStyle="style" runat="server" />

CssClass
It gives us the CSS class of the label control.
<asp:webcontrol id="id" CssClass="style" runat="server" />

Events for Label Controls
DataBinding

When the server control binds to a data source, this is referred to as data binding.

Disposed
When an ASP.NET page is requested, a server control is released from memory, which is the final stage of the server control lifecycle.

Init
Occurs during the initialization of the server control, which is the first step in its lifecycle.

Load
When the server control is loaded into the Page object, this event occurs.

PreRender
This occurs after the Control object has been loaded but before rendering.

Unload
This happens when the server control is loaded from memory.

Methods for Label Control
DataBind()
Binds a data source to the server control that was invoked and all of its child controls.

Dispose()
Allows a server control to perform final cleanup before releasing it from memory.

Equals(Object)
Checks whether the specified object is the same as the current object.

Focus()
Sets a control's input focus.

OnLoad(EventArgs)
The Load event is raised.

ToString()
This method returns a string that represents the current object.

Conclusion
Here, we have learned how label works in ASP.NET Framework and how label controls are useful for us to use.

If you have any queries/suggestions on the article, please leave your questions and thoughts in the comment section below. Follow C# Corner to learn more new and amazing things about ASP.NET or to explore more technologies.

HostForLIFE.eu 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 :: Complete Signup-Login System Using Dependency

clock July 12, 2022 08:50 by author Peter

There are various methods available to create a login system but here I'm introducing a way to design complete signup and login system using dependencies in asp.net core with SQL database.

What is a dependency?
The term dependency means to depend on anyone else which means if an object is dependent on other objects that is called a dependency. Dependency is a relationship between a component or class that can be thought of as a uses relationship generally the parameterized constructor that provides an object for a needed class. If you have more than one class that class is dependent on each other that is dependency. The dependency is injected into a parameterized constructor.

Step 1
Create a database from MSSQL.
create database dependencylogin
use dependencylogin;
create table users(id int primary key, Name varchar(50), Email varchar(50), Password varchar(50));
select * from users


Step 2
Create a table from the database and id is the primary key as well as identity with autoincrement.

Step 3
Open visual studio 2022 and click create a new project.


Step 4
Select ASP.Net core web App project and click on the Next button.


Step 5
Write the name of the project and click on the Next button.

Step 6
Click on the Create button for creating a project.

Step 7
Now my project is ready for use.

Step 8
Here create a new folder on solution explorer. Right-click on the project name in solution explorer and select Add option then select the new folder option then write the name of the folder.


Write the folder name as Models.

Step 9
In Models, folder right-click to choose to Add option and move to the class option, create a class with the class name as a connection.


 

Step 10
To make a property connection string name then create a constructor and pass the connection string.
namespace signuploginproject.Models
{
    public class connection
    {
        public string ConnectionString { get; set; }
        public connection()
        {
            this.ConnectionString = @"Data Source=LAPTOP-2L6RE54T;Initial Catalog=dependencylogin;Integrated Security=True";

        }
    }
}


Step 11
To install the System.Data.SqlClient package from NuGet Package Manager.


Step 12
Similar to creating another class on the Models folder the class name is DAL. Make a connection class object and pass  under the constructor.
using System.Data.SqlClient;
namespace signuploginproject.Models
{
    public class DAL
    {
        connection conn;
        public DAL(connection conn)
        {
            this.conn = conn;

        }
        public string GetValue(string query)
        {
            SqlConnection sqlconnection = new SqlConnection(conn.ConnectionString);
            SqlCommand cmd = new SqlCommand();
            cmd.Connection = sqlconnection;
            cmd.CommandText = query;
            sqlconnection.Open();
            var res = cmd.ExecuteScalar();
            sqlconnection.Close();
            return res.ToString();
        }
        public void SetValue(string query)
        {
            SqlConnection sqlconnection = new SqlConnection(conn.ConnectionString);
            SqlCommand cmd = new SqlCommand();
            cmd.Connection = sqlconnection;
            cmd.CommandText = query;
            sqlconnection.Open();
            cmd.ExecuteNonQuery();
            sqlconnection.Close();

        }
    }
}


Step 13
Similarly create one more class on the Models folder. The class name is Logics. Here create a DAL class object and pass a Logics class constructor. A Logic class makes two different functions for login and signup.
namespace signuploginproject.Models
{
    public class Logics
    {
        DAL DL;
        public Logics(DAL dl)
        {
            DL = dl;
        }
        public bool Login(string email, string password)
        {
            string query = $"select password from users where email='{email}'";
            var res = DL.GetValue(query);
            return res == password;
        }
        public string submitdata(string name, string email, string password)
        {
            string query = $"insert into users (name,email,password) values ('{name}','{email}','{password}')";
            DL.SetValue(query);
            return "Data submitted";

        }
    }
}

Step 14
Design an Index page for the Login page.
@page
@model IndexModel
@{
    ViewData["Title"] = "Home page";
}
<div class="container" style="width:30%">
  <center>
    <h2>Login</h2>
  </center>
  <form method="post">
    <div class="mb-3">
      <label class="form-label">Email</label>
      <input type="email" name="email" class="form-control">
    </div>
    <div class="mb-3">
      <label class="form-label">Password</label>
      <input type="password" name="password" class="form-control">
    </div>
    <div class="btn-group" style="margin-top:15px;">
      <button type="submit" class="btn btn-success">Submit</button>
    </div>
  </form>
  <center>
    <p>if you don't have an account to click <a href="/Signup"> Signup</a>
    </p>
  </center>
</div>


Login page


Step 15
Write a code on the Index model page.
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
using signuploginproject.Models;
namespace signuploginproject.Pages {
    public class IndexModel: PageModel {
        private readonly ILogger < IndexModel > _logger;
        public IndexModel(ILogger < IndexModel > logger, Logics logic) {
            _logger = logger;
            this.logi = logic;
        }
        public void OnGet() {}
        Logics logi;
        public IActionResult OnPost(string email, string password) {
            bool res = logi.Login(email, password);
            if (res == true) {
                return Redirect("/dashboard");
            } else {
                return Redirect("/error");
            }
        }
    }
}

Step 16
Create a new razor page for signup and design a signup form.
@page
@model signuploginproject.Pages.signupModel
@{
}
<div class="container" style="width:30%">
  <center>
    <h2>Signup</h2>
  </center>
  <form method="post">
    <div class="mb-3">
      <label class="form-label">Name</label>
      <input type="text" name="name" class="form-control">
    </div>
    <div class="mb-3">
      <label class="form-label">Email</label>
      <input type="email" name="email" class="form-control">
    </div>
    <div class="mb-3">
      <label class="form-label">Password</label>
      <input type="password" name="password" class="form-control">
    </div>
    <div class="btn-group" style="margin-top:15px;">
      <button type="submit" class="btn btn-success">Submit</button>
    </div>
  </form>
  <center>
    <p>Have an account to click <a href="/Index"> Login</a>
    </p>
  </center>
</div>


Signup Page


Step 17
Write code on the signup model page.
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
using signuploginproject.Models;
namespace signuploginproject.Pages {
    public class signupModel: PageModel {
        public signupModel(Logics logic) {
            this.logi = logic;
        }
        public void OnGet() {}
        Logics logi;
        public IActionResult OnPost(string name, string email, string password) {
            var rees = logi.submitdata(name, email, password);
            return Redirect("/index");
        }
    }
}

Step 18
Create a new razor page for the dashboard page and write the code.
@page
@model signuploginproject.Pages.dashboardModel
@{
}
<h1>Dashboard</h1>


Dashboard Page


Step 19
Add the services to the program.cs file for providing a class object when needed. To click on the program.cs file and write the code on container services.


To build and execute the project.

HostForLIFE.eu 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 :: Custome JWT Token And ASP.NET Core Web API

clock July 11, 2022 08:34 by author Peter

In this article, I am explaining how to implement custom JWT token authentication in ASP.NET Core 3.1 API. For this, I have created the demo application which has two controllers “AthenticateController” and “UserController”.

AthenticateController has one endpoint “AuthenticateUser”, which will authenticate the user based on the user id and password and if user is valid then it will generate the JWT Token.

UserController has two endpoints “GetUsers” and “GetUserById”.

GetUsers
I have implemented Authorization filter to secure the endpoint and this endpoint accepts HTTP GET requests and returns a list of all the users in the application if the HTTP Authorization header contains a valid JWT token. If there is no auth token or the token is invalid, then a 401 Unauthorized response is returned.

Similarly, GetUserById returns user details by id if the HTTP Authorization header contains a valid JWT token.

Project Architecture

Below is the project Architecture,


Follow below steps for project set up and generate JWT token:

Step 1
Create the ASP.NET Core 3.1 Web API Application. I am giving application name as “JWTTokenPOC”

Step 2
Install “Microsoft.AspNetCore.Authentication.JwtBearer” using NuGet Package manager. I have installed 3.1.26 version.

Step 3
Create new folder “Entities” inside the solution and create an entity class “User”
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using System.Text.Json.Serialization;
namespace JWTTokenPOC.Entities {
    public class User {
        public int Id {
            get;
            set;
        }
        public string FirstName {
            get;
            set;
        }
        public string LastName {
            get;
            set;
        }
        public string Username {
            get;
            set;
        }
        [JsonIgnore]
        public string Password {
            get;
            set;
        }
    }
}


Step 4
Create new folder Models inside the solution and create two models AuthenticateRequest and AuthenticateResponse.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using System.ComponentModel.DataAnnotations;
namespace JWTTokenPOC.Models {
    public class AuthenticateRequest {
        [Required]
        public string UserName {
            get;
            set;
        }
        [Required]
        public string Password {
            get;
            set;
        }
    }
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using JWTTokenPOC.Entities;
namespace JWTTokenPOC.Models {
    public class AuthenticateResponse {
        public int Id {
            get;
            set;
        }
        public string FirstName {
            get;
            set;
        }
        public string LastName {
            get;
            set;
        }
        public string Username {
            get;
            set;
        }
        public string Token {
            get;
            set;
        }
        public AuthenticateResponse(User user, string token) {
            Id = user.Id;
            FirstName = user.FirstName;
            LastName = user.LastName;
            Username = user.Username;
            Token = token;
        }
    }
}


Step 5
Create new folder “Helper” inside the solution and create two helper classes “AppSettings” and “AuthorizeAttribute” in that folder.
namespace JWTTokenPOC.Helper {
    public class AppSettings {
        public string Key {
            get;
            set;
        }
        public string Issuer {
            get;
            set;
        }
    }
}
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Filters;
using JWTTokenPOC.Entities;
namespace JWTTokenPOC.Helper {
    [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)]
    public class AuthorizeAttribute: Attribute, IAuthorizationFilter {
        public void OnAuthorization(AuthorizationFilterContext context) {
            var user = context.HttpContext.Items["User"];
            if (user == null) {
                // user not logged in
                context.Result = new JsonResult(new {
                    message = "Unauthorized"
                }) {
                    StatusCode = StatusCodes.Status401Unauthorized
                };
            }
        }
    }
}


Step 6
Add below appsetting in appsettings.json file.
"AppSettings": {
    "Key": "986ghgrgtru989ASdsaerew13434545435",
    "Issuer": "atul1234"
}

Step 7
Create new folder “Service” inside the solution and create two service classes “AuthenticationService” and “UserService” in that folder.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using JWTTokenPOC.Entities;
namespace JWTTokenPOC.Service {
    public interface IUserService {
        User GetById(int id);
        IEnumerable < User > GetAll();
    }
    public class UserService: IUserService {
        // List of user
        private List < User > _users = new List < User > {
            new User {
                Id = 1, FirstName = "mytest", LastName = "User", Username = "mytestuser", Password = "test123"
            },
            new User {
                Id = 2, FirstName = "mytest2", LastName = "User2", Username = "test", Password = "test"
            }
        };
        public IEnumerable < User > GetAll() {
            return _users;
        }
        public User GetById(int id) {
            return _users.FirstOrDefault(x => x.Id == id);
        }
    }
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.IdentityModel.Tokens;
using System.IdentityModel.Tokens.Jwt;
using System.Security.Claims;
using Microsoft.Extensions.Options;
using System.Text;
using JWTTokenPOC.Entities;
using JWTTokenPOC.Helper;
using JWTTokenPOC.Models;
namespace JWTTokenPOC.Service {
    public interface IAuthenticationService {
        AuthenticateResponse Authenticate(AuthenticateRequest model);
    }
    public class AuthenticationService: IAuthenticationService {
        // here I have  hardcoded user for simplicity
        private List < User > _users = new List < User > {
            new User {
                Id = 1, FirstName = "mytest", LastName = "User", Username = "mytestuser", Password = "test123"
            }
        };
        private readonly AppSettings _appSettings;
        public AuthenticationService(IOptions < AppSettings > appSettings) {
            _appSettings = appSettings.Value;
        }
        public AuthenticateResponse Authenticate(AuthenticateRequest model) {
            var user = _users.SingleOrDefault(x => x.Username == model.UserName && x.Password == model.Password);
            // return null if user not found
            if (user == null) return null;
            // authentication successful so generate jwt token
            var token = generateJwtToken(user);
            // Returns User details and Jwt token in HttpResponse which will be user to authenticate the user.
            return new AuthenticateResponse(user, token);
        }
        //Generate Jwt Token
        private string generateJwtToken(User user) {
            var securityKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_appSettings.Key));
            var credentials = new SigningCredentials(securityKey, SecurityAlgorithms.HmacSha256);
            // Here you  can fill claim information from database for the users as well
            var claims = new [] {
                new Claim("id", user.Id.ToString()),
                    new Claim(JwtRegisteredClaimNames.Sub, "atul"),
                    new Claim(JwtRegisteredClaimNames.Email, ""),
                    new Claim("Role", "Admin"),
                    new Claim(JwtRegisteredClaimNames.Jti, Guid.NewGuid().ToString())
            };
            var token = new JwtSecurityToken(_appSettings.Issuer, _appSettings.Issuer, claims, expires: DateTime.Now.AddHours(24), signingCredentials: credentials);
            return new JwtSecurityTokenHandler().WriteToken(token);
        }
    }
}


Step 8
Now inside Helper folder create a JwtMiddleware class. This class will be used to validate the token and it will be registered as middleware.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Options;
using Microsoft.IdentityModel.Tokens;
using JWTTokenPOC.Service;
using System.IdentityModel.Tokens.Jwt;
using System.Text;
namespace JWTTokenPOC.Helper {
    public class JwtMiddleware {
        private readonly RequestDelegate _next;
        private readonly AppSettings _appSettings;
        public JwtMiddleware(RequestDelegate next, IOptions < AppSettings > appSettings) {
            _next = next;
            _appSettings = appSettings.Value;
        }
        public async Task Invoke(HttpContext context, IUserService userService) {
            var token = context.Request.Headers["Authorization"].FirstOrDefault()?.Split(" ").Last();
            if (token != null)
                //Validate the token
                attachUserToContext(context, userService, token);
            await _next(context);
        }
        private void attachUserToContext(HttpContext context, IUserService userService, string token) {
            try {
                var tokenHandler = new JwtSecurityTokenHandler();
                var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_appSettings.Key));
                tokenHandler.ValidateToken(token, new TokenValidationParameters {
                    ValidateIssuerSigningKey = true,
                        ValidateAudience = true,
                        ValidateLifetime = true,
                        IssuerSigningKey = key,
                        ValidIssuer = _appSettings.Issuer,
                        ValidAudience = _appSettings.Issuer,
                        // set clockskew to zero so tokens expire exactly at token expiration time.
                        ClockSkew = TimeSpan.Zero
                }, out SecurityToken validatedToken);
                var jwtToken = (JwtSecurityToken) validatedToken;
                var userId = int.Parse(jwtToken.Claims.First(x => x.Type == "id").Value);
                // attach user to context on successful jwt validation
                context.Items["User"] = userService.GetById(userId);
            } catch (Exception) {
                // do nothing if jwt validation fails
                // user is not attached to context so request won't have access to secure routes
            }
        }
    }
}

Step 9
Now open the statrtup.cs file. In the ConfigureServices method, add CORS policy and add the services as below.
public void ConfigureServices(IServiceCollection services) {
    services.AddCors();
    services.AddControllers();
    // configure to get Appsetting section from appsetting.json
    services.Configure < AppSettings > (Configuration.GetSection("AppSettings"));
    services.AddScoped < IUserService, UserService > ();
    services.AddScoped < IAuthenticationService, AuthenticationService > ();
}

Step 10
In the Configure method, set CORS policy and register the JWT middleware as below.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env) {
    app.UseRouting();
    // set global cors policy
    app.UseCors(x => x.AllowAnyOrigin().AllowAnyMethod().AllowAnyHeader());
    // Custom jwt auth middleware to authenticate the token
    app.UseMiddleware < JwtMiddleware > ();
    app.UseEndpoints(endpoints => {
        endpoints.MapControllers();
    });
}


Step 11
Now build and run the application.

Step 12
Open Postman tool and generate the JWT token as below:

    Click on the New icon as shown in the below image and create a New Http Request. I have given Http Request name as “AuthToken”.
    Change the http request method to "GET" with the dropdown selector on the left of the URL input field.
    In the URL field enter the address to the route of your local API http://localhost:60119/Authenticate/authenticate.
    Select the "Body" tab below the URL field, change the body type radio button to "raw", and change the format dropdown selector to "JSON (application/json)".
    Enter a JSON object containing the test username and password in the "Body" text
    {
        "username": "mytestuser",
        "password": "test123"
    }


Click the "Send" button, you should receive a "200 OK" response with the user details including a JWT token in the response body, make a copy of the token value because we'll be using it in the next step to make an authenticated request.


 

HostForLIFE.eu ASP.NET Core Hosting

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



European ASP.NET Core Hosting :: ASP.NET Core - Middleware

clock July 8, 2022 07:39 by author Peter

Middleware is a newly introduced concept in asp.net core. I have split this topic into two parts. In the first part we will cover,

    HTTP Request Pipeline
    What is Middleware?
    How to configure Middleware
    Run() Method
    Use() Method
    Next() Method
    Map() Method

This article can be used by beginners, intermediates, and professionals.

Before we start with Middleware, we should have a good understanding of the HTTP Pipeline hence we will discuss the HTTP pipeline first and then move to Middleware.
HTTP Request Pipeline

Let’s say, we have an MVC application, and we got a request from the browser.

Please see the below diagram for the HTTP request pipeline of the above scenario.


As per the above diagram, the flow of the execution would be,

    The browser sent a request to the HTTP request pipeline.
    HTTP pipeline will execute.
    Once HTTP pipeline execution will be completed, the request goes to the MVC application.
    MVC Application executes the request and sends the response back to the HTTP Request pipeline -> Browser.

Now we will discuss Middleware.
What is Middleware?

Middleware is a core functionality of Asp.net Core. It is nothing but a class or component that will execute on each request.

If you worked on Asp.net before, you might be aware of HTTPhandler and HTTPModular which were part of the HTTP Request Pipeline. Middleware is like that only in the Asp.net Core HTTP request pipeline.

Let’s see the below image to get a better understanding of Middleware.

As we can see in the above diagram, There will be multiple middlewares in the asp.net core application and each middleware will be called one after the others in the pre-defined sequence. Please note that the order of the middleware matters a lot in the HTTP pipeline execution.

Each middleware will complete the task before and after the next middleware in the pipeline. It will also decide whether to pass the request to the next middleware or not.

We can have multiple middlewares in Asp.net Core Applications and it can be added through
    NuGet packages
    Custom Middleware – Project/Application specific.

How to configure Middleware
Middleware can be configured using Run(),Use() and Map() extension Methods.
Let's discuss the below code before we start a discussion on middleware,
public void Configure(IApplicationBuilder app, IWebHostEnvironment env) {
    if (env.IsDevelopment()) {
        app.UseDeveloperExceptionPage();
    } else {
        app.UseExceptionHandler("/Home/Error");
        // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
        app.UseHsts();
    }
    app.UseHttpsRedirection();
    app.UseStaticFiles();
    app.UseRouting();
    app.UseAuthorization();
    app.UseEndpoints(endpoints => {
        endpoints.MapControllerRoute(name: "default", pattern: "{controller=Home}/{action=Index}/{id?}");
    });
}


We have created the Asp.net core MVC application. Open StartUp.cs file -> Configure method.
Now we will add new middleware in the above code,
In Asp.Net core 5.0, we can configure middleware in the configure method of the startup class using IApplicationBuilder and Run/Use/Map extension methods.
In Asp.Net core 6.0, We don’t have to configure the method hence we can add the same middleware code after the builder.build() method.

We have used Asp.net core 5.0 in the below example,
public void Configure(IApplicationBuilder app, IWebHostEnvironment env) {
    app.Run(async (context) => {
        await context.Response.WriteAsync("Hello world!");
    });
    if (env.IsDevelopment()) {
        app.UseDeveloperExceptionPage();
    } else {
        app.UseExceptionHandler("/Home/Error");
        // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
        app.UseHsts();
    }
    app.UseHttpsRedirection();
    app.UseStaticFiles();
    app.UseRouting();
    app.UseAuthorization();
    app.UseEndpoints(endpoints => {
        endpoints.MapControllerRoute(name: "default", pattern: "{controller=Home}/{action=Index}/{id?}");
    });
}


In the above code, we have created simple Middleware using the Run() method. We will execute the code and see the output,

Output

You must notice that only the first middleware executes, and is then completed, other middlewares are not executed after the first middleware. This happened because we have used the Run () extension method to add middleware in the pipeline.

Let's discuss extension methods to configure middleware in the Request Pipelines.

Run() Method
Run() method is used to complete the middleware execution.

Syntax

using Microsoft.AspNetCore.Http;
namespace Microsoft.AspNetCore.Builder {
    //
    // Summary:
    //     Extension methods for adding terminal middleware.
    public static class RunExtensions {
        //
        // Summary:
        //     Adds a terminal middleware delegate to the application's request pipeline.
        //
        // Parameters:
        //   app:
        //     The Microsoft.AspNetCore.Builder.IApplicationBuilder instance.
        //
        //   handler:
        //     A delegate that handles the request.
        public static void Run(this IApplicationBuilder app, RequestDelegate handler);
    }
}

We have used the same method to create middleware in the last example.

Use() Method
Use() method is used to insert a new middleware in the pipeline.

Syntax
using Microsoft.AspNetCore.Http;
using System;
using System.Threading.Tasks;
namespace Microsoft.AspNetCore.Builder {
    //
    // Summary:
    //     Extension methods for adding middleware.
    public static class UseExtensions {
        //
        // Summary:
        //     Adds a middleware delegate defined in-line to the application's request pipeline.
        //
        // Parameters:
        //   app:
        //     The Microsoft.AspNetCore.Builder.IApplicationBuilder instance.
        //
        //   middleware:
        //     A function that handles the request or calls the given next function.
        //
        // Returns:
        //     The Microsoft.AspNetCore.Builder.IApplicationBuilder instance.
        public static IApplicationBuilder Use(this IApplicationBuilder app, Func < HttpContext, Func < Task > , Task > middleware);
    }
}


Let's see the below code to get a better understanding,
public void Configure(IApplicationBuilder app, IWebHostEnvironment env) {
    app.Use(async (context, next) => {
        await context.Response.WriteAsync("Hello World From 1st Middleware!");
    });
    if (env.IsDevelopment()) {
        app.UseDeveloperExceptionPage();
    } else {
        app.UseExceptionHandler("/Home/Error");
        // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
        app.UseHsts();
    }
    app.UseHttpsRedirection();
    app.UseStaticFiles();
    app.UseRouting();
    app.UseAuthorization();
    app.UseEndpoints(endpoints => {
        endpoints.MapControllerRoute(name: "default", pattern: "{controller=Home}/{action=Index}/{id?}");
    });
}


Output

Next Method
The next () method is used to pass the execution to the next middleware.

We will use the next method to call the next middleware. We will add one more middleware in the previous example and call the next method.

Let’s see the below code of the same,
public void Configure(IApplicationBuilder app, IWebHostEnvironment env) {
    app.Use(async (context, next) => {
        await context.Response.WriteAsync("Hello World From 1st Middleware!");
        await next();
    });
    app.Run(async (context) => {
        await context.Response.WriteAsync("Hello World From 2st Middleware!");
    });
    if (env.IsDevelopment()) {
        app.UseDeveloperExceptionPage();
    } else {
        app.UseExceptionHandler("/Home/Error");
        // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
        app.UseHsts();
    }
    app.UseHttpsRedirection();
    app.UseStaticFiles();
    app.UseRouting();
    app.UseAuthorization();
    app.UseEndpoints(endpoints => {
        endpoints.MapControllerRoute(name: "default", pattern: "{controller=Home}/{action=Index}/{id?}");
    });
}


You might notice the Next() method in the middleware. This method is responsible to invoke the next middleware component from the current Middleware.

public void Configure(IApplicationBuilder app, IWebHostEnvironment env) {
    app.Use(async (context, next) => {
        await context.Response.WriteAsync("Hello World From 1st Middleware!");
        await next();
    });
    app.Run(async (context) => {
        await context.Response.WriteAsync("Hello World From 2st Middleware!");
    });
    if (env.IsDevelopment()) {
        app.UseDeveloperExceptionPage();
    } else {
        app.UseExceptionHandler("/Home/Error");
        // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
        app.UseHsts();
    }
    app.UseHttpsRedirection();
    app.UseStaticFiles();
    app.UseRouting();
    app.UseAuthorization();
    app.UseEndpoints(endpoints => {
        endpoints.MapControllerRoute(name: "default", pattern: "{controller=Home}/{action=Index}/{id?}");
    });
}


Output


As we have used the next method hence both middlewares is called.
Map()

Map() method is used to map the middleware to a specific URL

Syntex
using Microsoft.AspNetCore.Http;
using System;
namespace Microsoft.AspNetCore.Builder {
    //
    // Summary:
    //     Extension methods for the Microsoft.AspNetCore.Builder.Extensions.MapMiddleware.
    public static class MapExtensions {
        //
        // Summary:
        //     Branches the request pipeline based on matches of the given request path. If
        //     the request path starts with the given path, the branch is executed.
        //
        // Parameters:
        //   app:
        //     The Microsoft.AspNetCore.Builder.IApplicationBuilder instance.
        //
        //   pathMatch:
        //     The request path to match.
        //
        //   configuration:
        //     The branch to take for positive path matches.
        //
        // Returns:
        //     The Microsoft.AspNetCore.Builder.IApplicationBuilder instance.
        public static IApplicationBuilder Map(this IApplicationBuilder app, PathString pathMatch, Action < IApplicationBuilder > configuration);
        //
        // Summary:
        //     Branches the request pipeline based on matches of the given request path. If
        //     the request path starts with the given path, the branch is executed.
        //
        // Parameters:
        //   app:
        //     The Microsoft.AspNetCore.Builder.IApplicationBuilder instance.
        //
        //   pathMatch:
        //     The request path to match.
        //
        //   preserveMatchedPathSegment:
        //     if false, matched path would be removed from Request.Path and added to Request.PathBase.
        //
        //   configuration:
        //     The branch to take for positive path matches.
        //
        // Returns:
        //     The Microsoft.AspNetCore.Builder.IApplicationBuilder instance.
        public static IApplicationBuilder Map(this IApplicationBuilder app, PathString pathMatch, bool preserveMatchedPathSegment, Action < IApplicationBuilder > configuration);
    }
}

Let's discuss the below example for more understanding of the Map extension method.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env) {
    app.Map("/testMap", testExample);
    if (env.IsDevelopment()) {
        app.UseDeveloperExceptionPage();
    } else {
        app.UseExceptionHandler("/Home/Error");
        // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
        app.UseHsts();
    }
    app.UseHttpsRedirection();
    app.UseStaticFiles();
    app.UseRouting();
    app.UseAuthorization();
    app.UseEndpoints(endpoints => {
        endpoints.MapControllerRoute(name: "default", pattern: "{controller=Home}/{action=Index}/{id?}");
    });
}
private void testExample(IApplicationBuilder app) {
    app.Run(async (context) => {
        await context.Response.WriteAsync("\n" + "Hello World From TestExample!");
    });
}


In the above example,
    app.map method, “/testMap” is a path and the second parameter (“testExample”) is a function name.
    Once you will pass “testMap in the requested path, it will try to match and call the testExample function in case of matching.

Output

That’s all for this article. We will discuss this more in the next article.



European ASP.NET Core Hosting :: Working With ASP.NET 6 IDistributedCache Provider For NCache

clock July 7, 2022 09:52 by author Peter

Key Takeaways
    NCache is an open-source distributed in-memory cache developed natively in .NET and .NET Core that helps such applications to process fast and scale out with ease.
    Caching is a proven technique used to hold and readily use frequently accessed data.
    This article presents a discussion and implementation of how we can work with NCache IDistributedCache provider using .NET 6.

Introduction

In this post, we'll look at how to implement distributed caching in ASP.NET Core using NCache as the cache provider. A cache is a type of high-speed memory that applications use to store frequently accessed data. It reduces the unnecessary database hits since the data being requested is readily available in the cache. Caching is a well-known approach for boosting application performance.

What is distributed caching
A distributed cache is a cache that is shared by several app servers and is frequently managed as a separate service from the app servers that use it.

A distributed cache can go beyond the memory restrictions of a single computer by connecting multiple computers, which is known as a distributed architecture or a distributed cluster, for increased capacity and processing power.

An ASP.NET Core project's efficiency and scalability can be improved by using a distributed cache, especially if the application is hosted by a cloud service or a server farm. In high-data-volume and high-load applications, distributed caches are extremely useful. The distributed design allows for gradual expansion and scalability by adding more computers to the cluster, allowing the cache to expand in sync with the data growth.

The advantages of distributed cache are:
    Cached data is consistent across all web servers. The user gets the same results regardless of which web server serves their request.
    Web server restarts and deployments do not affect cached data. Individual web servers can be added or removed with no effect on the cache.
    Doesn't use local memory.

What is NCache?
NCache is a free, open-source distributed in-memory cache written in.NET and.NET Core. NCache is a distributed cache that saves application data while avoiding costly database trips. It's lightning-fast and linearly scalable. NCache can be utilized to reduce performance constraints caused by data storage and databases, as well as to enable your.NET Core applications to manage high-volume transaction processing (XTP). It can be used both locally and as a distributed cache cluster for ASP.NET Core apps hosted on Azure or other platforms.

Distributed Caching in ASP.NET Core
Using the IDistributedCache interface provided by dotnetcore, we can connect our ASP.NET Core apps to any distributed cache cluster and utilize it for caching as needed. Almost all major cache providers provide implementations for IDistributedCache, which we can register in the IoC container using IServiceCollection.

IDistributedCache Interface
This is the interface required to access the distributed cache objects, which includes synchronous and asynchronous methods. Items can be added, retrieved, and removed from the distributed cache implementation using this interface.

To perform actions on the actual cache, the IDistributedCache Interface provides the following methods.
    Get, GetAsync: Takes a string key and retrieves the cached item from the cache server if found.
    Set, SetAsync: Add items to the cache using a string key.
    Refresh, RefreshAsync: Resets the sliding expiry timeout of an item in the cache based on its key (if any).
    Remove, RemoveAsync: Deletes the cache data based on the key.

Connecting to an NCache cache
First, we need to install NCache on our machine. You can find a step-by-step tutorial on how to set up NCache on your windows machine here.

Once, the setup is complete, we are ready to use the NCache server in our .NET 6 app.  Let's create a .NET 6 project to learn the caching operations with NCache.

First, let's install the following NuGet package:

Install-Package NCache.Microsoft.Extensions.Caching.

This package uses NCache to implement the IDistributedCache interface.

We need to add the cache to the ASP.NET dependencies container in the Program.cs file after installing the NuGet package.
// Program.cs
using Alachisoft.NCache.Caching.Distributed;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddControllers();
// Add NCache implementation here...
builder.Services.AddNCacheDistributedCache(configuration => {
    configuration.CacheName = "myClusteredCache";
    configuration.EnableLogs = true;
    configuration.ExceptionsEnabled = true;
});
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();
var app = builder.Build();
if (app.Environment.IsDevelopment()) {
    app.UseSwagger();
    app.UseSwaggerUI();
}
app.UseHttpsRedirection();
app.UseAuthorization();
app.MapControllers();
app.Run();


We can also configure the cache settings in the appsettings.json file. To achieve this, we can use another overload of the same method.
builder.Services.AddNCacheDistributedCache(Configuration.GetSection("NCacheSettings"));

// appsettings.josn
{
    "NCacheSettings": {
        "CacheName": "myClusteredCache",
        "EnableLogs": true,
        "EnableDetailLogs": false,
        "ExceptionsEnabled": true,
        "OperationRetry": 0,
        "operationRetryInterval": 0
    }
}

So far, we've finished the connectivity part. We have our NCache server running on our machine with a cluster cache named myClusterCache. A cluster cache with the name demoCache is created automatically when you install NCache on your machine. Learn about how to create a cluster cache manually here.

Let's create a new extension generic method that will make our life a bit easier to get or set records from the cache server. It contains two methods: SetRecordAsync, which stores the data in the cache, and GetRecordAsync, which retrieves the data. In the DistributedCacheEntryOptions, we can pass configuration values. This determines how long the items will be stored in the cache.

public static class DistributedCacheExtensions {
    public static async Task SetRecordAsync < T > (this IDistributedCache cache, string recordId, T data, TimeSpan ? absoluteExpireTime = null, TimeSpan ? unusedExpireTime = null) {
        var options = new DistributedCacheEntryOptions {
            AbsoluteExpirationRelativeToNow = absoluteExpireTime ?? TimeSpan.FromSeconds(60),
                SlidingExpiration = unusedExpireTime
        };
        var jsonData = JsonSerializer.Serialize(data);
        await cache.SetStringAsync(recordId, jsonData, options);
    }
    public static async Task < T > GetRecordAsync < T > (this IDistributedCache cache, string recordId) {
        var jsonData = await cache.GetStringAsync(recordId);
        if (jsonData is null) {
            return default (T);
        }
        return JsonSerializer.Deserialize < T > (jsonData);
    }
}


AbsoluteExpirationRelativeToNow
This method gets or sets an absolute expiry time relative to the current date and time.

SetSlidingExpiration

This works in the same way as Absolute Expiration. If it is not requested for a specified duration of time, the cache will expire. It is important to note that Sliding Expiration should always be set lower than absolute expiration.

Now, let's inject IDistributedCache into the StudentController to access the configured cache.
using DistributedCache_NCache.Extensions;
using DistributedCache_NCache.Models;
using DistributedCache_NCache.Services;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Caching.Distributed;
namespace DistributedCache_NCache.Controllers {
    [Route("api/[controller]")]
    [ApiController]
    public class StudentController: ControllerBase {
        private readonly IStudent < Student > _studentService;
        private readonly IDistributedCache _cache;
        public StudentController(IStudent < Student > studentService, IDistributedCache cache) {
                _studentService = studentService;
                _cache = cache;
            }
            [HttpGet]
        public async Task < IActionResult > Get() {
            string cacheKey = "StudentList_" + DateTime.Now.ToString("yyyyMMdd_hhmm");
            var student = await _cache.GetRecordAsync < List < Student >> (cacheKey);
            if (student is null) {
                student = (List < Student > ) await _studentService.ListAllAsync();
                await _cache.SetRecordAsync(cacheKey, student);
            }
            return Ok(student);
        }
    }
}

In the above snippet, we set the cache key first, so that when we call the method, it checks if the data is present with that cache key in the cache server. If the data is present, then it returns the data from the cache otherwise, it fetches the data from the database, set the data to the cache, and then returns the data.

The second time when we call this method again, the data will be returned from the cache without hitting the database and the response will be much faster.

Let's test our implementation via postman now. Run the application and hit the endpoint "/api/student".

The below screenshot shows that the request took 2.78 seconds for the response.

When I hit the endpoint for the second time, the data is returned from the cache, as it was added to the cache server on the first call. This is a cache hit and the response time is much faster compared to the first call.


The cache hit can also be seen on the NCache Web Manager portal, which allows us to keep track of the cache cluster's health and traffic in real-time.

Caching is a proven technique used to hold and readily use frequently accessed data. This has excellent benefits, as we can save the expensive database trips and increase the response time significantly and save a lot of resources and money.

While in-memory caching provides a decent start, distributed caching takes things a step further and is best suited to distributed systems and cloud-native solutions.

Along with Redis, Memcached, and other popular caching solutions, NCache is one of the most popular. It includes features like real-time cluster management, Pub/Sub design pattern, and a large library for ASP.NET Core integration.



European ASP.NET Core Hosting :: What Is .NET MAUI?

clock July 5, 2022 09:05 by author Peter

.NET MAUI is one of the latest additions to Microsoft's .NET ecosystem. If you are new to .NET MAUI, this artilce is for you. Here you will learn what .NET MAUI is and why Microsoft actually developed .NET MAUI. MAUI stands for Multi-platform App UI that is a UI framework to build UI applications using C#, .NET, and XAML. .NET MAUI can be used to build apps for Windows, MacOS, Web, and Mobile (iOS, Android). That means, you can develop one project and deploy that on multiple platfforms that will work on various devices including Desktops, Mac, laptops, tablets, and smartphones.

When I think of the .NET ecosystem, one phrase comes to mind: Code Re-use. It's amazing how much we can do within one .NET codebase, and this is especially true with the introduction of .NET Core, and technologies like Xamarin (and subsequently Xamarin.Forms).

These days, people switch between many devices throughout the day in order to stay maximally productive. It's becoming increasingly important that the applications we write are accessible, regardless of the devices our users are in front of. This point makes the web very powerful, and there are many pros to writing your application for the web browser. But, when we do this, we lose out on the native platform controls and performance offered to us by the OS vendors, making the application relatively unnatural to use, and to look at.

Xamarin.Forms to the rescue!
Xamarin Native (e.g. Xamarin.Android) abstracts away the underlying platform API, allowing us to use the fantastic .NET platform to write native applications on different devices. Xamarin.Forms takes this a step further, allowing us to write one UI for multiple platforms. We write the UI once, and this UI will then be translated to the appropriate native controls for each device.
.NET 5 and 6

Microsoft's goal with .NET 5 is to begin to unify all the various scattered technologies we know and love within .NET. The goal is to bring together technologies such as .NET Core, Mono, and Xamarin into one unified ecosystem. With .NET 6, this unifying will only continue further, with the introduction of .NET MAUI.

What is MAUI?

MAUI stands for Multi-platform App UI, which is a UI framework in .NET 6 for making Windows, iOS, Android, and macOS applications with one project, one codebase. It is an evolution over Xamarin.Forms and takes code reusability to the next level. Instead of having separate projects to target indiviual platforms, we will only need a single project, and we can just choose which platform we want to deploy on (whether it be emulators or physical devices.)

This is even more powerful than it might seem at first. Resources and assets such as fonts, images, etc will only need to be included once within the one project, and .NET MAUI will take care binding these assets to each platform.



Of course, just like in Xamarin, we will have access to the underlying native platform APIs if we need to open the hood and do some platform-specfic work. In fact, in .NET MAUI, this process will be even easier and more streamlined.

.NET 6 is all about developer productivity. Part of this productivity means not being locked-in to any individual architectural patterns you might not be comfortable with. Developers in .NET MAUI can choose to use the traditionally-accepted MVVM architectural pattern for writing multi-platform UIs, or the MVU (Model-View-Update) pattern which is a code-first UI experience.

The key benefits of .NET MAUI include:

  • C# and .NET developers can build all kinds of apps using a single programming language and framework. No need to learn different programming languages, frameworks, and libraries. Same code is compiled into libraries to target Windows, macOS, iOS, and Android. This is big for tech teams. They don't need to learn different programming languages and frameworks.
  • Businesses don’t need to hire multiple teams for different platforms. Also, no need to maintain multiple technologies and teams. The cost of hiring and maintain different tech stack teams are often costly. Imagine a startup launching a website and mobile apps for iOS and Android. The startup needs to maintain three different teams with different tech stacks.

What about my Xamarin projects?
In .NET MAUI, we will be using the same XAML controls we know and love from Xamarin.Forms, and Microsoft intends to make the migration process from Xamarin.Forms to MAUI as easy as possible. They will provide migration guides as well as tooling to convert your existing projects.
Sounds great, but what will happen to Xamarin?

Xamarin Native technologies (Xamarin.iOS, Xamarin.Android) are bindings to the native platform technologies offered by the OS vendors. This concept is fundamental to Xamarin.Forms, and .NET MAUI. These technologies will continue to exist, but will be merged into .NET 6 as first-class citizens. (".NET for Android" and ".NET for iOS")

After the release of .NET 6, the Xamarin team will release final versions of the Xamarin SDKs as they exist today, and continue servicing these SDKs and Xamarin.Forms for a year. After that, support will be shifted entirely to .NET MAUI, .NET for Android, and .NET for iOS.
Conclusion

I am very excited about .NET MAUI and all the productivity it will bring. The Idea of integrating Xamarin.Forms as a first-class technology in .NET makes sense, and I look forward to watching this technology come to life.

Thanks for reading! Feedback is always welcome.

HostForLIFE.eu 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 :: Getting Started With Unit Testing With NUnit In .Net Core

clock July 4, 2022 08:24 by author Peter

What is Unit Testing?
Unit testing is a type of Software Testing in which the smallest isolated individual piece of code is tested. This testing aims to validate each unit so that the software works as expected. Unit testing is done during the development phase of the software by the software developers. Tests that rely on external systems are not unit tests. Unit tests help to identify and fix the bugs in the development phase.

There are several Unit Testing frameworks available that can be used for Unit testing like MSTest, NUnit, xUnit, etc. A test suite is the collection of tests and a unit test runner is a program that verifies tests and reports the test results.

What is Test-Driven Development (TDD)?

Test-Driven Development is a development methodology in which a Test case is written before writing the actual piece of code. This methodology is also known as the “Red-Green-Refactor” approach. In this approach, First, the test case fails (red), then get the test case to Pass (Green) and then optimize the code (Refactor).
How to set up a unit test project with NUnit?

For demonstration, I am using Visual Studio 2019 and already have a class library project using .Net Core. Below is the structure of the Project.
And the code which is written in Calculate.cs is shown in the below image.

And the code which is written in Calculate.cs is shown in the below image.


In the above code, we have a method named as addTwoNumber which will add and return the result as the response. Now let’s add a Class Library project for writing the NUnit Test cases.


 

Install NUnit, NUnit3TestAdapter, and Microsoft.NET.Test.Sdk in Calculator.Test project from the Nuget Package Manager.

 

Now add the Calculator Class Library’s project reference in the Unit Test Project.

In the Unit Test project, add a class CalculateTest. Use the [TestFixture] attribute on CalculateTest class which denotes that the class contains the unit tests. [Test] attribute indicates that method is a test method. In the checkAddTwoNumber() method, I created an object of Calculate class and Assert the expected and actual value using the AreEqual() method.

 

Open Test Explorer through the Test menu as shown in the below image.


In case the expected and actual values matched then the test case is passed and shown with a green tick symbol.

In case the test case is failed then the message and the stack trace details will help to find the issue.


HostForLIFE.eu 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