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 :: Exploring OData Protocol With ASP.NET Core

clock August 31, 2021 07:16 by author Peter

In this article, we will try to have a general introduction to OData Protocol, and later on, we will try to implement OData with ASP.NET Core Web API to supercharge it.

Let's get started,
Open Data Protocol(OData) is an open protocol that allows the creation and consumption of queryable and interoperable REST APIs in a standard way. It defines a set of best practices building and consuming RESTful services without having to worry about the various approaches to define request and response header, status code, HTTP methods, URL convention and helps us to focus only on the business logic. It helps to enhance the capabilities of the API by advocating a standard way of implementing API that allows SQL-Like querying capabilities which are generally considered to be "SQL for the Web".OData basically adds one layer over the API treating the endpoint itself as a resource and adds the transformation capabilities (Selection, Sorting, Filtering, Paging) via the URL.

Advantages of using OData

The main advantage of OData is the support for generic queries against the service data. It basically replaces the classic "Get<EntityName>By><Criteria>" web services(like GetAllEmployees, GetEmployeeByID, GetEmployeeByDepartment). For example, we have a method "GetAllEmployees()" on our server that returns the list of all employees, and from the client-side, we call "https://localhost:<port>/odata/Employee" and show the list of Employees on our client-side. But as a requirement we also need to show the details of any specific employee, in our traditional development for this we need to create another method on our server-side "GetEmployeeByID(int id)" and this method will return the details of a specific employee. But with OData we don't need to create this new method, we can simply use our "GetAllEmployees()" and just filter our existing endpoint like this "https://localhost:<port>/odata/Employee?$filter=EmployeeId eq 1" and this will return us the employee details of the first employee. So look that's really simple, we don't need to implement various actions or use query parameters to provide filtered data or you may need a new filter for your client, it is very likely that we don't have to change the server just put up the query on the client-side. Along with the filter, we can also do operations like paging data, etc.

Another notable advantage of OData is the ability to provide metadata about the service interface. A metadata document is a static resource that describes the data model and type of particular OData services. And the client can use the metadata to understand how to query and navigate between entities.

Requesting & Querying Data in OData
Now we have introductory-level knowledge about OData let's explore the requesting process of OData. For this, we will use the demo OData service "https://services.odata.org/V4/TripinService".

Get Entity Collection
OData services support requests for data via HTTP Get requests. So from the demo OData service if we want to get a collection of all People entity we can query "https://services.odata.org/V4/TripPinService/People".

$filter
$filter query option allows the client to filter collection of each depending on the expression address by URL.
For example,

https://services.odata.org/V4/TripPinService/People?$filter=FirstName eq ‘Scott’

This query returns the list of People with FirstName "Scott". So the response for this will be something like this,

$orderby
"$orderby" query option allows the client to request the resource in either ascending order using 'asc' or descending order by 'desc'.

Example: https://services.odata.org/V4/TripPinService/People('scottketchum')/Trips?$orderby=EndsAt desc

This query return Trips of individual people and order them on property 'EndsAt' in descending order.

$top
"$top" requests the number of items in the queried collection to be included in the result.
Example:

https://services.odata.org/V4/TripPinService/Peope?$top=2

This query returns the first two people of the people entity.

$skip
"$skip" query option request the number of items in the queried collection that are to be skipped.

Example: https://services.odata.org/V4/TripPinService/Airports?$skip=14

This query returns resources skipping the first 14


$count
"$count" query option allows the client to request a count of the matching resources included with the resources in the response.

Ex:
https://services.odata.org/V4/TripPinService/Airports?$count=true

This example query requests to return the total number of items in the collection.

$expand
"$expand" query options specify the related resource to be included in the resource collection.

Example:
https://services.odata.org/V4/TripPinService/People?$expand=Friends,Trips

This example query returns People with navigation property Friend and Trips of a person.


$Select
"$select" query option allows the client to request a limited set of resources for each entity.

Ex.
https://services.odata.org/V4/TripPinService/People?$select=FirstName,LastName

Here the client requesting to return only the FirstName and LastName property of each person.


Lambda Operators
OData defines two operators any and all that evaluate the Boolean expression on a collection.

Ex.

https://services.odata.org/V4/TripPinService/People?$filter=Emails/any(s:endswith(s, 'contoso.com'))


Implementing OData with ASP.NET Core
First, we will create a new ASP.NET Core API Project and install "Microsoft.AspNetCore.OData" using the package manager console.
Install-Package Microsoft.AspNetCore.OData -Version 7.5.5

Now we need to add the entity class "Student".
public class Student {
    public int StudentID {
        get;
        set;
    }
    public string FName {
        get;
        set;
    }
    public string SName {
        get;
        set;
    }
    public string IDNumber {
        get;
        set;
    }
    public string EmailAddress {
        get;
        set;
    }
    public DateTime DateCreated {
        get;
        set;
    }
}

Then we will proceed to create DbContext class called AppDbContext. As we are familiar with this context class and the whole connection things to database with .NET application so I'm skipping the description of it.

public class AppDbContext: DbContext {
    public AppDbContext(DbContextOptions < AppDbContext > options): base(options) {}
    public AppDbContext() {}
    public DbSet < Student > Student {
        get;
        set;
    }
}

Now we need to modify the startup.cs file to support OData. On the configureServices() method we are disabling endpoint routing. And inside the Configure() method we will add routeBuilder inside the UseMvc method and specify various OData options(Select, Filter, etc) and another more important thing is we are providing "GetEdmModel()" this method creates the necessary IEdmModel object for us.
public void ConfigureServices(IServiceCollection services) {
    services.AddControllers(mvcOptions => mvcOptions.EnableEndpointRouting = false);
    services.AddOData();
    //rest of the code
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env) {
    //Rest of the code
    app.UseMvc(routeBuilder => {
        routeBuilder.Select().Filter().Expand().OrderBy().Count().MaxTop(100);
        routeBuilder.MapODataServiceRoute("odata", "odata", GetEdmModel());
    });
}
private IEdmModel GetEdmModel() {
    var edmBuilder = new ODataConventionModelBuilder();
    edmBuilder.EntitySet < StudentCourse > ("StudentCourse");
    edmBuilder.EntitySet < Student > ("Student");
    return edmBuilder.GetEdmModel();
}


Now to add the OData service we will create Controller "StudentController" that will be inherited from the ODataController.
[ODataRoutePrefix("Student")]
public class StudentController: ODataController {
    private readonly AppDbContext db;
    public StudentController(AppDbContext db) {
            this.db = db;
        }
        [HttpGet]
        [EnableQuery()]
    public IQueryable < Student > Get() {
            return db.Student.AsQueryable();
        }
        [EnableQuery]
        [ODataRoute("({id})")]
    public Student Get([FromODataUri] int id) {
        return db.Student.Find(id);
    }
}

Explanation

Line 1
We have added a "[ODataRoutePrefix("Student")]" so the sample route will be "https://localhost/odata/Student"

Line 12

[EnableQuery()] attribute enables OData querying for the underlying action.

Now if we build and run the application and navigate to "https://localhost:<port>/odata/Student" we will get a list of Students.

Consume OData Feed with C# Client
Simple.OData.client is a library that supports all OData protocol versions. This is used to consume the OData feed with C# that supports different .NET versions.

Let's create a .NET Core console application named and inside the application install the Simple.OData.Client library using this command in package manager console.
Install-Package Simple.OData.Client -Version 5.18.2

Now create a new folder "Models" and create a class Student inside this folder.  Here we will create typed classes for each table data to be consumed. As we are going to consume student data so we built a Student class according to the metadata exposed by our service.
public class Student
{
    public int StudentID { get; set; }
    public string FName { get; set; }
    public string SName { get; set; }
    public string IDNumber { get; set; }
    public string EmailAddress { get; set; }
    public DateTime DateCreated { get; set; }
}


Now we will make a get request using the ODataClient and print the response in the console.
class Program {
    static async Task Main(string[] args) {
        SimpleQuery();
        Console.ReadKey();
    }
    static async void SimpleQuery() {
        var settings = new ODataClientSettings(new Uri("https://localhost:44340/odata/"));
        var client = new ODataClient(settings);
        try {
            var response = await client.For < Student > ().Filter(x => x.StudentID > 1).OrderBy(s => s.SName).Select(p => new {
                p.StudentID, p.SName, p.FName
            }).FindEntriesAsync();
            foreach(var res in response) {
                Console.WriteLine("Student ID:" + res.StudentID + ", Student Name: " + res.SName + "," + " Father's Name:" + res.FName);
            }
        } catch (Exception e) {
            Console.WriteLine("Simple Query " + e);
        }
    }
}


Finally, our project structure will look like this,


Now if we run our Client project (make sure the API service is running) we will get the response.

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 :: The New PriorityQueue Collection In .NET 6

clock August 30, 2021 07:01 by author Peter

In today’s article, we will take a look at the new PriorityQueue collection introduced with .NET 6. This is an advanced version of the existing queue collection. It allows us to add the priority of an item when the item is added to the queue. We will be using the Visual Studio 2022 preview version for this article. So, let us begin.
Creating our console application in Visual Studio 2022

Let us create a console application in Visual Studio 2022. I am using the community preview edition.

 

 

 

We now see the below,


Add the below code in the “Program.cs” file.
using System;
using System.Collections.Generic;
// Old Queue implementation
Console.WriteLine("Old Queue implementation");
var numbers = new Queue < string > ();
numbers.Enqueue("one");
numbers.Enqueue("two");
numbers.Enqueue("three");
numbers.Enqueue("four");
var total = numbers.Count;
for (var i = 0; i < total; i++) {
    var number = numbers.Dequeue();
    Console.WriteLine(number);
}
// New C#10 PriorityQueue
Console.WriteLine("New C#10 PriorityQueue implementation");
var newNumbers = new PriorityQueue < string,
    int > ();
newNumbers.Enqueue("one", 3);
newNumbers.Enqueue("two", 4);
newNumbers.Enqueue("three", 2);
newNumbers.Enqueue("four", 1);
var newTotal = newNumbers.Count;
for (var i = 0; i < newTotal; i++) {
    var number = newNumbers.Dequeue();
    Console.WriteLine(number);
}
Console.ReadKey();


Looking at the above code we see that we first create a simple queue collection and enqueue four strings to it. When we dequeue the elements of the queue collection, we get them back in the same order in which they were added. This is the default working of the queue.

However, in the second part of the code, we are using the new PriorityQueue collection in which we can specify the order in which we would want to dequeue the elements. Hence, we are giving the members of the queue a priority.

When we run the code, we will see the below,


In this article, we took a look at the new PriorityQueue collection introduced with .NET 6. This can be very useful for creating a collection in which certain members need to be dequeued and processed before others irrespective of when they were added to the queue. Happy coding!

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 :: Authorization Attribute In ASP.NET Core Web API

clock August 25, 2021 07:07 by author Peter

uthorization is a basic requirement while the application is used by multiple & multilevel users. While developing APIs, it's also important to provide basic authorization to handle security. Here we will see how to implement the authorization attribute in ASP. Net Core web API. This post will cover the basics of developing authorization attributes for both intermediate and experienced users.

Step 1 - Create Authorization Attribute Class
Create a class for handling the logic of the authorization process. Here I have assigned the class name "AuthAttribute". Assign TypeFilterAttribute to AuthAttribute class and create a constructor of the class. The constructor can contain parameters as per requirements. Here I have assigned two parameters to the constructor name as actionName and roleType.

public class AuthAttribute: TypeFilterAttribute {
    public AuthAttribute(string actionName, string roleType): base(typeof(AuthorizeAction)) {
        Arguments = new object[] {
            actionName,
            roleType
        };
    }
}


Step 2 - Create a class to handle the logic for an Authorization
Now, create a class for handling the logic for the authorization process.
public class AuthorizeAction: IAuthorizationFilter {
    private readonly string _actionName;
    private readonly string _roleType;
    public AuthorizeAction(string actionName, string roleType) {
        _actionName = actionName;
        _roleType = roleType;
    }
    public void OnAuthorization(AuthorizationFilterContext context) {
        string _roleType = context.HttpContext.Request?.Headers["role"].ToString();
        switch (_actionName) {
            case "Index":
                if (!_roleType.Contains("admin")) context.Result = new JsonResult("Permission denined!");
                break;
        }
    }
}


The authorization can get a role name in different ways. Here role name is passing in the header, so httpcontext will return us the role name from the header details. However, the action name will fetch from the action's attribute parameter which will be bind in the controller.

Step 3 - Assign Authorization Attribute to Action

Now, assign authorization attribute to action as per requirements. The attribute contains a parameter like rolename and actionname. So during the declaration of the authorization attribute with the action, it will require rolename and actionname as parameters.

[HttpGet]
[AuthAttribute("Index", "Admin")]
[Route("sample")]
Public async Task<IActionResult> Index()
{
    return Ok("Action perform successfully!");
}


Here, I have created a simple action under the controller and assigned an authorization attribute to the action. Now, I have assigned the action name as "Index" and role type as "Admin". We can manage action names and role names based on application requirements.

Step 4 - API call from the postman
Call API using postman with role name in the header.

Step 5 - Logic behind the process
When API call, first of all, it will redirect to the authorization process. The authorization will get the action name and role type in a parameter from the action. Roles which are passing in the parameter are eligible to access the action. And authorization process will check requesting role with eligible parameter roles, and if the condition will fulfill then the process will allow the user to access the action; otherwise, it will not allow the user to access or enter in action logic.

It's difficult to manage Authorization inside action's services while creating an Asp.Net Core web API. It's possible that an unauthorized person might gain access to the logic of the process if the logical criteria don't meet. As a result, if a user is prohibited from a specific process, that user will be unable to enter the action's logic. On the other side, if actions have any loopholes for managing logic, this technique can also make logic safe against unauthorized user access.

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 :: Purpose and Use of Delegate

clock August 24, 2021 06:39 by author Peter

Why use delegate in C#?
Delegate is one of the most incorrectly-interpreted words by developers in C#. Delegate is widely used inside .net framework itself. Let’s go further and break down  that delegate question that every interviewer asks.
 
My Experience with Delegates
In my all years of experience I have used delegate several times and noticed that after I am done with development who ever over takes that code from me is not able to grasp that particular delegate logic.
 
If used wisely it can save a lot of time and lines of code but if used in inappropriately it will confuse everyone in the future.
 
Purpose
It helps achieve the following,
    Encapsulation / Abstraction
    Security
    Callback
    Re-usability

Most common definition of Delegate,
“Delegate is a keyword in .net that is used as function pointer” or
“Delegate is used for callbacks only”
 

Well nothing is wrong with these definitions but they don't tell you the whole picture.
 
Characteristics
Delegate has a few characteristics:
    Type safe
    Takes method in assignment

Let’s start by an example,
 
First let’s create our Product model
 
We are going to use this model
using System;
namespace Models
{
    public class Products
    {
        public string ProductName { get; set; }
        public int ProductId { get; set; }

    }
}


Let’s create and interface
General practice to create interface
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace BusinessLayer
{
    public interface ICustomer<T>
    {
        void Process(T products);
    }
}

Second, inherit this interface in class
using Models;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace BusinessLayer
{
    public class FrequentCustomer : ICustomer<Products>
    {
        public void Process(Products product)
        {
            Console.WriteLine($"Product Count : 1");
            Console.WriteLine("--Product Details--");
            Console.WriteLine($"Name : {product.ProductName} Product Id : {product.ProductId}");
        }
    }
}   

Process is the method which will be called by an anonymous later
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace ServiceCallManager
{
    public static class ServiceCaller
    {
        public static void Invoke<TService>(Action<TService> action)
        {
            Type typ = typeof(TService);
            TService instance = (TService)Activator.CreateInstance(typ);

            action(instance);
        }
    }
}


Invoke is the method which takes Action<TService> type argument, in .Net Action delegate's return type is void.

See the summary, it says “encapsulates.”
 
Now we all know delegate takes method in assignment (Encapsulates method)
 
Method can be in any form, let’s say anonymous methods.
 
What is the anonymous method?
“A method without a name!”
 
Now let’s look into our next class.
class Program
{
    static void Main(string[] args)
    {
        IList<Products> products = new List<Products>();

        Products product1 = new Products();
        product1.ProductName = "Rice";
        product1.ProductId = 1;
        products.Add(product1);

        product1 = new Products();
        product1.ProductName = "Bread";
        product1.ProductId = 2;
        products.Add(product1);

        product1 = new Products();
        product1.ProductName = "Pasta";
        product1.ProductId = 3;
        products.Add(product1);

        ServiceCaller.Invoke<FrequentCustomer>(x => x.Process(product1));

        Console.WriteLine();
        Console.ReadKey();
    }
}
ServiceCaller.Invoke<FrequentCustomer>(x => x.Process(product1));


Remember that the invoke method accepts delegate as argument and delegate encapsulates methods, so here inside Invoke method I am passing an anonymous method which will get invoked when action() is called which executes the anonymous method and calls the Process method of FrequentCustomer class.

Let’s go step by step,
    Breakpoint comes to ServiceCaller.Invoke<FrequentCustomer>(x => x.Process(product1));
    It goes inside Invoke method of staticServiceCaller class
    Via reflection we are creating object of ServiceT type (You can ignore this if you don’t understand reflection)
    At the last line of method action is called with parameter instance; i.e. object of ServiceT type
    After action (instance) is called breakpoint comes to ServiceCaller.Invoke<FrequentCustomer>(x => x.Process(product1)); and it starts executing the x => x.Process(product1) part only
    You will notice that x is of type FrequentCustomer


    So this part of execution calls the Process method or FrequentCustomer and is also passing local parameter in it.

Now the benefit of delegate here is I am able to use local variable inside method; i.e. product1, which may not be available in other class due to security reasons.

Delegate helps me implement Encapsulation, Security, Callback (Obviously), Re-usability and if used wisely, Polymorphism also.

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 :: How to Implement Read/Write Operations Using CQRS And Dapper In ASP.NET Core?

clock August 23, 2021 07:47 by author Peter

In this article, we will look into the implementation of reading Queries and Write Commands using CQRS and Dapper ORM in the ASP.Net Core 5.0 template. CQRS is a popular architecture pattern because it addresses a common problem with most enterprise applications. Separating write behavior from reading behavior, which is the essence of the CQRS architectural pattern, provides stability and scalability to enterprise applications while also improving overall performance.

In scenarios, when you have complex business logic CQRS may simplify understanding of the domain by dividing the problem into the command and query parts. In situations, when your UI is based on workflows and utilizes the Interface pattern it is easier to identify user's intents and translate them into domain events.

Setup the Project

    Open Visual Studio and select "Create a new project" and click the "Next" button.
    Add the "project name" and "solution name", also choose the path to save the project in that location, click on "Next".
    Now choose the target framework ".Net 5.0" which we get once we install the SDK and also will get one more option to configure Open API support by default with that check box option.

Tables Schema
Create a Database in the SQL Server to execute the below schema under that database to create respective tables. If the database already exists then we can directly execute the schema without creating the database. Here we have created two tables Order & Product to work with CRUD Operations.
USE [OrderDb]
GO
/****** Object:  Table [dbo].[Orders]    Script Date: 17-08-2021 10:54:38 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TABLE [dbo].[Orders](
    [OrderId] [int] IDENTITY(1,1) NOT NULL,
    [OrderDetails] [nvarchar](max) NULL,
    [IsActive] [bit] NOT NULL,
    [OrderedDate] [datetime2](7) NOT NULL,
 CONSTRAINT [PK_Orders] PRIMARY KEY CLUSTERED
(
    [OrderId] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, OPTIMIZE_FOR_SEQUENTIAL_KEY = OFF) ON [PRIMARY]
) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]
GO
/****** Object:  Table [dbo].[Products]    Script Date: 17-08-2021 10:54:38 ******/
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TABLE [dbo].[Products](
    [ProductId] [int] IDENTITY(1,1) NOT NULL,
    [Name] [nvarchar](max) NULL,
    [Price] [real] NOT NULL,
    [isDisCountApplied] [bit] NOT NULL,
 CONSTRAINT [PK_Products] PRIMARY KEY CLUSTERED
(
    [ProductId] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, OPTIMIZE_FOR_SEQUENTIAL_KEY = OFF) ON [PRIMARY]
) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]
GO

Adding the Domain Models
Let's create the table models inside the project. To separate the things from each other we will be following the Onion Architecture pattern in which we will maintain all our Models under the Domain Layer. Create a Class library named Domain Layer and add the below class files inside that.

Order.cs
using System;

namespace DomainLayer
{
   public class Order
    {
       public int OrderId { get; set;}
       public string OrderDetails { get; set; }
       public bool IsActive { get; set; }
       public DateTime OrderedDate { get; set; }
    }
}

Product.cs
namespace DomainLayer
{
    public class Product
    {
       public int ProductId { get; set; }
       public string Name { get; set; }
       public float Price { get; set; }
       public bool isDisCountApplied  { get; set; }
    }
}


Domain Layer

Commands & Queries
Commands are nothing but task-based operations where they will perform the write operations to the database. Here will need one more project (Class Library) to maintain all these Read/Write Operations so that will have layered architecture with fewer dependencies. Create a class library named ApplicationLayer to have the commands and queries based on requirements.

Create a folder named Commands and Query and inside that will add the classes based on the tables and operations. Below is the image of the Application Layer

Adding the Required Packages in Application Layer
As referenced before, the Application Layer will contain the CQRS Commands and Queries that are explicit for this application.

Right off the bat, Add Reference to the Domain Project.

Then, at that point, introduce the necessary bundles through Console.

Install-Package MediatR.Extensions.Microsoft.DependencyInjection

Adding the Dependency Injection
This is another variation that I have seen in numerous tremendous arrangements. Suppose you have around 100 interfaces and 100 executions. Do you add this load of 100 lines of code to the Startup.cs to enroll them in the holder? That would be crazy according to the viability perspective. To keep things clean, what we can do is, Create a DependencyInjection static Class for each layer of the arrangement and just add the comparing expected administrations to the comparing Class.

Along these lines, we are decentralizing the code lines and keeping our Startup class slick and clean. Here is an augmentation technique over the IServiceCollection.
using MediatR;
using Microsoft.Extensions.DependencyInjection;
using System.Reflection;

namespace ApplicationLayer
{
public static class DependencyInjection
{
    #region Services Injection
    public static void AddApplication(this IServiceCollection services)
    {
        services.AddMediatR(Assembly.GetExecutingAssembly());
    }
    #endregion

}
}


Basically, these classes would cover our CRUD Operations implementation by using the SQL Queries - Dapper

CreateOrUpdateOrderCommand.cs
using Dapper;
using MediatR;
using Microsoft.Extensions.Configuration;
using System.ComponentModel.DataAnnotations;
using System.Data.SqlClient;
using System.Threading;
using System.Threading.Tasks;

namespace ApplicationLayer.Commands.Orders
{
public class CreateOrUpdateOrderCommand : IRequest<int>
{
    public int OrderId { get; set; }
    [Required]
    public string OrderDetails { get; set; }
    public class CreateOrUpdateOrderCommandHandler : IRequestHandler<CreateOrUpdateOrderCommand, int>
    {
        private readonly IConfiguration configuration;
        public CreateOrUpdateOrderCommandHandler(IConfiguration configuration)
        {
            this.configuration = configuration;
        }
        public async Task<int> Handle(CreateOrUpdateOrderCommand command, CancellationToken cancellationToken)
        {
            if (command.OrderId > 0)
            {
                var sql = "Update Orders set OrderDetails = @OrderDetails Where OrderId = @OrderId";
                using (var connection = new SqlConnection(configuration.GetConnectionString("DefaultConnection")))
                {
                    connection.Open();
                    var result = await connection.ExecuteAsync(sql, command);
                    return result;
                }
            }
            else
            {
                var sql = "Insert into Orders (OrderDetails) VALUES (@OrderDetails)";
                using (var connection = new SqlConnection(configuration.GetConnectionString("DefaultConnection")))
                {
                    connection.Open();
                    var result = await connection.ExecuteAsync(sql, new { ClientName = command.OrderDetails });
                    return result;
                }
            }
        }
    }
}
}


DeleteProductByIdCommand.cs
using Dapper;
using MediatR;
using Microsoft.Extensions.Configuration;
using System.ComponentModel.DataAnnotations;
using System.Data.SqlClient;
using System.Threading;
using System.Threading.Tasks;

namespace ApplicationLayer.Commands.Products
{
public class DeleteProductByIdCommand : IRequest<int>
{
    [Required]
    public int ProductId { get; set; }
    public class DeleteProductByIdCommandHandler : IRequestHandler<DeleteProductByIdCommand, int>
    {
        private readonly IConfiguration _configuration;
        public DeleteProductByIdCommandHandler(IConfiguration configuration)
        {
            _configuration = configuration;
        }
        public async Task<int> Handle(DeleteProductByIdCommand command, CancellationToken cancellationToken)
        {
            var sql = "DELETE FROM Products WHERE ProductId = @ProductId";
            using (var connection = new SqlConnection(_configuration.GetConnectionString("DefaultConnection")))
            {
                connection.Open();
                var result = await connection.ExecuteAsync(sql, new { ClientID = command.ProductId });
                return result;
            }
        }
    }
}
}


GetAllORdersQuery.cs
using Dapper;
using DomainLayer;
using MediatR;
using Microsoft.Extensions.Configuration;
using System.Collections.Generic;
using System.Data.SqlClient;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;

namespace ApplicationLayer.Queries.Orders
{
public class GetAllOrdersQuery : IRequest<IList<Order>>
{
    public class GetAllOrderQueryHandler : IRequestHandler<GetAllOrdersQuery, IList<Order>>
    {
        private readonly IConfiguration _configuration;
        public GetAllOrderQueryHandler(IConfiguration configuration)
        {
            _configuration = configuration;
        }
        public async Task<IList<Order>> Handle(GetAllOrdersQuery query, CancellationToken cancellationToken)
        {
            var sql = "Select * from Orders";
            using (var connection = new SqlConnection(_configuration.GetConnectionString("DefaultConnection")))
            {
                connection.Open();
                var result = await connection.QueryAsync<Order>(sql);
                return result.ToList();
            }
        }
    }
}
}


GetAllProductsQuery.cs
using Dapper;
using DomainLayer;
using MediatR;
using Microsoft.Extensions.Configuration;
using System.Collections.Generic;
using System.Data.SqlClient;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;

namespace ApplicationLayer.Queries.Products
{
public class GetAllProductsQuery : IRequest<IList<Product>>
{
    public class GetAllOrderQueryHandler : IRequestHandler<GetAllProductsQuery, IList<Product>>
    {
        private readonly IConfiguration _configuration;
        public GetAllOrderQueryHandler(IConfiguration configuration)
        {
            _configuration = configuration;
        }
        public async Task<IList<Product>> Handle(GetAllProductsQuery query, CancellationToken cancellationToken)
        {
            var sql = "Select * from Products";
            using (var connection = new SqlConnection(_configuration.GetConnectionString("DefaultConnection")))
            {
                connection.Open();
                var result = await connection.QueryAsync<Product>(sql);
                return result.ToList();
            }
        }
    }
}
}


Firstly, add a connection string to the appsettings.json found in the WebApi Project.

appsettings.json
"ConnectionStrings": {
"DefaultConnection": "Server=**********;Database=OrderDb;Trusted_Connection=True;"
}

Furthermore, in the Startup class/ConfigureServices strategy for the WebApi Just Add the accompanying line. You would now be able to see the benefit of this sort of approach.
#region Dependency Injection
services.AddApplication();
#endregion

Adding the MediatR Handler and Controllers

This is the last step of setting up Onion Architecture In ASP.NET Core. We should wire up a regulator to the Application Layer.

Make a Base API Controller. This will be an Empty API Controller which will have a MediatR object. What is the point of this Base Controller? It is simply to diminish the lines of code. Say, we add another regulator. We won't need to re-characterize the MediatR object. Be that as it may, we will simply add the BaseAPI Controller as the base class. Get it? I will show it in execution.

Add another Empty API Controller in the Controllers envelope and name it BaseController.

BaseController.cs
using MediatR;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.DependencyInjection;

namespace OnionArchitecture_CQRS_Dapper.Controllers
{
[Route("api/[controller]")]
[ApiController]
public abstract class BaseController : ControllerBase
{
    #region Property
    private IMediator _mediator;
    #endregion
    protected IMediator Mediator => _mediator ??= HttpContext.RequestServices.GetService<IMediator>();
}
}


OrderController.cs
using ApplicationLayer.Commands.Orders;
using ApplicationLayer.Queries.Orders;
using Microsoft.AspNetCore.Mvc;
using System.Threading.Tasks;

namespace OnionArchitecture_CQRS_Dapper.Controllers
{
public class OrderController : BaseController
{
    /// <summary>
    /// Save newly added order to database
    /// </summary>
    /// <param name="command"></param>
    /// <returns></returns>
    [HttpPost(nameof(SaveOrderData))]
    public async Task<IActionResult> SaveOrderData(CreateOrUpdateOrderCommand command) => Ok(await Mediator.Send(command));
    /// <summary>
    /// Fetch all data from the Orders table.
    /// </summary>
    /// <returns></returns>
    [HttpGet]
    public async Task<IActionResult> GetAllOrders() => Ok(await Mediator.Send(new GetAllOrdersQuery()));
}
}

ProductController.cs
using ApplicationLayer.Commands.Products;
using ApplicationLayer.Queries.Products;
using Microsoft.AspNetCore.Mvc;
using System.Threading.Tasks;

namespace OnionArchitecture_CQRS_Dapper.Controllers
{
public class ProductController : BaseController
{
    /// <summary>
    /// Delete Product from the Products Table
    /// </summary>
    /// <param name="command"></param>
    /// <returns></returns>
    [HttpDelete(nameof(DeleteProduct))]
    public async Task<IActionResult> DeleteProduct(DeleteProductByIdCommand command) => Ok(await Mediator.Send(command));
    /// <summary>
    /// Fetch all Product Data from the Database
    /// </summary>
    /// <returns></returns>
    [HttpGet]
    public async Task<IActionResult> GetAllProducts() => Ok(await Mediator.Send(new GetAllProductsQuery()));
}
}


Testing

Run the application and open up Swagger. We will do a simple test to ensure that our solution works.


 

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 :: Data Source Controls In ASP.NET

clock August 18, 2021 09:06 by author Peter

SqlDataSource control is a data source control provided in ASP.NET to connect to database providers such as SQL, OLEDB, ODBC, and Oracle. This control only establishes a connection with the data source; it does not display data on the web page. The data is displayed by binding the SqlDataSource control to a data-bound control such as a GridView or DataList. These data-bound controls, in turn, display the data on the web page. The SqlDataSource control also supports editing, updating, deleting, and sorting of the records retrieved from the database. This support to manipulate the data in the data source can be implemented in data-bound controls without writing any code. In other words, a SqlDataSource control allows you to access databases without creating a Connection, Command, or a Data Reader object.
Adding SqlDataSource Control

A SqlDataSource control is added to the webform using markup or by dragging it from the Toolbox and dropping it on the web form. The code below shows the markup to create a SqlDataSource control.
<asp:SqlDataSource ID=”sqldsSuppliers” runat=”server”>
</asp:SqlDataSource>


The markup in this code creates a SqlDataSource control named sqldsSuppliers. This control will be used to connect to the NWSuppliers table in the Northwind database.
Configuring SqlDataSource Control

The basic configuration of the SqlDataSource control involves setting two attributes, namely ConnectionString and SelectCommand. The ConnectionString attribute specifies the connection string to connect to a particular database. The SelectCommand attribute specifies the select statement to retrieve the records from a database table. Source code uses these attributes to connect to the Northwind database located on the SQL Server instance, SQLEXPRESS, installed on the system 10.2.1.51.

<asp:SqlDataSource ID=”sqldsSuppliers” runat=”server” ConnectionString=”Data Source=10.2.1.51\SQLEXPRESS;Initial Catalog=Northwind; Integrated Security=True” SelectCommand=”select * from NWSupplierss;”>
</asp:SqlDataSource>


The SqlDataSource control, sqldsSuppliers, will retrieve all the records from the NWSuppliers table.

The attribute ConnectionString and SelectCommand are available only in the Source view of the web form in design view, the selectCommand attribute is available as a SelectQuery property.

Binding to a Data Bound Control
After the SqlDataSource control is configured to retrieve data from the database, it is bound to a data-bound control. The code below shows the code to bind an SQqlDataSource control named sqldsSuppliers to a DataList control named dlstSuppliers using the DataSourceID property.

<asp:DataList ID=”dlstSuppliers” runat=”server” backcolor=”LightGoldenrodYellow” BorderColor=”Tan” BorderWidth=”1px” CellPadding=”2” DataSourceID=”sqldsSuppliers” Font-Name=”verdana” Font-Size=”Smaller” ForeColor=”Black”>
</asp:Datalist>

The same SqlDataSource control can be bound to another data-bound control such as the GridView control by setting the DataSourceID property to sqldsSuppliers. Code shows the ItemTemplate code to display the data in a DataList control named dlstSuppliers.
<ItemTemplate>
  <strong>Supplier ID </strong>
  <asp:Label ID=”lblSupplierID” runat=”server” Text=’<%#Eval(“SupplierID”)%>’ width=”45px” Font-size=”x-small”>
  </asp:Label> &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; <strong> Company Name:</strong>
  <asp:Label ID=”lblCompanyName” runat=”server” Test=’<%#Eval(“Companyname”)%>’ width=”197px” Font-size=”x-small”>
  </asp:Label>
  <br />
  <br />
  <strong> Contact Name:</strong>
  <asp:Label ID=”lblContactName” runat=”server” Test=’<%#Eval(“ContactName”)%>’ width=”127px” Font-size=”x-small” Font-Bold=”False”>
  </asp:Label>
  <br />
  <br />
  <strong> Phone:</strong>
  <asp:Label ID=”lblPhone” runat=”server” Test=’<%#Eval(“Phone”)%>’ width=”111px” Font-size=”xx-small” Font-Bold=”False”>
  </asp:Label>
  <br />
  <br />
</ItemTemplate>
<AlternatingItemStyle BackColor=”PaleGoldenrod” />

The ItemTemplate in the source code comprises four times. It displays four textual labels namely Supplier ID, Company name, Contacts Name, and Phone. The ItemTemplate also has four corresponding Label controls namely lblSupplierID, lblCompanyName, lblContactName, and lblPhone respectively. These Label controls are bound to the columns SupplierID, CompanyName, ContactName, and Phone respectively of the NWSuppliers table.
Commands in SqlDataSource Control

The SqlDataSource control uses the SelectCommand property to retrieve the records from a database table. Similarly, SqlDataSource control is provided with DeleteCommand, UpdateCommand, and InsertCommand properties to delete, update and add a new record into a database table.

DeleteCommand Property
The DeleteCommand property is used to specify the DELETE statement to delete a record. DeleteCommand is available as an attribute of the SQLDataSource tag in source view. In the Design view, the DELETE statement is specified as a value of the property, DeleteQuery. Source code shows in bold how to set the DeleteCommand attribute of the SqlDataSource tag.
<asp:SqlDataSource ID=”sqldssuppliers” runat=”server” ConnectionString=”Data Source=10.2.1.51\SQLEXPRESS;Initial Catalog=Northwind;Integrated Security=”True” SelectCommand=”Select * from NWSuppliers ;”DeleteCommand=”delete from NWSuppliers where [email protected]” >
    <DeleteParameters>
        <asp:Parameter Type=”Int32” Name=”SupplierID” />
    </DeleteParameters>
</asp:SqlDataSource>


The DeleteCommand in code contains a placeholder, @SupplierID, for SupplierID value. The details about this placeholder are specified by the <DeleteParameters> element. This data source control can now be used with a data-bound control such as a DataList control.

If the SqlDataControl is used with a GridView control, you can provide delete functionality by setting two properties. The DataSource property is set to sqldsSuppliers and the DataKeyNames property is set to SupplierID.

The steps to be followed in order to implement delete functionality in the DataList control, dlstSuppliers are listed below:

In the Properties window of the dlstSuppliers control, set the DatakeyField property to the primary key column of the database table, NWSuppliers. In this case, you set it to SupplierID. The DataKeyField attribute specifies the name of the primary key column, which is used to delete or update a record in the database table.

In the ItemTemplate of dlstSuppliers control, add a LinkButton Web Server control with the CommandName property set to delete and Text property set to Delete. This will render the DataList control with a Delete link to delete an item.

Add a DeleteCommand event handler to dlstSuppliers control a shown in code below,

protected void dlstSuppliers DeleteCommand(object source, DataListCommandEventArgs e) {
    int id = (int) dlstSuppliers.DataKeys[e.Item.ItemIndex];
    sqldsSuppliers.DeleteParameters[“SupplierID”].DefaultValue = id.ToString();
    sqldsSuppliers.Delete();
}


The DataKeys collection of dlstSuppliers contains all the keys values of the items listed in the control. Therefore, the SupplierID value of the item clicked is retrieved by indexing the Datakeys collection with the index of the item clicked. The ItemIndex property returns the index of the item clicked. The SupplierID value retrieved is then assigned to the delete parameter of the SqlDataSource control named sqldsSuppliers. Finally, the delete() method is invoked.

The SqlDataSource control is used to connect to databases such as Access, SQLServer, and Oracle. The SqlDataSource and XMLDataSource controls are associated with a data-bound control using the DataSourceID attribute. The SelectCommand attribute of the SqlDataSource tag is used to specify a SELECT statement while the DeleteCommand attribute is used to specify a DELETE statement. Parameters to DELETE statement in a DeleteCommand are described using the <DeleteParameters> element.

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 :: How to Calling Web API Using HttpClient?

clock August 16, 2021 07:28 by author Peter


HttpClient class provides a base class for sending/receiving the HTTP requests/responses from a URL. It is a supported async feature of .NET framework. HttpClient is able to process multiple concurrent requests. It is a layer over HttpWebRequest and HttpWebResponse. All methods with HttpClient are asynchronous.

In this example, I have created a console application.

To call Web API methods from the console Application, the first step is to install the required packages, using NuGet Package Manager. The following package needs to be installed in the console Application.

Install-Package Microsoft.AspNet.WebApi.Client

Next step is to create HttpClient object. In the following code snippet, the main function calls private static method "CallWebAPIAsync" and this blocks until CallWebAPIAsync completes the process, using wait function.
static void Main(string[] args)
{
    CallWebAPIAsync()
        .Wait();
}
static asyncTaskCallWebAPIAsync()
{
    using(var client = newHttpClient())
    {
        //Send HTTP requests from here.
    }
}


Afterwards, we have set the base URL for the HTTP request and set the Accept header. In this example, I have set Accept header to "application/json" which tells the Server to send the data into JSON format.
using(var client = newHttpClient())
{
    client.BaseAddress = newUri("http://localhost:55587/");
    client.DefaultRequestHeaders.Accept.Clear();
    client.DefaultRequestHeaders.Accept.Add(newMediaTypeWithQualityHeaderValue("application/json"));
}

HTTP GET Request
Following code is used to send a GET request for department, as shown below:
using(var client = newHttpClient())
{
    client.BaseAddress = newUri("http://localhost:55587/");
    client.DefaultRequestHeaders.Accept.Clear();
    client.DefaultRequestHeaders.Accept.Add(newMediaTypeWithQualityHeaderValue("application/json"));
    //GET Method
    HttpResponseMessage response = awaitclient.GetAsync("api/Department/1");
    if (response.IsSuccessStatusCode)
    {
        Departmentdepartment = awaitresponse.Content.ReadAsAsync < Department > ();
        Console.WriteLine("Id:{0}\tName:{1}", department.DepartmentId, department.DepartmentName);
        Console.WriteLine("No of Employee in Department: {0}", department.Employees.Count);
    }
    else
    {
        Console.WriteLine("Internal server Error");
    }
}


In the code given above, I have used GetAsync method to send HTTP GET request asynchronously. When the execution of this method is finished, it returns HttpResponseMessage,  which contains HTTP response. If the response contains success code as response, it means the response body contains the data in the form of JSON. ReadAsAsync method is used to deserialize the JSON object.

HttpClient does not throw any error when HTTP response contains an error code, but it sets the IsSuccessStatusCode property to false. If we want to treat HTTP error codes as exceptions, we can use HttpResponseMessage.EnsureSuccessStatusCode method.

When we run the code, given above, it throws the exception "Internal Server error".

We have to configure the serializer to detect then handle self-referencing loops. The following code needs to be placed in Global.asax.cs in Web API:

GlobalConfiguration.Configuration.Formatters.JsonFormatter.SerializerSettings
.PreserveReferencesHandling =Newtonsoft.Json.PreserveReferencesHandling.All;

HTTP POST request
Following code is used to send a POST request for the department:
var department = newDepartment() { DepartmentName = "Test Department" };
HttpResponseMessage response = awaitclient.PostAsJsonAsync("api/Department", department);

if (response.IsSuccessStatusCode)
{
   // Get the URI of the created resource.
   UrireturnUrl = response.Headers.Location;
   Console.WriteLine(returnUrl);
}


In this code, PostAsJsonAsync method serializes the object into JSON format and sends this JSON object in POST request. HttpClient has a built-in method "PostAsXmlAsync" to send XML in POST request. Also, we can use "PostAsync" for any other formatter.

HTTP PUT Request
Following code is used to send a PUT request for the department:

//PUT Method
var department = newDepartment() { DepartmentId = 9, DepartmentName = "Updated Department" };
HttpResponseMessage response = awaitclient.PutAsJsonAsync("api/Department", department);
if (response.IsSuccessStatusCode)
{
   Console.WriteLine("Success");
}

Same as POST, HttpClient also supports all three methods: PutAsJsonAsync, PutAsXmlAsync and PutAsync.

HTTP DELETE Request
Following code is used to send a DELETE request for the department:
intdepartmentId = 9;
HttpResponseMessage response = awaitclient.DeleteAsync("api/Department/" + departmentId);
if (response.IsSuccessStatusCode)
{
   Console.WriteLine("Success");
}


HttpClient only supports DeleteAsync method because Delete method does not have a request body.

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 :: Code First Connection By Migration .NET Core

clock August 9, 2021 07:52 by author Peter

Add package by right clicking on the project. Click on manage nuget packages, browse package, search microsoft.entityframeworkcore.sqlserver , install it, search microsoft.entityframeworkcore.tool,microsoft.visualstudio.web.codegenerator.design , click ok and click accept on pop up.
 
This package will be added in packages. Add DataBaseContext.cs class in model inherit DbContext in the method class of DataBaseContext and use namespace. Microsoft.EntityFrameworkCore forDbContext Definition makes a constructor for connectivity with the database.
    public DataBaseContext(DbContextOptions<DataBaseContext> options) : base(options)  
    {  
    }  


In database context class add a class in the model for the table you want to make in the database. You can use a prop and double tab. For auto creating a property in class assign primary key here only on the property of class as an attribute with keyword [Key]. Use namespace System.ComponentModel.DataAnnotations for key attribute definition now link this table as DbSet type of property in DataBaseContext class LIKE this,
    public DbSet<Student> students { get; set; }   

Now use connection string in appsetting.json below "AllowedHosts": "*",
    "ConnectionStrings": {  
       "DatabaseConnection": "Data Source=DESKTOP-DCDA4OG\\SQLEXPRESS; Initial Catalog=CodeFirst; Integrated Security=True;"  
    }   

Now create a new database in SQL server rest of table will automatically be created by the project itself

add,
    string connection = Configuration.GetConnectionString("DataBaseConnection");  
    services.AddDbContext<DataBaseContext>(options => options.UseSqlServer(connection));  

in Configuresrevices in startup.cs use namespace microsoft.entityframeworkcore for usesqlserver connectivity keyword now add controller lets say with name usercontroller add model class add datacontext class click add you can auto create add update delete list by scaffolding now do migration,

select tools - > nugetpackage manager -> package manager console

write Add-Migration InitialCreate and enter

Write update-database enter

Now run controllers.

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 :: How to Building Secure REST API?

clock August 5, 2021 07:14 by author Peter

In this article, we build a secure REST API in ASP.NET Core using JWT Authentication. We begin with what essentially a JWT is and its structure.

Sections 1 - 4 of the article explain what a JWT token is, how to set it with .Net Core, Installing Required Packages, creating Application models, Migrations & Updating the Database

Sections 5 - 9  focus on generating Secure JWT tokens, making secure calls with and without the generated token, and registering users. Have used Postman for testing and firing Web requests to secure API.

1. JWT Structure
See the below JWT token. It is broken down and explained below as Header, Payload, Signature,
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiI1Njc3OCIsIm5hbWUiOiJSYWp1IEt1bWFyIiwiaWF0IjozNDU2Njd9.eJBP0IBy20JT9iwP6pHiKkFfHcbMPg_gVYKH-e5j0qk

Header
Provides details on the type of Token (JWT) and the algorithm used to sign the token, such as RSA, SHA256.  In the above example, it is,
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9

Payload
Contains user details also known as claims, this is the data to be secured. In the above example, it is,
eyJzdWIiOiI1Njc3OCIsIm5hbWUiOiJSYWp1IEt1bWFyIiwiaWF0IjozNDU2Njd9

Signature
Encryption between the header, payload, and a secret key. In the above example, it is,
eJBP0IBy20JT9iwP6pHiKkFfHcbMPg_gVYKH-e5j0qk

See this site JSON Web Tokens - jwt.io to decode this JWT token.

2. Let's start by Installing Required Packages

Create a new ASP.NET Core application using the API template and install the following packages. The target framework is 3.1 and above.
Install-Package Microsoft.AspNetCore.Authentication.JwtBearer
Install-Package Microsoft.AspNetCore.Identity.EntityFrameworkCore
Install-Package Microsoft.EntityFrameworkCore
Install-Package Microsoft.EntityFrameworkCore.Design
Install-Package Microsoft.EntityFrameworkCore.SqlServer
Install-Package Microsoft.EntityFrameworkCore.Tools
Install-Package Microsoft.VisualStudio.Web.CodeGeneration.Design
Install-Package System.IdentityModel.Tokens.Jwt


3(a). Configure JWT in code as shown
Add the following to appsettings.json,
"JWT": {
    "key": "C1CF4B7DC4C4175B6618DE4F55CA4",
    "Issuer": "MySecureRestApi",
    "Audience": "AsecureRestApiUser",
    "DurationInMinutes": 20
}


Create a corresponding class for the above settings, namely, Settings/JWT.cs which will be used to read data from our previously created JWT Section of appsettings.json using the IOptions feature of ASP.NET Core.
public class JWTSettings {
    public string Key {
        get;
        set;
    }
    public string Issuer {
        get;
        set;
    }
    public string Audience {
        get;
        set;
    }
    public double DurationInMinutes {
        get;
        set;
    }
}

Then, add the following classes to your project:
    DbContext - Add connection string in appsettings.json
    ApplicationUser which derives from IdentityUser

3(b). Configure JWT in code as shown
To configure the authentication, add code to ConfigureServices method as shown below-
public void ConfigureServices(IServiceCollection services) {
    Line 1 //The JWT Configuration from AppSettings
    services.Configure < JWTSettings > (_configuration.GetSection("JWT"));
    //The User Manager Service
    services.AddIdentity < ApplicationUser, IdentityRole > ().AddEntityFrameworkStores < ApplicationDbContext > ();
    services.AddScoped < IUserService, UserService > ();
    //Adding DB Context with MSSQL
    services.AddDbContext < ApplicationDbContext > (options => options.UseSqlServer(_configuration.GetConnectionString("DefaultConnection"), b => b.MigrationsAssembly(typeof(ApplicationDbContext).Assembly.FullName)));
    //The JWT Athentication
    services.AddAuthentication(options => {
        options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
        options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
    }).AddJwtBearer(oa => {
        oa.RequireHttpsMetadata = false;
        oa.SaveToken = false;
        oa.TokenValidationParameters = new TokenValidationParameters {
            ValidateIssuerSigningKey = true,
                ValidateIssuer = true,
                ValidateAudience = true,
                ValidateLifetime = true,
                ClockSkew = TimeSpan.Zero,
                ValidIssuer = _configuration["JWT:Issuer"],
                ValidAudience = _configuration["JWT:Audience"],
                IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_configuration["JWT:Key"]))
        };
    });
    services.AddControllers();
}


4. For DB Migration
Add a Connection String in APP Settings.json. For creating the database, using Code First Approach of Entity Framework Core.

Before executing the application, please run the following commands on the Package Manager Console to apply migrations.

add-migration "migrationDB"
update-database

Following the set of ASPNET users and roles tables are created post a successful migration, see below


5. Registering a User
Create a Models/RegisterModel.cs with the following properties. The user has to post data with this object to register.
public class RegisterModel {
    [Required]
    public string FirstName {
        get;
        set;
    }
    [Required]
    public string LastName {
        get;
        set;
    }
    [Required]
    public string Username {
        get;
        set;
    }
    [Required]
    public string Email {
        get;
        set;
    }
    [Required]
    public string Password {
        get;
        set;
    }
}


In IUserService.cs, add the following 2 function definitions to Register users accepting a Register Model.
Task<string> RegisterAsync(RegisterModel model);
Task<AuthenticationModel> GetTokenAsync(TokenRequestModel model);

Go to Concrete class, UserService to implement the Register Function.
public async Task < string > RegisterAsync(RegisterModel model) {
    var user = new ApplicationUser {
        UserName = model.Username,
            Email = model.Email,
            FirstName = model.FirstName,
            LastName = model.LastName
    };
    var userWithSameEmail = await _userManager.FindByEmailAsync(model.Email);
    if (userWithSameEmail == null) {
        var result = await _userManager.CreateAsync(user, model.Password);
        if (result.Succeeded) {
            return $ "Success: User Registered with username {user.UserName}";
        } else {
            string descr = "";
            if (result.Errors.Any()) {
                foreach(var item in result.Errors) {
                    descr += item.Description;
                }
            }
            return $ "Error(s), registering user : {descr}";
        }
    } else {
        return $ "Error(s), Email {user.Email } is already registered.";
    }
}

In the above code snippet, we accept the RegisterModel object, perform validations and create the user in DB, else return the appropriate error message.

From the controller, the call will go as below,
[HttpPost("CreateUser")]
public async Task < ActionResult > RegisterAsync(RegisterModel model) {
    var result = await _userService.RegisterAsync(model);
    return Ok(result);
}

6. Test with Postman

Open up Postman and define a raw JSON object that is to be posted to <localhost>/api/user/CreateUser. Check the following screenshot, on success, we get a confirmed user-created message.


7. Generate JWT Token
Let’s try to fetch the JWT Token. We will build a Token Generation function that accepts a TokenRequestModel (email, password), validates them, and builds a token for us.

Following are model classes for token Models/TokenRequestModel.cs and Models/AuthenticationModel.cs,
public class TokenRequestModel {
    [Required]
    public string Email {
        get;
        set;
    }
    [Required]
    public string Password {
        get;
        set;
    }
}

Another class, AuthenticationModel.cs which is basically the response from the API endpoint. This endpoint will return a status message, user details, and finally our token.
public class AuthenticationModel {
    public string Message {
        get;
        set;
    }
    public bool IsAuthenticated {
        get;
        set;
    }
    public string UserName {
        get;
        set;
    }
    public string Email {
        get;
        set;
    }
    public string Token {
        get;
        set;
    }
}


Check below implementation in the concrete class of UserService for the token generation,
public async Task < AuthenticationModel > GetTokenAsync(TokenRequestModel model) {
    var authenticationModel = new AuthenticationModel();
    var user = await _userManager.FindByEmailAsync(model.Email);
    if (user == null) {
        authenticationModel.IsAuthenticated = false;
        authenticationModel.Message = $ "No Accounts Registered with {model.Email}.";
        return authenticationModel;
    }
    if (await _userManager.CheckPasswordAsync(user, model.Password)) {
        authenticationModel.IsAuthenticated = true;
        JwtSecurityToken jwtSecurityToken = await CreateJwtToken(user);
        authenticationModel.Token = new JwtSecurityTokenHandler().WriteToken(jwtSecurityToken);
        authenticationModel.Email = user.Email;
        authenticationModel.UserName = user.UserName;
        return authenticationModel;
    }
    authenticationModel.IsAuthenticated = false;
    authenticationModel.Message = $ "Incorrect Credentials for user {user.Email}.";
    return authenticationModel;
}
private async Task < JwtSecurityToken > CreateJwtToken(ApplicationUser user) {
    var userClaims = await _userManager.GetClaimsAsync(user);
    var roles = await _userManager.GetRolesAsync(user);
    var roleClaims = new List < Claim > ();
    for (int i = 0; i < roles.Count; i++) {
        roleClaims.Add(new Claim("roles", roles[i]));
    }
    var claims = new [] {
        new Claim(JwtRegisteredClaimNames.Sub, user.UserName),
            new Claim(JwtRegisteredClaimNames.Jti, Guid.NewGuid().ToString()),
            new Claim(JwtRegisteredClaimNames.Email, user.Email),
            new Claim("uid", user.Id)
    }.Union(userClaims).Union(roleClaims);
    var symmetricSecurityKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_jwt.Key));
    var signingCredentials = new SigningCredentials(symmetricSecurityKey, SecurityAlgorithms.HmacSha256);
    var jwtSecurityToken = new JwtSecurityToken(issuer: _jwt.Issuer, audience: _jwt.Audience, claims: claims, expires: DateTime.UtcNow.AddMinutes(_jwt.DurationInMinutes), signingCredentials: signingCredentials);
    return jwtSecurityToken;
}

Following are the activities in the above code function,

Line #4 to #11 check the validity of provided email and password and return a message if not.

Line #14 Calls the CreateJWTToken function. This function builds the JWT. It gets all the claims of the user ( user details ) as well as roles if any.

Finally, Line #51 to #57 creates a new JWT Security Token and returns them.

Now, wire this function to Controllers/UserController.cs

[HttpPost("GenerateToken")]
public async Task < IActionResult > GetTokenAsync(TokenRequestModel model) {
    var result = await _userService.GetTokenAsync(model);
    if (string.IsNullOrEmpty(result.Token)) return NotFound(" " + result.Message);
    return Ok(result.Token);
}

Next, post a valid email and password request to ../api/user/GenerateToken. See below Postman screenshot for the successful response of JWT token and AuthenticationModel object containing user details. The validity of this token is 20 minutes (as an expiration time is set to 20 minutes in app.json).

On Posting an invalid password for the same user, PostMan returns the following message: "Incorrect Credentials for user: [email protected]".

8. Access Database information securely, i.e. using the generated token.
I have earlier created few cities in my Database which I shall access using this bearer token. For this, I need to decorate the Get City endpoint with the [Authorize] keyword in the Controller class. Refer below codebase,
[Authorize]
[HttpGet]
[Route("AllCities")]
public IActionResult GetAllCities(string Email) {
    if (appdbcontext.CountryInfos == null || !appdbcontext.CountryInfos.Any()) return Ok("No Country-Cities created as yet.");
    var res = appdbcontext.CountryInfos.Where(aa => aa.Email == Email).
    Select(xx => new {
        City = xx.City,
            Email = xx.Email,
            Isfavourite = xx.Isfavourite
    });
    if (res.Count() < 1) {
        return NotFound("No records against this UserEmail" + Email);
    } else return Ok(res);
}

Now copy the bearer token in the previous snippet and fire this GET Request, ..api/user/allcities?email in POSTMAN to return cities. For a successful response, refer to the screen below,




European ASP.NET Core Hosting :: Generate HTML From MJML Syntax In ASP.NET Core API Using Mjml.AspNetCore Package

clock August 2, 2021 07:49 by author Peter

In this article, you will learn how to integrate Mailjet Markup Language (MJML) in your ASP .Net Core Web API through the NuGet package. MJML sums up everything Mailjet has learned about HTML email creation over the past few years and includes a whole layer of complexity related to responsive email creation.

Make your speed and productivity enhanced with MJML semantic syntax. Say get rid of the endless HTML table or email client email. Creating a responsive email is much easier with tags like <mj-section>, <mj-image>, <mj-text> and <mj-column>. MJML is designed with responsiveness in mind. The abstraction it offers ensures you stay up-to-date with industry practice and responsiveness.

The only thing we do in our API is to add the NuGet package of MJML. Then we will write the MJML syntax for our email template and then we will call the “Render” method of the MJML Service which returns the HTML. We will simply pass it to our email body and it will be rendered in our email.

Let’s see how to do it in simple steps.
Steps

First of all open visual studio and click on create a new project.


Select ASP .NET Core Web API and click Next.


Enter the project name and click Next.


Select target framework as 3.1 and click on Create.


It will take few seconds and your project will be created. There will be a few folders and files in the project already. Right-click on the Controller folder and add a new empty MVC Controller.


 

 

Name the controller as “EmailController”. After creating the EmailController right-click on your project and click on manage NuGet packages. Write MJML in the browse tab and install the latest stable version of Mjml.AspNetCore package.


After installing the package add the namespace of “using Mjml.AspNetCore” in EmailController. You can use dependency injection which will make it much easier to use Mjml Services. For this purpose, write the below code in your “ConfigureServices” method in the startup.cs class and also add namespace “using Mjml.AspNetCore”.
services.AddMjmlServices(o => {
    o.DefaultKeepComments = true;
    o.DefaultBeautify = true;
});

We have successfully created the Mjml service now it’s time to inject it into our controller. Inject “MjmlServices” through the constructor and create a HttpGet method by the name “Send” which returns Ok in case of successful email send. After that write the Mjml syntax for your email template and call the “Render” method of the Mjml service. It will return HTML in response. Simply pass that HTML as your email body. Below is the complete code of the EmailController.
using Microsoft.AspNetCore.Mvc;
using Mjml.AspNetCore;
using System;
using System.Net;
using System.Net.Mail;
using System.Threading.Tasks;
namespace MJMLTestAPI.Controllers {
    [ApiController]
    [Route("[controller]")]
    public class EmailController: ControllerBase {
        public readonly IMjmlServices _mjmlServices;
        public EmailController(IMjmlServices _mjml) => (_mjmlServices) = (_mjml);
        [HttpGet]
        public IActionResult Send() {
            SendEmail();
            return Ok();
        }
        public async Task SendEmail() {
            var prehtml = "<mjml><mj-body><mj-container><mj-section><mj-column><mj-text>Hello World!</mj-text></mj-column></mj-section></mj-container></mj-body></mjml>";
            var result = await _mjmlServices.Render(prehtml);
            SendEmail(result.Html);
        }
        public void SendEmail(string emailBody) {
            try {
                SmtpClient objsmtp = new SmtpClient(EmailServer, Port);
                objsmtp.UseDefaultCredentials = false;
                objsmtp.Credentials = new NetworkCredential(UserName, Password);
                objsmtp.DeliveryMethod = SmtpDeliveryMethod.Network;
                MailMessage msg = new MailMessage(EmailFrom, EmailTo, "MJML Test", emailBody);
                msg.IsBodyHtml = true;
                objsmtp.Timeout = 50000;
                objsmtp.Send(msg);
            } catch (Exception ex) {}
        }
    }
}


Note that the variables (EmailServer, Port, UserName, Password, EmailFrom, EmailTo) in the above SendEmail method will be the settings of your SMTP email server. “prehtml” will be the MJML syntax by which you designed your email template. I used a sample syntax here. You can see sample email templates and their MJML code by visiting this link.

Now, just run your project and replace the weatherforecast in the URL with Email, and press enter button. The email will be sent to your desired email address with the generated email template in the email body.

 



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.


Tag cloud

Sign in