How to Create a QRCoder in ASP.NET Core using C #

How to Create a QRCoder in ASP.NET Core using C #

How to Create a QRCoder in ASP.NET Core using C # - Here I am going to implement the QRCoder library to generate QR Codes in my ASP.NET Core application. I will also be using C#...🚀🚀🚀🚀🚀

How to Create a QRCoder in ASP.NET Core using C # - Here I am going to implement the QRCoder library to generate QR Codes in my ASP.NET Core application. I will also be using C#.

QRCoder is a very popular QR Code implementation library written in C#. It is available in GitHub**. Here I am going to implement the QRCoder library to generate QR Codes in my ASP.NET **Core application. I will also be using C#.

I will implement QRCoder in 3 ways, which are:

  1. Create QR Code Bitmap image for any text.

  2. Create QR Code File (.qrr) for any text and then save these files in the application.

  3. Read and display all the QR Code Files (.qrr).

Let’s start with the Installation of QRCoder in ASP.NET Core Framework.

You can download the full code from my GitHub Respositiory.

Installation

Install QRCoder via NuGet Package Manager. If you want to use NuGet, just search for “QRCoder” or run the following command in the NuGet Package Manager console:

PM> Install-Package QRCoder

The QRCoder will install in 1 minute and will be ready to use.

Now let us start with the implementation of QRCoder in the 3 ways mentioned above.

Create QR Code Bitmap image for any text

Create a new Controller called ‘QRCoderController’ inside the Controllers folder. The controller will be created and it will have just one Action Method called ‘Index’ in it:

public IActionResult Index()
{
    return View();
}

Import the following namespaces in the controller:

using System;
using System.Collections.Generic;
using System.Drawing;
using System.IO;
using Microsoft.AspNetCore.Mvc;
using QRCoder;

Next, add the Index Action of type [HttpPost] to the controller:

[HttpPost]
public IActionResult Index(string qrText)
{
    QRCodeGenerator qrGenerator = new QRCodeGenerator();
    QRCodeData qrCodeData = qrGenerator.CreateQrCode(qrText,
    QRCodeGenerator.ECCLevel.Q);
    QRCode qrCode = new QRCode(qrCodeData);
    Bitmap qrCodeImage = qrCode.GetGraphic(20);
    return View(BitmapToBytes(qrCodeImage));
}

This Index Action receives a string parameter called ‘qrText’. It contains the text that is provided by an Input control defined in the View. This text will be converted to QR Code Bitmap image. The following code lines do this work:

QRCodeGenerator qrGenerator = new QRCodeGenerator();
QRCodeData qrCodeData = qrGenerator.CreateQrCode(qrText, QRCodeGenerator.ECCLevel.Q);
QRCode qrCode = new QRCode(qrCodeData);
Bitmap qrCodeImage = qrCode.GetGraphic(20);

The QRCode object (‘qrCode’) defined calls a static function called ‘BitmapToBytes()’. The role of this function is to convert the Bitmap image to ‘Byte[]’.

Add this function to your controller:

private static Byte[] BitmapToBytes(Bitmap img)
{
    using (MemoryStream stream = new MemoryStream())
    {
        img.Save(stream, System.Drawing.Imaging.ImageFormat.Png);
        return stream.ToArray();
    }
}

Finally create the Index View inside the ‘Views/QRCoder’ folder with the following code:

@model Byte[]
@{
    Layout = null;
}
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width" />     <title>Implementing QRCoder in ASP.NET Core - Create QR Code</title>
<style>
body {
background: #111 no-repeat;
background-image: -webkit-gradient(radial, 50% 0, 150, 50% 0, 300, from(#444), to(#111));
}
h1, h2, h3 {
text-align: center;
color: #FFF;
margin: 5px 0;
}
h1 {
font-size: 30px;
}
h2 a {
font-size: 25px;
color: #0184e3;
text-decoration: none;
}
h3 {
font-size: 23px;
border-bottom: solid 3px #CCC;
padding-bottom: 10px;
}
h3 a {
color: #00e8ff;
text-decoration: none;
}
h3 a:hover, h2 a:hover {
text-decoration: underline;
}
.container {
width: 800px;
margin: auto;
color: #FFF;
font-size: 25px;
}
.container #content {
border: dashed 2px #CCC;
padding: 10px;
}
#reset {
padding: 5px 10px;
background: #4CAF50;
border: none;
color: #FFF;
cursor: pointer;
}
#reset:hover {
color: #4CAF50;
background: #FFF;
}
#viewContent table {
width: 100%;
}
#viewContent table tr {
height: 80px;
background: darkcyan;
}
#viewContent table tr td {
width: 50%;
padding-left: 5px;
}
</style>
</head>
<body>
  <div class="container">
    <div id="content">
      <h1>Implementing QRCoder in ASP.NET Core - Create QR Code</h1>
      <h2>
        <a href="http://www.yogihosting.com/category/aspnet-core/">Read the tutorial on YogiHosting » </a>
      <button id="reset" onclick="location=''">Reset »</button>
      </h2>
      <div id="viewContent">
        @using (Html.BeginForm(null, null, FormMethod.Post))
        {
          <table>
            <tbody>
              <tr>
                <td>
                  <label>Enter text for creating QR Code</label
                </td>
                <td>
                  <input type="text" name="qrText" />
                </td>
              </tr>
              <tr>
                <td colspan="2">
                  <button>Submit</button>
                </td>
              </tr>
            </tbody>
          </table>
        }
      </div>
      
      @{
        if (Model != null)
        {
          <h3>QR Code Successfully Generated</h3>
          <img src="@String.Format("data:image/png;base64,{0}", Convert.ToBase64String(Model))" />
        }
      }
    </div>
  </div>
</body>
</html>

The Index View has an ‘input’ control. The user enters their text into this control to create the QR Code:

<input type="text" name="qrText" />

Once the QR Code is generated by the Index Action method, its ‘byte’ array is returned to the View as model and then the bitmap image is displayed by the below code:

@{
  if (Model != null)
  {
    <h3>QR Code Successfully Generated</h3>
    <img src="@String.Format("data:image/png;base64,{0}", Convert.ToBase64String(Model))" />
  }
}

Testing the Code

Run your application and go to the URL — ‘<a href="http://localhost:50755/QRCoder" target="_blank">http://localhost:50755/QRCoder</a>’ to invoke the Index Action method.

In the text box, add your text and click the submit button to create the QR Code Bitmap image.

See this image which illustrates it working:

Create QR Code File (.qrr) for any text and then save these files in the application

You can also generate QR Code files for a text and save it in your website. These files have .*qrr *extension.

To your controller add the following Action methods called ‘GenerateFile’:

public IActionResult GenerateFile()
{
  return View();
}
[HttpPost]
public IActionResult GenerateFile(string qrText)
{
  QRCodeGenerator qrGenerator = new QRCodeGenerator();
  QRCodeData qrCodeData = qrGenerator.CreateQrCode(qrText,   QRCodeGenerator.ECCLevel.Q);
  string fileGuid = Guid.NewGuid().ToString().Substring(0, 4);
  qrCodeData.SaveRawData("wwwroot/qrr/file-" + fileGuid + ".qrr", QRCodeData.Compression.Uncompressed);
  QRCodeData qrCodeData1 = new QRCodeData("wwwroot/qrr/file-" + fileGuid + ".qrr", QRCodeData.Compression.Uncompressed);
  QRCode qrCode = new QRCode(qrCodeData1);
  Bitmap qrCodeImage = qrCode.GetGraphic(20);
  return View(BitmapToBytes(qrCodeImage));
}

The [HttpPost] version of this action method generates the QR Code files inside the ‘wwwroot/qrr’ folder. The code that does this work is the following:

QRCodeGenerator qrGenerator = new QRCodeGenerator();
QRCodeData qrCodeData = qrGenerator.CreateQrCode(qrText, QRCodeGenerator.ECCLevel.Q);
string fileGuid = Guid.NewGuid().ToString().Substring(0, 4);
qrCodeData.SaveRawData("wwwroot/qrr/file-" + fileGuid + ".qrr", QRCodeData.Compression.Uncompressed);

Once the .qrr file is created then I am simply reading it for its saved location in the website. Then I am converting it to Bitmap type and finally sending the image’s bytes to the view. The corresponding code is:

QRCodeData qrCodeData1 = new QRCodeData("wwwroot/qrr/file-" + fileGuid + ".qrr", QRCodeData.Compression.Uncompressed);
QRCode qrCode = new QRCode(qrCodeData1);
Bitmap qrCodeImage = qrCode.GetGraphic(20);
return View(BitmapToBytes(qrCodeImage));

Next, add the GenerateFile view inside the ‘Views/QRCoder’ folder and add the following code to it:

@model Byte[]
@{
Layout = null;
}
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width" />
<title>Implementing QRCoder in ASP.NET Core - Create QR Code File</title>
<style>
body {
background: #111 no-repeat;
background-image: -webkit-gradient(radial, 50% 0, 150, 50% 0, 300, from(#444), to(#111));
}
h1, h2, h3 {
text-align: center;
color: #FFF;
margin: 5px 0;
}
h1 {
font-size: 30px;
}
h2 a {
font-size: 25px;
color: #0184e3;
text-decoration: none;
}
h3 {
font-size: 23px;
border-bottom: solid 3px #CCC;
padding-bottom: 10px;
}
h3 a {
color: #00e8ff;
text-decoration: none;
}
h3 a:hover, h2 a:hover {
text-decoration: underline;
}
.container {
width: 800px;
margin: auto;
color: #FFF;
font-size: 25px;
}
.container #content {
border: dashed 2px #CCC;
padding: 10px;
}
#reset {
padding: 5px 10px;
background: #4CAF50;
border: none;
color: #FFF;
cursor: pointer;
}
#reset:hover {
color: #4CAF50;
background: #FFF;
}
#viewContent table {
width: 100%;
}
#viewContent table tr {
height: 80px;
background: darkcyan;
}
#viewContent table tr td {
width: 50%;
padding-left: 5px;
}
</style>
</head>
<body>
<div class="container">
<div id="content">
<h1>Implementing QRCoder in ASP.NET Core - Create QR Code File</h1>
<h2>
<a href="http://www.yogihosting.com/category/aspnet-core/">Read the tutorial on YogiHosting » </a>
<button id="reset" onclick="location=''">Reset »</button>
</h2>
<div id="viewContent">
@using (Html.BeginForm(null, null, FormMethod.Post))
{
<table>
<tbody>
<tr>
<td>
<label>Enter text for creating QR File</label>
</td>
<td>
<input type="text" name="qrText" />
</td>
</tr>
<tr>
<td colspan="2">
<button>Submit</button>
</td>
</tr>
</tbody>
</table>
}
</div>
@{
if (Model != null)
{
<h3>QR Code file Successfully Generated</h3>
<img src="@String.Format("data:image/png;base64,{0}", Convert.ToBase64String(Model))" />
}
}
</div>
</div>
</body>
</html>

The code of this View is exactly similar to the ‘Index’ View and works exactly like it.

The URL to invoke this View is ‘<a href="http://localhost:50755/QRCoder/GenerateFile" target="_blank">http://localhost:50755/QRCoder/GenerateFile</a>’.

Read and display all the QR Code Files (.qrr)

You can also read all the .qrr files saved in the website. Go to your controller and add a new action called ‘ViewFile’:

public IActionResult ViewFile()
{
  List<KeyValuePair<string, Byte[]>> fileData=new List<KeyValuePair<string, byte[]>>();
  KeyValuePair<string, Byte[]> data;
  string[] files = Directory.GetFiles("wwwroot/qrr");
  foreach (string file in files)
  {
    QRCodeData qrCodeData = new QRCodeData(file, QRCodeData.Compression.Uncompressed);
    QRCode qrCode = new QRCode(qrCodeData);
    Bitmap qrCodeImage = qrCode.GetGraphic(20);
    Byte[] byteData = BitmapToBytes(qrCodeImage);
    data = new KeyValuePair<string, Byte[]>(Path.GetFileName(file), byteData);
    fileData.Add(data);
  }
  return View(fileData);
}

In this action method, I read the filed located in the ‘qrr’ folder using the code:

Directory.GetFiles("wwwroot/qrr")

Then I add each qrr file’s bytes and name inside a List<KeyValuePair<string, Byte[]>> object.

This object is returned to the View at the end:

return View(fileData);

Finally create the ‘ViewFile’ View inside the ‘Views/QRCoder’ folder with the following code:

@model List<KeyValuePair<string, Byte[]>>
@{
Layout = null;
}
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width" />
<title>Implementing QRCoder in ASP.NET Core - View QR Code Files</title>
<style>
body {
background: #111 no-repeat;
background-image: -webkit-gradient(radial, 50% 0, 150, 50% 0, 300, from(#444), to(#111));
}
h1, h2, h3 {
text-align: center;
color: #FFF;
margin: 5px 0;
}
h1 {
font-size: 30px;
}
h2 a {
font-size: 25px;
color: #0184e3;
text-decoration: none;
}
h3 {
font-size: 23px;
border-bottom: solid 3px #CCC;
padding-bottom: 10px;
}
h3 a {
color: #00e8ff;
text-decoration: none;
}
h3 a:hover, h2 a:hover {
text-decoration: underline;
}
.container {
width: 800px;
margin: auto;
color: #FFF;
font-size: 25px;
}
.container #content {
border: dashed 2px #CCC;
padding: 10px;
}
#reset {
padding: 5px 10px;
background: #4CAF50;
border: none;
color: #FFF;
cursor: pointer;
}
#reset:hover {
color: #4CAF50;
background: #FFF;
}
#viewContent table {
width: 100%;
}
#viewContent table tr {
height: 80px;
background: darkcyan;
}
#viewContent table tr td {
width: 50%;
padding-left: 5px;
}
#viewContent table tr td img {
width: 150px;
}
#viewContent table tr td span {
display: block;
}
</style>
</head>
<body>
<div class="container">
<div id="content">
<h1>Implementing QRCoder in ASP.NET Core - View QR Code Files</h1>
<h2>
<a href="http://www.yogihosting.com/category/aspnet-core/">Read the tutorial on YogiHosting » </a>
<button id="reset" onclick="location=''">Reset »</button>
</h2>
<div id="viewContent">
<table>
<tbody>
@foreach (KeyValuePair<string, Byte[]> k in Model)
{
<tr>
<td>
<img src="@String.Format("data:image/png;base64,{0}", Convert.ToBase64String(k.Value))" />
<span>@k.Key</span>
</td>
</tr>
}
</tbody>
</table>
</div>
</div>
</div>
</body>
</html>

This View displays all the qrr files as bitmap images inside a ‘HTML’ table. The below code creates the HTML table:

<table>
  <tbody>
    @foreach (KeyValuePair<string, Byte[]> k in Model)
    {
      <tr>
        <td>
          <img src="@String.Format("data:image/png;base64,{0}", Convert.ToBase64String(k.Value))" />
         <span>@k.Key</span>
        </td>
      </tr>
    }
  </tbody>
</table>

Testing the Code

Run your application and go to the URL — ‘<a href="http://localhost:50755/QRCoder/ViewFile" target="_blank">http://localhost:50755/QRCoder/ViewFile</a>’ to invoke the ViewFile Action method. You will see all the .qrr files saved in your website.

See the below image which illustrates it working:

View all QRR files

You can download the full code from my GitHub Respositiory.

Conclusion

I hope you love this repository which will help you to use QRCoder in your ASP.NET Core Project. Make sure you like this repository to show your love to it.

If you need any help in ASP.NET Core then let me know in the below comments section.

Create a web API with ASP.NET Core MVC

Create a web API with ASP.NET Core MVC

This tutorial teaches the basics of building a web API with ASP.NET Core.

In this tutorial, you learn how to:

  • Create a web API project.
  • Add a model class.
  • Create the database context.
  • Register the database context.
  • Add a controller.
  • Add CRUD methods.
  • Configure routing and URL paths.
  • Specify return values.
  • Call the web API with Postman.
  • Call the web API with jQuery.

At the end, you have a web API that can manage "to-do" items stored in a relational database.

Overview

This tutorial creates the following API:

Create a web API with ASP.NET Core MVC

The following diagram shows the design of the app.

Create a web API with ASP.NET Core MVC

Prerequisites

Visual Studio

Visual Studio 2019 with the ASP.NET and web development workload

.NET Core SDK 2.2 or later

Visual Studio Code

Visual Studio Code

.NET Core SDK 2.2 or later

C# for Visual Studio Code (latest version)

Visual Studio for Mac

Visual Studio for Mac version 7.7 or later

.NET Core SDK 2.2 or later

Create a Web API project

Visual Studio

  • From the File menu, select New > Project.
  • Select the ASP.NET Core Web Application template. Name the project TodoApi and click OK.
  • In the New ASP.NET Core Web Application - TodoApi dialog, choose the ASP.NET Core version. Select the API template and click OK. Do not select Enable Docker Support.

Create a web API with ASP.NET Core MVC

Visual Studio Code

Open the integrated terminal.

Change directories (cd) to the folder which will contain the project folder.

Run the following commands:

console

dotnet new webapi -o TodoApi
code -r TodoApi

These commands create a new web API project and open a new instance of Visual Studio Code in the new project folder.

When a dialog box asks if you want to add required assets to the project, select Yes.

Visual Studio for Mac

  • Select File > New Solution.
  • Create a web API with ASP.NET Core MVC
  • Select .NET Core App > ASP.NET Core Web API > Next.
  • Create a web API with ASP.NET Core MVC
  • In the Configure your new ASP.NET Core Web API dialog, accept the default Target Framework of *.NET Core 2.2.
  • Enter TodoApi for the Project Name and then select Create.
  • Create a web API with ASP.NET Core MVC

Test the API

The project template creates a values API. Call the Get method from a browser to test the app.

Visual Studio

Press Ctrl+F5 to run the app. Visual Studio launches a browser and navigates to [https://localhost:/api/values](https://localhost:/api/values), where `` is a randomly chosen port number.

If you get a dialog box that asks if you should trust the IIS Express certificate, select Yes. In the Security Warning dialog that appears next, select Yes.

Visual Studio Code

Press Ctrl+F5 to run the app. In a browser, go to following URL: https://localhost:5001/api/values.

Visual Studio for Mac

Select Run > Start With Debugging to launch the app. Visual Studio for Mac launches a browser and navigates to [https://localhost:](https://localhost:), where `` is a randomly chosen port number. An HTTP 404 (Not Found) error is returned. Append /api/values to the URL (change the URL to [https://localhost:/api/values](https://localhost:/api/values)).

The following JSON is returned:

JSON

["value1","value2"]

Add a model class

A model is a set of classes that represent the data that the app manages. The model for this app is a single TodoItem class.

Visual Studio

  • In Solution Explorer, right-click the project. Select Add > New Folder. Name the folder Models.
  • Right-click the Models folder and select Add > Class. Name the class TodoItem and select Add.
  • Replace the template code with the following code:

Visual Studio Code

  • Add a folder named Models.
  • Add a TodoItem class to the Models folder with the following code:

Visual Studio for Mac

  • Right-click the project. Select Add > New Folder. Name the folder Models.
  • Right-click the Models folder, and select Add > New File > General > Empty Class.
  • Name the class TodoItem, and then click New.
  • Replace the template code with the following code:

C#

namespace TodoApi.Models
{
    public class TodoItem
    {
        public long Id { get; set; }
        public string Name { get; set; }
        public bool IsComplete { get; set; }
    }
}

The Id property functions as the unique key in a relational database.

Model classes can go anywhere in the project, but the Models folder is used by convention.

Add a database context

The database context is the main class that coordinates Entity Framework functionality for a data model. This class is created by deriving from the Microsoft.EntityFrameworkCore.DbContext class.

Visual Studio

Right-click the Models folder and select Add > Class. Name the class TodoContext and click Add.

Visual Studio Code/ Visual Studio for Mac

Add a TodoContext class to the Models folder.

Replace the template code with the following code:

C#

using Microsoft.EntityFrameworkCore;

namespace TodoApi.Models
{
    public class TodoContext : DbContext
    {
        public TodoContext(DbContextOptions options)
            : base(options)
        {
        }

        public DbSet TodoItems { get; set; }
    }
}
Register the database context

In ASP.NET Core, services such as the DB context must be registered with the dependency injection (DI) container. The container provides the service to controllers.

Update Startup.cs with the following highlighted code:

C#

// Unused usings removed
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using TodoApi.Models;

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

        public IConfiguration Configuration { get; }

        // This method gets called by the runtime. Use this method to add services to the 
        //container.
        public void ConfigureServices(IServiceCollection services)
        {
            services.AddDbContext(opt =>
                opt.UseInMemoryDatabase("TodoList"));
            services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
        }

        // This method gets called by the runtime. Use this method to configure the HTTP 
        //request pipeline.
        public void Configure(IApplicationBuilder app, IHostingEnvironment env)
        {
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }
            else
            {
                // 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.UseMvc();
        }
    }
}

The preceding code:

  • Removes unused using declarations.
  • Adds the database context to the DI container.
  • Specifies that the database context will use an in-memory database.
Add a controller

Visual Studio

  • Right-click the Controllers folder.
  • Select Add > New Item.
  • In the Add New Item dialog, select the API Controller Class template.
  • Name the class TodoController, and select Add.
  • Create a web API with ASP.NET Core MVC

Visual Studio Code/ Visual Studio for Mac

In the Controllers folder, create a class named TodoController.

Replace the template code with the following code:

C#

using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using TodoApi.Models;

namespace TodoApi.Controllers
{
    [Route("api/[controller]")]
    [ApiController]
    public class TodoController : ControllerBase
    {
        private readonly TodoContext _context;

        public TodoController(TodoContext context)
        {
            _context = context;

            if (_context.TodoItems.Count() == 0)
            {
                // Create a new TodoItem if collection is empty,
                // which means you can't delete all TodoItems.
                _context.TodoItems.Add(new TodoItem { Name = "Item1" });
                _context.SaveChanges();
            }
        }
    }
}

The preceding code:

  • Defines an API controller class without methods.
  • Decorates the class with the [ApiController] attribute. This attribute indicates that the controller responds to web API requests. For information about specific behaviors that the attribute enables, see Create web APIs with ASP.NET Core.
  • Uses DI to inject the database context (TodoContext) into the controller. The database context is used in each of the CRUD methods in the controller.
  • Adds an item named Item1 to the database if the database is empty. This code is in the constructor, so it runs every time there's a new HTTP request. If you delete all items, the constructor creates Item1 again the next time an API method is called. So it may look like the deletion didn't work when it actually did work.
Add Get methods

To provide an API that retrieves to-do items, add the following methods to the TodoController class:

C#

// GET: api/Todo
[HttpGet]
public async Task>> GetTodoItems()
{
    return await _context.TodoItems.ToListAsync();
}

// GET: api/Todo/5
[HttpGet("{id}")]
public async Task> GetTodoItem(long id)
{
    var todoItem = await _context.TodoItems.FindAsync(id);

    if (todoItem == null)
    {
        return NotFound();
    }

    return todoItem;
}

These methods implement two GET endpoints:

  • GET /api/todo
  • GET /api/todo/{id}

Test the app by calling the two endpoints from a browser. For example:

  • [https://localhost:/api/todo](https://localhost:/api/todo)
  • [https://localhost:/api/todo/1](https://localhost:/api/todo/1)

The following HTTP response is produced by the call to GetTodoItems:

**JSON**

[
  {
    "id": 1,
    "name": "Item1",
    "isComplete": false
  }
]
Routing and URL paths

The [[HttpGet]](https://docs.microsoft.com/en-us/dotnet/api/microsoft.aspnetcore.mvc.httpgetattribute) attribute denotes a method that responds to an HTTP GET request. The URL path for each method is constructed as follows:

  • Start with the template string in the controller's Route attribute:

C#

namespace TodoApi.Controllers
{
    [Route("api/[controller]")]
    [ApiController]
    public class TodoController : ControllerBase
    {
        private readonly TodoContext _context;
  • Replace [controller] with the name of the controller, which by convention is the controller class name minus the "Controller" suffix. For this sample, the controller class name is TodoController, so the controller name is "todo". ASP.NET Core routing is case insensitive.
  • If the [HttpGet] attribute has a route template (for example, [HttpGet("products")]), append that to the path. This sample doesn't use a template. For more information, see Attribute routing with Http[Verb] attributes.

In the following GetTodoItem method, "{id}" is a placeholder variable for the unique identifier of the to-do item. When GetTodoItem is invoked, the value of "{id}" in the URL is provided to the method in itsid parameter.

C#

// GET: api/Todo/5
[HttpGet("{id}")]
public async Task> GetTodoItem(long id)
{
    var todoItem = await _context.TodoItems.FindAsync(id);

    if (todoItem == null)
    {
        return NotFound();
    }

    return todoItem;
}
Return values

The return type of the GetTodoItems and GetTodoItem methods is ActionResult type. ASP.NET Core automatically serializes the object to JSON and writes the JSON into the body of the response message. The response code for this return type is 200, assuming there are no unhandled exceptions. Unhandled exceptions are translated into 5xx errors.

ActionResult return types can represent a wide range of HTTP status codes. For example, GetTodoItem can return two different status values:

  • If no item matches the requested ID, the method returns a 404 NotFound error code.
  • Otherwise, the method returns 200 with a JSON response body. Returning item results in an HTTP 200 response.
Test the GetTodoItems method

This tutorial uses Postman to test the web API.

  • Install Postman
  • Start the web app.
  • Start Postman.
  • Disable SSL certificate verification
  • From File > Settings (*General tab), disable SSL certificate verification.
  • Warning
  • Re-enable SSL certificate verification after testing the controller.
  • Create a new request.
  • Set the HTTP method to GET.
  • Set the request URL to [https://localhost:/api/todo](https://localhost:/api/todo). For example, [https://localhost:5001/api/todo](https://localhost:5001/api/todo).
  • Set Two pane view in Postman.
  • Select Send.

Create a web API with ASP.NET Core MVC

Add a Create method

Add the following PostTodoItem method:

C#

	// POST: api/Todo
[HttpPost]
public async Task> PostTodoItem(TodoItem item)
{
    _context.TodoItems.Add(item);
    await _context.SaveChangesAsync();

    return CreatedAtAction(nameof(GetTodoItem), new { id = item.Id }, item);
}
	```

The preceding code is an HTTP POST method, as indicated by the [[HttpPost]](https://docs.microsoft.com/en-us/dotnet/api/microsoft.aspnetcore.mvc.httppostattribute) attribute. The method gets the value of the to-do item from the body of the HTTP request.

The `CreatedAtAction` method:

*   Returns an HTTP 201 status code, if successful. HTTP 201 is the standard response for an HTTP POST method that creates a new resource on the server.
*   Adds a `Location` header to the response. The `Location` header specifies the URI of the newly created to-do item. For more information, see [10.2.2 201 Created](https://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html).
*   References the `GetTodoItem` action to create the `Location` header's URI. The C# `nameof` keyword is used to avoid hard-coding the action name in the `CreatedAtAction` call.
*   C#

// GET: api/Todo/5
[HttpGet("{id}")]
public async Task> GetTodoItem(long id)
{
var todoItem = await _context.TodoItems.FindAsync(id);

if (todoItem == null)
{
    return NotFound();
}

return todoItem;

}


### Test the PostTodoItem method

*   Build the project.
*   In Postman, set the HTTP method to `POST`.
*   Select the **Body** tab.
*   Select the **raw** radio button.
*   Set the type to **JSON (application/json)**.
*   In the request body enter JSON for a to-do item:
*   JSON

{

"name":"walk dog",
"isComplete":true
}
```

  • Select Send.
    Create a web API with ASP.NET Core MVC
  • If you get a 405 Method Not Allowed error, it's probably the result of not compiling the project after adding the PostTodoItem method.

Test the location header URI

  • Select the Headers tab in the Response pane.
  • Copy the Location header value:
    Create a web API with ASP.NET Core MVC
  • Set the method to GET.
  • Paste the URI (for example, [https://localhost:5001/api/Todo/2](https://localhost:5001/api/Todo/2))
  • Select Send.
Add a PutTodoItem method

Add the following PutTodoItem method:

C#

	// PUT: api/Todo/5
[HttpPut("{id}")]
public async Task PutTodoItem(long id, TodoItem item)
{
    if (id != item.Id)
    {
        return BadRequest();
    }

    _context.Entry(item).State = EntityState.Modified;
    await _context.SaveChangesAsync();

    return NoContent();
}
	```

`PutTodoItem` is similar to `PostTodoItem`, except it uses HTTP PUT. The response is [204 (No Content)](https://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html). According to the HTTP specification, a PUT request requires the client to send the entire updated entity, not just the changes. To support partial updates, use [HTTP PATCH](https://docs.microsoft.com/dotnet/api/microsoft.aspnetcore.mvc.httppatchattribute).

If you get an error calling `PutTodoItem`, call `GET` to ensure there is an item in the database.

### Test the PutTodoItem method

This sample uses an in-memory database that must be initialed each time the app is started. There must be an item in the database before you make a PUT call. Call GET to insure there is an item in the database before making a PUT call.

Update the to-do item that has id = 1 and set its name to "feed fish":

`JSON`

  {
"ID":1,
"name":"feed fish",
"isComplete":true

}
```

The following image shows the Postman update:

Create a web API with ASP.NET Core MVC

Add a DeleteTodoItem method

Add the following DeleteTodoItem method:

C#

	// DELETE: api/Todo/5
[HttpDelete("{id}")]
public async Task DeleteTodoItem(long id)
{
    var todoItem = await _context.TodoItems.FindAsync(id);

    if (todoItem == null)
    {
        return NotFound();
    }

    _context.TodoItems.Remove(todoItem);
    await _context.SaveChangesAsync();

    return NoContent();
}
	```

The `DeleteTodoItem` response is [204 (No Content)](https://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html).

### Test the DeleteTodoItem method

Use Postman to delete a to-do item:

*   Set the method to `DELETE`.
*   Set the URI of the object to delete, for example `[https://localhost:5001/api/todo/1](https://localhost:5001/api/todo/1)`
*   Select **Send**

The sample app allows you to delete all the items, but when the last item is deleted, a new one is created by the model class constructor the next time the API is called.

## Call the Web API with jQuery

In this section, an HTML page is added that uses jQuery to call the web api. jQuery initiates the request and updates the page with the details from the API's response.

Configure the app to [serve static files](https://docs.microsoft.com/en-us/dotnet/api/microsoft.aspnetcore.builder.staticfileextensions.usestaticfiles#Microsoft_AspNetCore_Builder_StaticFileExtensions_UseStaticFiles_Microsoft_AspNetCore_Builder_IApplicationBuilder_) and [enable default file mapping](https://docs.microsoft.com/en-us/dotnet/api/microsoft.aspnetcore.builder.defaultfilesextensions.usedefaultfiles#Microsoft_AspNetCore_Builder_DefaultFilesExtensions_UseDefaultFiles_Microsoft_AspNetCore_Builder_IApplicationBuilder_):

`C#`

public void Configure(IApplicationBuilder app, IHostingEnvironment env)

{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
// 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.UseDefaultFiles();
app.UseStaticFiles();
app.UseHttpsRedirection();
app.UseMvc();

}
```

Create a wwwroot folder in the project directory.

Add an HTML file named index.html to the wwwroot directory. Replace its contents with the following markup:

HTML

	


    
    To-do CRUD
    


    # To-do CRUD

    ### Add

    
        
        
    

    
        ### Edit

        
            
            
            
            
            ✖
        
    

    



    
        
            Is Complete
            Name
            
            
        
        
    

    
    


	```

Add a **JavaScript** file named _site.js_ to the _wwwroot_ directory. Replace its contents with the following code:

`JavaScript`

const uri = "api/todo";

let todos = null;
function getCount(data) {
const el = $("#counter");
let name = "to-do";
if (data) {
if (data > 1) {
name = "to-dos";
}
el.text(data + " " + name);
} else {
el.text("No " + name);
}
}

$(document).ready(function() {
getData();
});

function getData() {
$.ajax({
type: "GET",
url: uri,
cache: false,
success: function(data) {
const tBody = $("#todos");

  $(tBody).empty();

  getCount(data.length);

  $.each(data, function(key, item) {
    const tr = $("")
      .append(
        $("").append(
          $("", {
            type: "checkbox",
            disabled: true,
            checked: item.isComplete
          })
        )
      )
      .append($("").text(item.name))
      .append(
        $("").append(
          $("Edit").on("click", function() {
            editItem(item.id);
          })
        )
      )
      .append(
        $("").append(
          $("Delete").on("click", function() {
            deleteItem(item.id);
          })
        )
      );

    tr.appendTo(tBody);
  });

  todos = data;
}

});
}

function addItem() {
const item = {
name: $("#add-name").val(),
isComplete: false
};

$.ajax({
type: "POST",
accepts: "application/json",
url: uri,
contentType: "application/json",
data: JSON.stringify(item),
error: function(jqXHR, textStatus, errorThrown) {
alert("Something went wrong!");
},
success: function(result) {
getData();
$("#add-name").val("");
}
});
}

function deleteItem(id) {
$.ajax({
url: uri + "/" + id,
type: "DELETE",
success: function(result) {
getData();
}
});
}

function editItem(id) {
$.each(todos, function(key, item) {
if (item.id === id) {
$("#edit-name").val(item.name);
$("#edit-id").val(item.id);
$("#edit-isComplete")[0].checked = item.isComplete;
}
});
$("#spoiler").css({ display: "block" });
}

$(".my-form").on("submit", function() {
const item = {
name: $("#edit-name").val(),
isComplete: $("#edit-isComplete").is(":checked"),
id: $("#edit-id").val()
};

$.ajax({
url: uri + "/" + $("#edit-id").val(),
type: "PUT",
accepts: "application/json",
contentType: "application/json",
data: JSON.stringify(item),
success: function(result) {
getData();
}
});

closeInput();
return false;
});

function closeInput() {
$("#spoiler").css({ display: "none" });
}
```

A change to the ASP.NET Core MVCproject's launch settings may be required to test the HTML page locally:

  • Open Properties\launchSettings.json.
  • Remove the launchUrl property to force the app to open at index.html—the project's default file.

There are several ways to get jQuery. In the preceding snippet, the library is loaded from a CDN.

This sample calls all of the CRUD methods of the API. Following are explanations of the calls to the API.

Get a list of to-do items

The jQuery ajax function sends a GET request to the API, which returns JSON representing an array of to-do items. The success callback function is invoked if the request succeeds. In the callback, the DOM is updated with the to-do information.

JavaScript

	$(document).ready(function() {
  getData();
});

function getData() {
  $.ajax({
    type: "GET",
    url: uri,
    cache: false,
    success: function(data) {
      const tBody = $("#todos");

      $(tBody).empty();

      getCount(data.length);

      $.each(data, function(key, item) {
        const tr = $("")
          .append(
            $("").append(
              $("", {
                type: "checkbox",
                disabled: true,
                checked: item.isComplete
              })
            )
          )
          .append($("").text(item.name))
          .append(
            $("").append(
              $("Edit").on("click", function() {
                editItem(item.id);
              })
            )
          )
          .append(
            $("").append(
              $("Delete").on("click", function() {
                deleteItem(item.id);
              })
            )
          );

        tr.appendTo(tBody);
      });

      todos = data;
    }
  });
}
	```

### Add a to-do item

The [ajax](https://api.jquery.com/jquery.ajax/) function sends a `POST` request with the to-do item in the request body. The `accepts` and `contentType` options are set to `application/json` to specify the media type being received and sent. The to-do item is converted to JSON by using [JSON.stringify](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/JSON/stringify). When the API returns a successful status code, the `getData` function is invoked to update the HTML table.

`JavaScript`

function addItem() {

const item = {
name: $("#add-name").val(),
isComplete: false
};

$.ajax({
type: "POST",
accepts: "application/json",
url: uri,
contentType: "application/json",
data: JSON.stringify(item),
error: function(jqXHR, textStatus, errorThrown) {
alert("Something went wrong!");
},
success: function(result) {
getData();
$("#add-name").val("");
}
});
}
```

Update a to-do item

Updating a to-do item is similar to adding one. The url changes to add the unique identifier of the item, and the type is PUT.

JavaScript

	$.ajax({
  url: uri + "/" + $("#edit-id").val(),
  type: "PUT",
  accepts: "application/json",
  contentType: "application/json",
  data: JSON.stringify(item),
  success: function(result) {
    getData();
  }
});
	```

### Delete a to-do item

Deleting a to-do item is accomplished by setting the `type` on the AJAX call to `DELETE` and specifying the item's unique identifier in the URL.

`JavaScript`

$.ajax({

url: uri + "/" + id,
type: "DELETE",
success: function(result) {
getData();
}
});
```

How to create an Angular 8 application with ASP.NET Core 3.0

How to create an Angular 8 application with ASP.NET Core 3.0

In this post, we will see how to create an Angular 8 application with ASP.NET Core 3.0 SDK using the default Visual Studio 2019 template

Introduction

Microsoft just released .NET Core 3.0 on 23rd September 2019. You can get the latest version from this URL. Please note, if you are a Windows developer, you must install Visual Studio 2019 version 16.3 or later to work with this version. .NET Core 3.0 contains more awesome features. Previous ASP.NET version 2.1 and 2.2 were shipped with Angular version 6 only. But in this current release, Microsoft added the latest version of Angular 8. They have resolved the loading issues in previous version as well. In this post, I will explain the steps to create an Angular 8 application with ASP.NET 3.0. We will create a simple controller class to get latest C# Corner posts details and will be shown in the home component. We will get more features soon from Microsoft soon.

Install Node.js latest version

Please download the latest version of Node.js from their website. You require Node.js 10 or later version to work with Angular 8 as per their official documentation.

How to create an Angular 8 application with ASP.NET Core

Download and Install .NET Core 3.0 SDK.

As I mentioned earlier, .NET Core 3.0 requires Visual Studio 2019 v.16.3 or later. Please download and install the latest version of Visual Studio.

After installing both .NET Core 3.0 and Visual Studio 2019 v.16.3, you can create a new project in Visual Studio.

How to create an Angular 8 application with ASP.NET Core

Choose ASP.NET Core Web Application template and click Next button.

How to create an Angular 8 application with ASP.NET Core

Please give a valid name to the project and choose an appropriate folder to save that project. Click “Create” button to go next stage.

How to create an Angular 8 application with ASP.NET Core

Please note, by default HTTPS configuration is selected. If you do not wish that, please remove the tick from check box.

After clicking the “Create” button, your new project will be created shortly.

How to create an Angular 8 application with ASP.NET Core

You can see a “ClientApp” folder is created in the project. This is our Angular 8 project.

How to create an Angular 8 application with ASP.NET Core

If you check the package.json file, you can see the Angular library references. Please note that, node_modules are not yet created automatically. You must build the solution to create node packages. Other option is to just run the project. The node dependencies will be created automatically.

How to create an Angular 8 application with ASP.NET Core

In previous version of Angular 6 with ASP.NET Core 2.2, showed some error in the startup needed multiple refresh to resolve the issue. In this version, Microsoft resolved those issues.

How to create an Angular 8 application with ASP.NET Core

But currently I am getting some errors in the console with default project. Hopefully, Microsoft team will resolve these issues in coming releases. Adding to this project, we can create a new controller for getting the latest posts details (articles, blogs and news) from C# Corner RSS feeds.

Create an API controller for getting C# Corner RSS Feeds

We can create a “Feed” class.


    using System;  
      
    namespace Angular8ASPNETCore3  
    {  
        public class Feed  
        {  
            public string Link { get; set; }  
            public string Title { get; set; }  
            public string FeedType { get; set; }  
            public string Author { get; set; }  
            public string Content { get; set; }  
            public DateTime PubDate { get; set; }  
            public string PublishDate { get; set; }  
      
            public Feed()  
            {  
                Link = "";  
                Title = "";  
                FeedType = "";  
                Author = "";  
                Content = "";  
                PubDate = DateTime.Today;  
                PublishDate = DateTime.Today.ToString("dd-MMM-yyyy");  
            }  
        }  
    }  

We can create the controller for getting RSS feeds for latest post details from C# Corner.

RssFeedsController.cs


    using Microsoft.AspNetCore.Mvc;  
    using System;  
    using System.Collections.Generic;  
    using System.Globalization;  
    using System.Linq;  
    using System.Xml.Linq;  
      
    namespace Angular8ASPNETCore3.Controllers  
    {  
        [ApiController]  
        [Route("[controller]")]  
        public class RssFeedsController : ControllerBase  
        {  
            readonly CultureInfo culture = new CultureInfo("en-US");  
      
            [HttpGet]  
            public IEnumerable<Feed> Get()  
            {  
                try  
                {  
                    XDocument doc = XDocument.Load("https://www.c-sharpcorner.com/rss/latestcontentall.aspx");  
                    var entries = from item in doc.Root.Descendants().First(i => i.Name.LocalName == "channel").Elements().Where(i => i.Name.LocalName == "item")  
                                  select new Feed  
                                  {  
                                      Content = item.Elements().First(i => i.Name.LocalName == "description").Value,  
                                      Link = (item.Elements().First(i => i.Name.LocalName == "link").Value).StartsWith("/") ? "https://www.c-sharpcorner.com" + item.Elements().First(i => i.Name.LocalName == "link").Value : item.Elements().First(i => i.Name.LocalName == "link").Value,  
                                      PubDate = Convert.ToDateTime(item.Elements().First(i => i.Name.LocalName == "pubDate").Value, culture),  
                                      PublishDate = Convert.ToDateTime(item.Elements().First(i => i.Name.LocalName == "pubDate").Value, culture).ToString("dd-MMM-yyyy"),  
                                      Title = item.Elements().First(i => i.Name.LocalName == "title").Value,  
                                      FeedType = (item.Elements().First(i => i.Name.LocalName == "link").Value).ToLowerInvariant().Contains("blog") ? "Blog" : (item.Elements().First(i => i.Name.LocalName == "link").Value).ToLowerInvariant().Contains("news") ? "News" : "Article",  
                                      Author = item.Elements().First(i => i.Name.LocalName == "author").Value  
                                  };  
      
                    return entries.OrderByDescending(o => o.PubDate);  
                }  
                catch  
                {  
                    List<Feed> feeds = new List<Feed>();  
                    Feed feed = new Feed();  
                    feeds.Add(feed);  
                    return feeds;  
                }  
            }  
        }  
    }  

Please create above class under “Controllers” folder and paste above code. Please add required references to your class.

We can modify the Home component inside the “ClientApp”, “src” and “app” folder with below code.

home.component.ts


    import { Component, Inject } from '@angular/core';  
    import { HttpClient } from '@angular/common/http';  
      
    @Component({  
        selector: 'app-home',  
        templateUrl: './home.component.html'  
    })  
    export class HomeComponent {  
        latestPosts: Feed[] = [];  
        constructor(http: HttpClient, @Inject('BASE_URL') baseUrl: string) {  
            http.get<Feed[]>(baseUrl + 'rssfeeds').subscribe(result => {  
                this.latestPosts = result;  
            }, error => console.error(error));  
        }  
    }  
      
    interface Feed {  
        link: string;  
        title: string;  
        feedType: string;  
        author: string;  
        content: string;  
        publishDate: string;  
    }    

Also modify the template file with below code.

home.component.html

<div style="text-align:center">  
  <h1 style="margin-top:10px;">  
    Welcome to Angular <b style="color:crimson">8</b> with ASP.NET Core <b style="color:navy">3.0</b>  
  </h1>  
  <img width="200" alt="Angular ASP.Net Core Logo" src="../assets/angularcore.png" />  
  <div class="card" style="margin-left:50px; margin-right:50px; margin-bottom:50px;">  
    <div class="card-header" style="font-weight:bold; font-size:x-large;">  
      C# Corner Latest Posts from RSS Feeds  
    </div>  
    <div class="card-body">  
      <div class="table-responsive" style="max-height:385px;">  
        <table class="table mb-0" *ngIf="latestPosts && latestPosts.length>0">  
          <thead>  
            <tr>  
              <th>Sl.No</th>  
              <th>Post Title(With Link)</th>  
              <th>Post Type</th>  
              <th>Published Date</th>  
              <th>Author</th>  
            </tr>  
          </thead>  
          <tbody>  
            <tr *ngFor="let post of latestPosts; let i = index">  
              <td>{{ i + 1 }}</td>  
              <td style="text-align:left;"><a href="{{post.link}}" target="_blank">{{post.title}}</a></td>  
              <td>{{ post.feedType }}</td>  
              <td>{{ post.publishDate }}</td>  
              <td>{{ post.author}} </td>  
            </tr>  
          </tbody>  
        </table>  
      </div>  
    </div>  
  </div>  
</div> 

We have successfully modified the Home component. We can run the application.

How to create an Angular 8 application with ASP.NET Core

We could see the latest 30 articles/blogs/news details from C# Croner in this home page.

Conclusion

In this post, we could see how to create an Angular 8 project with ASP.NET Core 3.0 latest SDK in very simple steps. We could also see that; Microsoft improved the performance of Angular 8 application and reduced the initial loading time as well. I can say this is very light weight build. We can expect more exciting features from Microsoft team very soon. I will also try to write more articles on other features of .NET Core 3.0 very soon. Please give your valuable feedback about this post.

Overview of Blazor Grid Templates

Overview of Blazor Grid Templates

In this article we'll see an overview of what templates are available and simple use cases. We'll use these as building blocks to see just how dynamic a Blazor grid can be when using templates for advanced ideas like custom editors and master-detail views.

Originally published by Ed Charbeneau at https://www.telerik.com     

Using a template in an application implies that you're creating a custom experience for your user by leveraging a component or framework you're working with. Because the Telerik UI for Blazor components are native, built from the ground up using the Blazor framework, it can tap directly in to Blazor's best features. Grid component templates can fully utilize the HTML, Razor, and components to completely customize the user experience.

In this article we'll see an overview of what templates are available and simple use cases. We'll use these as building blocks to see just how dynamic a Blazor grid can be when using templates for advanced ideas like custom editors and master-detail views.

Template Types

There are currently three types of templates available for the Blazor grid: column Template, Editor Template, and Row Template. Each has very specific uses and are powerful tools for adapting the grid to your specific needs. Let's start with a quick introduction to each template type.

Column Template

By default, the grid renders the value of the field in the column exactly as it's provided from the data source. We can override this behavior by using a column Template which allows us to take control over the rendering of the object within the column. The Template provides the entire object currently bound to the row in which the column exists, and this object is the template's context. Through the Template we can apply custom formatting, insert additional HTML and images, and display Razor Components using any value from the context.

<TelerikGridColumn Field="@(nameof(SampleData.Name))" Title="Employee Name">
   <Template>
      Employee name is: @((context as SampleData).Name)
   </Template>
</TelerikGridColumn>

The column Template is visible when the current row is not in edit mode. To customize the grid's editing experience we'll use the EditorTemplate.

Editor Template

The EditorTemplate is a template that bound to the editing context. The EditorTemplate defines the inline template or component that will be rendered when the user is editing the field. Although the EditorTemplate acts much like the column Template, it is only shown when the given row is in edit mode.

<TelerikGridColumn [email protected](Employee.VacationDays) Title="Position">
   <EditorTemplate>
       @{
           var employeeToUpdate = context as Employee;
                      <KendoNumericTextBox Decimals="1" Format="#.0 days" Max="15" Min="0" Step="0.5m" Value="@employeeToUpdate.VacationDays" />
       }
   </EditorTemplate>
</TelerikGridColumn>

The column and editor templates give excellent control over column rendering in the grid. For even more control we can choose to use a row template and completely customize the grid.

Row Template

Unlike the previously mentioned templates, the RowTemplate spans the entire grid for all columns. The row template allows you to define custom rendering for the entire <tr> element for each record. It can be convenient if you want to use templates for most or all of the columns, as it requires less markup than setting individual templates for many columns.

Since the template isn't bound to a specific column, it can use the Context attribute of the RowTemplate to set the name of the context variable. Its type is the model type to which the grid is bound.

<RowTemplate Context="employee">
   <td>
       <span>@employee.Id</span>
   </td>
   <td>
       Hired on: @(String.Format("{0:dd MMM yyyy}", employee.HireDate))
   </td>
</RowTemplate>
<TelerikGridColumns>
   <TelerikGridColumn [email protected](SampleData.Name) Title="Employee Name" />
   <TelerikGridColumn [email protected](SampleData.HireDate) Title="Hire Date" />
</TelerikGridColumns>

Using the three template types we can tackle a wide variety of requirements. Let's look at how flexible the Telerik UI for Blazor Grid can be - what we can accomplish might just surprise you.

Image Template

We'll begin with a simple yet common scenario, embedding an image in a grid column. Let's assume we have a list of users that we need to manage a broad range of details for. It be nice to associate a face with a name, and with a column template we can do just that. Using a column template we can use one or many values from the currently bound item's properties to generate an image element and display an image directly in the column. In this example we'll assume that our product's images are stored on the server with a relative path of /images/, and each image file name corresponds to the productId.

Let's begin without a template to see how the grid is structured without customization.

<TelerikGrid [email protected] Height="500">
   <TelerikGridColumns>
       <TelerikGridColumn [email protected](Product.ProductName) Title="Product Name"/>
       <TelerikGridColumn [email protected](Product.UnitPrice) Title="Unit Price"/>
   </TelerikGridColumns>
</TelerikGrid> 

@functions {
   public IEnumerable<Product> GridData { get; set; }
   
    protected override void OnInit() => GridData = ... //fetch data;
}

Here we have a basic two column grid with just a text display of each Product Name and Unit Price. Using a template we can transform the Product Name column to display an image alongside the product name.

To access the template, the Product Name column needs to have a TelerikGridColumn component with matching begin/end tags. Inside the component we'll add a Template component which will define our custom rendering. Inside of the template we have access to the context object, this is the current Product in scope. A simple cast of context as Product will give us access to the proper type.

<TelerikGridColumn [email protected](Product.ProductName) Title="Product Name">
   <Template>
       @{
           var product = context as Product;
       }
   </Template>
</TelerikGridColumn>

Now that we have our current Product we can render it how we see fit within the column. Let's add an HTML <img tag and create a path from the ProductId property. We can apply CSS to the image using standard HTML markup class="rounded-circle". Also, since this is Razor, C# string literals are a valid way of formating the path src="@($"/images/{product.ProductId}.jpg")". We'll also display the Product Name property along side the image using simple markup.

<TelerikGrid [email protected] Height="500">
   <TelerikGridColumns>
       <TelerikGridColumn [email protected](Product.ProductName) Title="Product Name">
           <Template>
               @{
                   var product = context as Product;
                   <img class="rounded-circle" src="@($"/images/{product.ProductId}.jpg")" />
                   <span>@product.ProductName</span>
               }
           </Template>
       </TelerikGridColumn>
       <TelerikGridColumn [email protected](Product.UnitPrice) Title="Unit Price"/>
   </TelerikGridColumns>
</TelerikGrid>

@functions ...

Because the underlying Razor Components framework supports templates and the Telerik UI for Blazor Grid is built using the framework's native architecture, the grid is a fully capable solution to many problems.

Custom Form

With templates we can fully utilize Blazor's framework features. Inside the template we can add components, logic, and even trigger events. In addition, templates aren't just scoped to the component they're contained in - we can access events and values outside of the template as well. This opens up new possibilities for creating a custom experience.

Let's assume we want to create a custom edit experience versus using one of the built in grid editors. This will give us full control over every aspect of the form. The challenge is getting the form to interact with the grid. To make a custom editor we'll need to select an item, place its properties on a form, and save/cancel changes. On the surface this might seem like a complex task, however the framework has extremely flexible data binding mechanics.

Identifying the currently selected object would provide most of what we need to accomplish the task since we can bind its properties directly to form elements. The grid's template gives us access to items that are bound to a grid row, all we'll need is a method of selecting the value and creating a reference to the object. Let's start by creating a placeholder for our object reference using a field named selectedProduct. To create an easy way of selecting a product, a column template with a button will suffice. When the button is clicked, we'll invoke an in-line function to set selectedProduct to the current context.

<TelerikGridColumn [email protected](Product.ProductId) Title="Id">
   <Template>
       <TelerikButton Icon="edit" OnClick="@(=> selectedProduct = (Product)context)">Edit</TelerikButton>
   </Template>
</TelerikGridColumn>

With the data referenced we can now add a form to display the information and provide save and cancel actions. The form will exist outside of the grid, since the object reference is now scoped to the page we can place the form anywhere outside the grid. The form can be hidden or shown based on if an item is selected using a standard Razor @if block.

@if (selectedProduct != null) {
       ...form
}

Saving and canceling the edit are also straightforward tasks now. We just need to create buttons with corresponding OnClick events. To cancel the edit, the selectedProduct reference is simply reset to null.

<TelerikGrid [email protected] [email protected] Pageable="true" [email protected]>
   <TelerikGridColumns>
       <TelerikGridColumn [email protected](Product.ProductId) Title="Id">
           <Template>
               <TelerikButton Icon="edit" OnClick="@(=> selectedProduct = (Product)context)">Edit</TelerikButton>
           </Template>
       </TelerikGridColumn>
       <TelerikGridColumn [email protected](Product.ProductName) Title="Product Name" />
       <TelerikGridColumn [email protected](Product.UnitPrice) Title="Unit Price" />
   </TelerikGridColumns>
</TelerikGrid>
<hr />
@if (selectedProduct != null)
{
   <div class="form-group ">
       <label class="control-label" for="productName">
           Product Name
       </label>
       <input class="form-control" bind="@selectedProduct.ProductName" id="name" name="name" type="text" />
   </div>
   <div class="form-group ">
       <label class="control-label" for="unitPrice">
           Unit Price
       </label>
       <input class="form-control" bind="@selectedProduct.UnitPrice" id="unitPrice" name="unitPrice" type="number" />
   </div>
   <div class="form-group">
       <div>
           <TelerikButton Icon="save" Class="k-primary" OnClick="@Save">Save</TelerikButton>
           <TelerikButton Icon="cancel" OnClick="@(_=> selectedProduct = null)">Cancel</TelerikButton>
       </div>
   </div>
}
@functions {
   ...
   Product selectedProduct;

   void Save()
   {
              // save logic
       selectedProduct = null;
   }
}

With the ability to share state with other components on the page, the opportunities for template driven experiences are unlimited.

Master-Detail View

Using templates we can completely transform an entire grid row with custom HTML, Razor, and even components. In this next example we'll look at just how advanced we can get with templates by adding a Master-Detail view to a grid.

A likely scenario for any application is one where a data point has many properties with varying importance. Some of those properties should always be front and center, while others might be helpful to have just within reach. This is where a master-detail view can be quite handy. This type of view helps keep extended data out of view until it is requested by the user, while keeping critical data up front all of the time.

Using the RowTemplate we can define two different states for our row which can easily be toggled by a simple button click. We'll start with the default state which only displays two columns of data. This view is nicely tucked away in a custom component called ProductMasterTemplate and takes a parameter of Product to be displayed in a two column format.

<ProductMasterTemplate Product="@product" />

HTML

In addition, we'll use a more complex view to reveal all of the data for a given product in a list view. Once again, we'll encapsulate the view in custom component called ProductDetailTemplate.

<ProductDetailTemplate Product="@product"/>

Within each of these custom components are table data cells <td> that contain Razor code for displaying the properties of a given Product. The contents of the row template must be <td> elements and their number (or total colspan) must match the number of columns defined in the grid. Internally both templates contain markup similar to the following example.

<td>@Product.property</td>
<td colspan="2">
       ... some view logic
</td>

With the two states clearly defined as components we can focus on switching between the two. Let's begin by defining which item is selected by creating a variable where we can hold a reference to the selected product. As such, we'll name it SelectedProduct. To enable the user to toggle between views, we'll need a set of buttons to display for the user. To show the details we'll simply check the SelectedProduct to see if it matches the current item in the row. Since we're using Blazor, we can easily set the state of SelectedProduct directly in the event handler with an in-line function, OnClick="@(=> SelectedProduct = ...)".

   <RowTemplate Context="product">
       @if (SelectedProduct != product)
       {
           <td>
               <TelerikButton Icon="@IconName.Window" OnClick="@(=> SelectedProduct = product)">Details</TelerikButton>
           </td>
           <ProductMasterTemplate Product="@product" />
       }
       else
       {
           <td>
               <TelerikButton  Icon="@IconName.Close" OnClick="@(=> SelectedProduct = null)">Close</TelerikButton>
           </td>
           <ProductDetailTemplate Product="@product"/>
       }
   </RowTemplate>

The completed code below is actually quite simple due to the combination of template and component architecture.

<TelerikGrid [email protected] Height="@Height">
   <RowTemplate Context="product">
       @if (SelectedProduct != product)
       {
           <td>
               <TelerikButton Icon="@IconName.Window" OnClick="@(=> SelectedProduct = product)">Details</TelerikButton>
           </td>
           <ProductMasterTemplate Product="@product" />
       }
       else
       {
           <td>
               <TelerikButton  Icon="@IconName.Close" OnClick="@(_=> SelectedProduct = null)">Close</TelerikButton>
           </td>
           <ProductDetailTemplate Product="@product"/>
       }
   </RowTemplate>
   <TelerikGridColumns>
       <TelerikGridColumn Width="100" [email protected](Product.ProductName) Title="Product" />
       <TelerikGridColumn [email protected](Product.ProductName) Title="Product Name" />
       <TelerikGridColumn [email protected](Product.UnitsInStock) Title="Unit Price" />
   </TelerikGridColumns>
</TelerikGrid>

@functions {
   Product SelectedProduct;
}

Clicking the Details button gives us a slick UI that allows us to drill into grid data.

Conclusion

Because the Telerik UI for Blazor components are native, built from the ground up using the Blazor framework, it can tap directly in to Blazor's best features. Grid component templates can fully utilize the HTML, Razor, and components to completely customize the user experience. Simple templates are useful for formatting or displaying images, while more extensive templates can transform the user interface completely adding entirely new functionality to the grid.

In this post we focused on the grid, however other components like the DropDownList already feature template fields as well. Make sure you download the latest release and try the templates for yourself using our demo repository on GitHub.

Thanks for reading

If you liked this post, share it with all of your programming buddies!

Follow us on Facebook | Twitter

Further reading about Blazor

Blazor CRUD Using Google Cloud Firestore

Blazor: A new framework for browser-based .NET Apps

How to Login and Registration ASP.NET Web API with Angular 8

How to Login and Registration ASP.NET Web API with Angular 8

In this article, we will learn the step by step process of creating login and registration pages in a Web API with Angular 8

In this article, we will learn the step by step process of creating login and registration pages in a Web API with Angular 8 using the following technologies:

  • ASP.NET Web API.
  • Angular 8.
  • SQL Server.
  • Bootstrap.

You may also like: Angular 8 HttpClient & Http Tutorial – Build and Consume RESTful API.

Prerequisites

  • Basic knowledge of Angular and Web API.
  • Visual Studio Code and Visual Studio IDE should be installed.
  • SQL Server Management Studio.
  • Nodejs should be installed.
Step 1

Open SQL Server Management Studio, create a database named Employee, and in this database, create a table. Give that table a name like Employeemaster.

CREATE TABLE [dbo].[Employeemaster](  
    [UserId] [int] IDENTITY(1,1) NOT NULL,  
    [UserName] [varchar](50) NOT NULL,  
    [LoginName] [varchar](50) NULL,  
    [Password] [varchar](50) NOT NULL,  
    [Email] [varchar](50) NULL,  
    [ContactNo] [varchar](15) NULL,  
    [Address] [varchar](50) NULL,  
    [IsApporved] [int] NULL,  
    [Status] [int] NULL,  
    [TotalCnt] [int] NULL,  
PRIMARY KEY CLUSTERED   
(  
    [UserId] ASC  
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]  
) ON [PRIMARY]  

GO  

Now, create a stored procedure with the name, Usp_Login for adding the login functionality.

create proc  [dbo].[Usp_Login]  
@UserName varchar(50)='',  
@Password varchar(50)=''  
as begin  
    declare @UserId int =0,@TotalCnt int =0  
    select @UserId=UserId,@TotalCnt=TotalCnt from  Employeemaster um   
    where [email protected] and [email protected] and Status<>3 and IsApporved=1  
    if(@TotalCnt>=5)  
    begin  
       select 0 UserId,'' UserName,'' LoginName,'' Password,'' Email,'' ContactNo,   
    ''Address,0 IsApporved,-1 Status  
    end  
    if(@UserId>0)  
    begin  
        select UserId, UserName, LoginName, Password, Email, ContactNo,   
        Address, IsApporved, Status from  Employeemaster um   
        where [email protected]   
        --update  Employeemaster  set  Status=2 where [email protected]   

    end  
    else  
    begin  
       Update Employeemaster set @TotalCnt=TotalCnt+1    
       where [email protected] and Status=1 and IsApporved=1  
       select 0 UserId,'' UserName,'' LoginName,'' Password,'' Email,'' ContactNo,   
    ''Address,0 IsApporved,0 Status  
    end  
    end  
Step 2

Open Visual Studio and create a new project.

Create Registration And Login Page Using Angular 7 And Web API

_Create Registration And Login Page Using Angular 7 And Web API_

Change the name as LoginAPI and select Web API as its template.

Create Registration And Login Page Using Angular 7 And Web API

Step 3

Right-click the Models folder from Solution Explorer and go to Add >> New Item >> data. Create Registration And Login Page Using Angular 7 And Web API

Click on the ADO.NET Entity Data Model option and click Add. Create Registration And Login Page Using Angular 7 And Web API

Select EF designer from the database and click the Next button.

Create Registration And Login Page Using Angular 7 And Web API

Add the connection properties, select database name on the next page, and click OK. Create Registration And Login Page Using Angular 7 And Web API

Check the Tables and Stored procedure checkboxes. The internal options will be selected by default. Now, click the Finish button.

Create Registration And Login Page Using Angular 7 And Web API

Our data model is created now.

Step 4

Right-click on the Models folder and add two classes — Login and Response respectively. Now, paste the following codes in these classes.

using LoginAPI.Models;   
Step 5

Right-click on the Controllers folder and add a new controller. Name it as Logincontroller.

Add the following namespace in the Login controller.

[Route("Api/Login/createcontact")]  
       [HttpPost]  
       public object createcontact(Registration Lvm)  
       {  
           try  
           {  
               DemologinEntities db = new DemologinEntities();  
               Employeemaster Em = new Employeemaster();  
               if (Em.UserId == 0)  
               {  
                   Em.UserName = Lvm.UserName;  
                   Em.LoginName = Lvm.LoginName;  
                   Em.Password = Lvm.Password;  
                   Em.Email = Lvm.Email;  
                   Em.ContactNo = Lvm.ContactNo;  
                   Em.Address = Lvm.Address;  
                   Em.IsApporved = Lvm.IsApporved;  
                   Em.Status = Lvm.Status;  
                   db.Employeemasters.Add(Em);  
                   db.SaveChanges();  
                   return new Response  
                   { Status = "Success", Message = "SuccessFully Saved." };  
               }  
           }  
           catch (Exception)  
           {  

               throw;  
           }  
           return new Response  
           { Status = "Error", Message = "Invalid Data." };  
       }   

Now, add a method to insert data into the database for user registration.

[Route("Api/Login/UserLogin")]  
       [HttpPost]  
       public Response Login(Login Lg)  
       {  
           DemologinEntities DB = new DemologinEntities();  
           var Obj = DB.Usp_Login(Lg.UserName, Lg.Password).ToList<Usp_Login_Result>().FirstOrDefault();  
           if (Obj.Status == 0)  
               return new Response { Status = "Invalid", Message = "Invalid User." };  
           if (Obj.Status == -1)  
               return new Response { Status = "Inactive", Message = "User Inactive." };  
           else  
               return new Response { Status = "Success", Message = Lg.UserName };  
       }  
Step 6

Add a new method for logging into the Login controller with the following lines of code.

using System;  
using System.Collections.Generic;  
using System.Linq;  
using System.Net;  
using System.Net.Http;  
using System.Web.Http;  
using LoginAPI.Models;  

namespace LoginAPI.Controllers  
{  
    public class LoginController : ApiController  
    {  

        //For user login   
        [Route("Api/Login/UserLogin")]  
        [HttpPost]  
        public Response Login(Login Lg)  
        {  
            DemologinEntities DB = new DemologinEntities();  
            var Obj = DB.Usp_Login(Lg.UserName, Lg.Password).ToList<Usp_Login_Result>().FirstOrDefault();  
            if (Obj.Status == 0)  
                return new Response { Status = "Invalid", Message = "Invalid User." };  
            if (Obj.Status == -1)  
                return new Response { Status = "Inactive", Message = "User Inactive." };  
            else  
                return new Response { Status = "Success", Message = Lg.UserName };  
        }  

        //For new user Registration  
        [Route("Api/Login/createcontact")]  
        [HttpPost]  
        public object createcontact(Registration Lvm)  
        {  
            try  
            {  
                DemologinEntities db = new DemologinEntities();  
                Employeemaster Em = new Employeemaster();  
                if (Em.UserId == 0)  
                {  
                    Em.UserName = Lvm.UserName;  
                    Em.LoginName = Lvm.LoginName;  
                    Em.Password = Lvm.Password;  
                    Em.Email = Lvm.Email;  
                    Em.ContactNo = Lvm.ContactNo;  
                    Em.Address = Lvm.Address;  
                    Em.IsApporved = Lvm.IsApporved;  
                    Em.Status = Lvm.Status;  
                    db.Employeemasters.Add(Em);  
                    db.SaveChanges();  
                    return new Response  
                    { Status = "Success", Message = "SuccessFully Saved." };  
                }  
            }  
            catch (Exception)  
            {  

                throw;  
            }  
            return new Response  
            { Status = "Error", Message = "Invalid Data." };  
        }  
    }  

}  

Complete Login controller

EnableCorsAttribute cors = new EnableCorsAttribute("*", "*", "*");  
config.EnableCors(cors);  
Step 7

Now, let's enable Cors. Go to Tools, open NuGet Package Manager, search for Cors, and install the "Microsoft.Asp.Net.WebApi.Cors" package. Create Registration And Login Page Using Angular 7 And Web API Open Webapiconfig.cs and add the following lines.

ng new login
Step 8

Create an Angular 8 project with a name "login" by using the following command.

npm install bootstrap --save
Step 9

Open Visual Studio Code, open the newly created project and add bootstrap to this project.

export class Register {  
    UserName:string;  
    LoginName:string;  
    Password:string;  
    Email:string;  
    ContactNo:string;  
    Address:string  
} 
Step 10

Now, create three components for the login page, registration page, and dashboard respectively. To create the components, open terminal and use the following commands.

  • ng g c login
  • ng g c register
  • ng g c dashboard

Create Registration And Login Page Using Angular 7 And Web API

Step 11

Create a class named "register". ng g class register Add the required properties in the class.

ng g s login 
Step 12

Create a service to call the Web API.

import { Injectable } from '@angular/core';  
import {HttpClient} from '@angular/common/http';  
import {HttpHeaders} from '@angular/common/http';  
import { from, Observable } from 'rxjs';  
import { Register } from "../app/register";  
@Injectable({  
  providedIn: 'root'  
})  
export class LoginService {  
  Url :string;  
  token : string;  
  header : any;  
  constructor(private http : HttpClient) {   

    this.Url = 'http://localhost:14812/api/Login/';  

    const headerSettings: {[name: string]: string | string[]; } = {};  
    this.header = new HttpHeaders(headerSettings);  
  }  
  Login(model : any){  
    debugger;  
     var a =this.Url+'UserLogin';  
   return this.http.post<any>(this.Url+'UserLogin',model,{ headers: this.header});  
  }  
   CreateUser(register:Register)  
   {  
    const httpOptions = { headers: new HttpHeaders({ 'Content-Type': 'application/json' }) };  
    return this.http.post<Register[]>(this.Url + '/createcontact/', register, httpOptions)  
   }  
}  

Open the login service and import required packages and classes. Add the following lines of code in the login.service.ts file.

<div class="container" style="padding-top:40px;">  
    <div class="row">  
      <div class="col-md-6 mx-auto">  
        <div class="card mx-4">  
          <div class="card-body p-4">  
            <form [formGroup]="employeeForm" (ngSubmit)="onFormSubmit(employeeForm.value)">  
              <h1 style="text-align:center">Register</h1>  

              <div class="input-group mb-3">  

                <input type="text" class="form-control" placeholder="Username"  formControlName="UserName">  
              </div>  
              <div class="input-group mb-3">  
                <input type="text" class="form-control" placeholder="Loginname"  formControlName="LoginName">  
              </div>  
              <div class="input-group mb-3">  
                <input type="password" class="form-control" placeholder="Password"  formControlName="Password">  
              </div>  
              <div class="input-group mb-4">  
                <input type="text" class="form-control" placeholder="Email"  formControlName="Email">  
              </div>  
              <div class="input-group mb-4">  
                <input type="text" class="form-control" placeholder="Contact No"  formControlName="ContactNo">  
              </div>  
              <div class="input-group mb-4">  
                <input type="text" class="form-control" placeholder="Address"  formControlName="Address">  
              </div>  
              <button type="submit" class="btn btn-block btn-success">Add User</button>  
            </form>  
          </div>  
        </div>  
      </div>  
    </div>  
  </div>  
Step 13

Now, open register.component.html and add the following HTML code to design the registration form.

import { Component, OnInit } from '@angular/core';    
import { LoginService } from '../login.service';    
import {Register} from '../register';    
import {Observable} from 'rxjs';    
import { NgForm, FormBuilder, FormGroup, Validators, FormControl } from '@angular/forms';    

@Component({    
  selector: 'app-register',    
  templateUrl: './register.component.html',    
  styleUrls: ['./register.component.css']    
})    
export class RegisterComponent implements OnInit {    
  data = false;    
  UserForm: any;    
  massage:string;    
  constructor(private formbulider: FormBuilder,private loginService:LoginService) { }    

  ngOnInit() {    
    thisthis.UserForm = this.formbulider.group({    
      UserName: ['', [Validators.required]],    
      LoginName: ['', [Validators.required]],    
      Password: ['', [Validators.required]],    
      Email: ['', [Validators.required]],    
      ContactNo: ['', [Validators.required]],    
      Address: ['', [Validators.required]],    
    });    
  }    
   onFormSubmit()    
  {    
    const user = this.UserForm.value;    
    this.Createemployee(user);    
  }    
  Createemployee(register:Register)    
  {    
  this.loginService.CreateUser(register).subscribe(    
    ()=>    
    {    
      this.data = true;    
      this.massage = 'Data saved Successfully';    
      this.UserForm.reset();    
    });    
  }    
}    

Step 14

Open register.componet.ts file and add following lines.

<div class="container" style="padding-top:60px;">  
  <div class="row">  
    <div class="col-md-6 mx-auto">  
      <div class="card-group">  
        <div class="card p-4">  
          <div class="card-body">  
            <form name="form" (ngSubmit)="login()" #f="ngForm">   
              <h1 style="text-align:center">Login</h1>  

              <div class="input-group mb-3">  
                <div class="input-group-prepend">  
                  <span class="input-group-text"><i class="icon-user"></i></span>  
                </div>  
                <input type="text" name="UserName" [(ngModel)]="model.UserName" class="form-control sty1" placeholder="Email" required>  
              </div>  
              <div class="input-group mb-4">  
                <div class="input-group-prepend">  
                  <span class="input-group-text"><i class="icon-lock"></i></span>  
                </div>  
                <input  type="password" name="Passward" [(ngModel)]="model.Password" class="form-control"  
               placeholder="Password">  
              </div>  
              <div>  
                  <p style="color:#E92626;font-size:20px;font-weight:normal" Class="success" align="left">  
                    {{errorMessage}}  
                  </p>  
                </div>  
              <div class="row">  
                <div class="col-6">  
                  <button type="submit" class="btn btn-primary px-4">Login</button>  
                </div>  
                <div class="col-6 text-right">  
                  <button type="button" class="btn btn-link px-0">Forgot password?</button>  
                </div>  
              </div>  

            </form>  
          </div>  
        </div>  
      </div>  
    </div>  
  </div>  
</div>  
Step 15

Open login.componet.html and add this HTML.

import { Component, OnInit } from '@angular/core';    
import { Router } from '@angular/router';    
import { LoginService } from '../login.service';    
 import { FormsModule } from '@angular/forms';    

@Component({    
  selector: 'app-login',    
  templateUrl: './login.component.html',    
  styleUrls: ['./login.component.css']    
})    
export class LoginComponent {    

  model : any={};    

  errorMessage:string;    
  constructor(private router:Router,private LoginService:LoginService) { }    

  ngOnInit() {    
    sessionStorage.removeItem('UserName');    
    sessionStorage.clear();    
  }    
  login(){    
    debugger;    
    this.LoginService.Login(this.model).subscribe(    
      data => {    
        debugger;    
        if(data.Status=="Success")    
        {       
          this.router.navigate(['/Dashboard']);    
          debugger;    
        }    
        else{    
          this.errorMessage = data.Message;    
        }    
      },    
      error => {    
        this.errorMessage = error.message;    
      });    
  };    
 }    

Open login.componet.ts and add following code.

<div>  
  <div class="row">  
    <div class="col-sm-12 btn btn-primary">  
        Welcome to DashBoard  
    </div>  
  </div>  
</div>  
Step 16

Now, open dashboard.component.html and add the following lines.

import { NgModule } from '@angular/core';    
import { Routes, RouterModule } from '@angular/router';    
import { DashboardComponent } from './dashboard/dashboard.component';    
import { LoginComponent } from './login/login.component';    
import { RegisterComponent } from './register/register.component';    

export const routes: Routes = [    
  {    
    path: '',    
    redirectTo: 'login',    
    pathMatch: 'full',    
  },    
  {    
    path: 'login',    
    component: LoginComponent,    
    data: {    
      title: 'Login Page'    
    }    
  },    
  {    
    path: 'Dasboard',    
    component: DashboardComponent,    
    data: {    
      title: 'Dashboard Page'    
    }    
  },    
  {    
    path: 'AddUser',    
    component: RegisterComponent,    
    data: {    
      title: 'Add User Page'    
    }    
  },    
];    

@NgModule({    
  imports: [RouterModule.forRoot(routes)],    
  exports: [RouterModule]    
})    
export class AppRoutingModule { } 
Step 17

Now, open app-routing.module.ts file and add the following lines to create routing

import { NgModule } from '@angular/core'; 
import { Routes, RouterModule } from '@angular/router'; 
import { DashboardComponent } from './dashboard/dashboard.component'; 
import { LoginComponent } from './login/login.component'; 
import { RegisterComponent } from './register/register.component'; 

export const routes: Routes = [ 
  { path: '', redirectTo: 'login', pathMatch: 'full', }, 
  { path: 'login', component: LoginComponent, data: { title: 'Login Page' } }, 
  { path: 'Dasboard', component: DashboardComponent, data: { title: 'Dashboard Page' } }, 
  { path: 'AddUser', component: RegisterComponent, data: { title: 'Add User Page' } }, 
]; 

@NgModule({ 
  imports: [RouterModule.forRoot(routes)], 
  exports: [RouterModule] 
}) 

export class AppRoutingModule { } 
Step 18

Now, let us run the project and redirect the URL to the "Add User" page.

Create Registration And Login Page Using Angular 7 And Web API

Enter the details and click on the "Add User" button.

Step 19

Now, run the project's default URL which takes us to the login page. Enter the username and password and click "Login".

Create Registration And Login Page Using Angular 7 And Web API

The following Page will be displayed.

Create Registration And Login Page Using Angular 7 And Web API

You may also like: Angular vs React vs Vue: Which one will be popular in 2020.

Summary

In this article, we discussed the process of Login and Registration page creation in an application with Angular 8 and Web API.

Thank you for reading ! If you enjoyed this article, please share it with others who may enjoy it as well.!

ASP.NET Core 3.0 - JWT Authentication Tutorial with Example API

ASP.NET Core 3.0 - JWT Authentication Tutorial with Example API

In this tutorial we'll go through a simple example of how to implement JWT (JSON Web Token) authentication in an ASP.NET Core 3.0 API with C#.

In this tutorial we'll go through a simple example of how to implement JWT (JSON Web Token) authentication in an ASP.NET Core 3.0 API with C#.

The example API has just two endpoints/routes to demonstrate authenticating with JWT and accessing a restricted route with JWT:

  • /users/authenticate - public route that accepts HTTP POST requests containing the username and password in the body. If the username and password are correct then a JWT authentication token and the user details are returned.
  • /users - secure route that 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.

The tutorial project is available on GitHub at https://github.com/cornflourblue/aspnet-core-3-jwt-authentication-api.

Tutorial Contents

  • Tools required to develop ASP.NET Core 3.0 applications
  • Running the example API locally
  • Testing the ASP.NET Core API with Postman
  • Running an Angular 8 app with the ASP.NET Core API
  • Running a React app with the ASP.NET Core API
  • Running a Vue.js app with the ASP.NET Core API
  • ASP.NET Core JWT API project structure
Tools required to run the ASP.NET Core 3.0 JWT Example Locally

To develop and run ASP.NET Core applications locally, download and install the following:

  • .NET Core SDK - includes the .NET Core runtime and command line tools
  • Visual Studio Code - code editor that runs on Windows, Mac and Linux
  • C# extension for Visual Studio Code - adds support to VS Code for developing .NET Core applications
Running the ASP.NET Core JWT Authentication API Locally
  1. Download or clone the tutorial project code from https://github.com/cornflourblue/aspnet-core-3-jwt-authentication-api
  2. Start the api by running dotnet run from the command line in the project root folder (where the WebApi.csproj file is located), you should see the message Now listening on: http://localhost:4000. Follow the instructions below to test with Postman or hook up with one of the example single page applications available (Angular, React or Vue).

NOTE: You can also start the application in debug mode in VS Code by opening the project root folder in VS Code and pressing F5 or by selecting Debug -> Start Debugging from the top menu. Running in debug mode allows you to attach breakpoints to pause execution and step through the application code.

Testing the ASP.NET Core JWT Auth API with Postman

Postman is a great tool for testing APIs, you can download it at https://www.getpostman.com/.

Below are instructions on how to use Postman to authenticate a user to get a JWT token from the api, and then make an authenticated request with the JWT token to retrieve a list of users from the api.

How to authenticate a user with Postman

To authenticate a user with the api and get a JWT token follow these steps:

  1. Open a new request tab by clicking the plus (+) button at the end of the tabs.

  2. Change the http request method to "POST" with the dropdown selector on the left of the URL input field.

  3. In the URL field enter the address to the authenticate route of your local API - http://localhost:4000/users/authenticate.

  4. 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)".

  5. Enter a JSON object containing the test username and password in the "Body" textarea:

    {
        "username": "test",
        "password": "test"
    }
    
  6. 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.

Here's a screenshot of Postman after the request is sent and the user has been authenticated:

This is image title

This is image title

How to make an authenticated request to retrieve all users

To make an authenticated request using the JWT token from the previous step, follow these steps:

  1. Open a new request tab by clicking the plus (+) button at the end of the tabs.
  2. Change the http request method to "GET" with the dropdown selector on the left of the URL input field.
  3. In the URL field enter the address to the users route of your local API - http://localhost:4000/users.
  4. Select the "Authorization" tab below the URL field, change the type to "Bearer Token" in the type dropdown selector, and paste the JWT token from the previous authenticate step into the "Token" field.
  5. Click the "Send" button, you should receive a "200 OK" response containing a JSON array with all the user records in the system (just the one test user in the example).

Here's a screenshot of Postman after making an authenticated request to get all users:

This is image title

This is image title

Running an Angular 8 client app with the ASP.NET Core JWT Auth API

For full details about the example Angular 8 application see the post Angular 8 - JWT Authentication Example & Tutorial. But to get up and running quickly just follow the below steps.

  1. Download or clone the Angular 8 tutorial code from https://github.com/cornflourblue/angular-8-jwt-authentication-example
  2. Install all required npm packages by running npm install from the command line in the project root folder (where the package.json is located).
  3. Remove or comment out the line below the comment // provider used to create fake backend located in the /src/app/app.module.ts file.
  4. Start the application by running npm start from the command line in the project root folder, this will launch a browser displaying the Angular example application and it should be hooked up with the ASP.NET Core JWT Auth API that you already have running.
Running a React client app with the ASP.NET Core JWT Auth API

For full details about the example React application see the post React - JWT Authentication Tutorial & Example. But to get up and running quickly just follow the below steps.

  1. Download or clone the React tutorial code from https://github.com/cornflourblue/react-jwt-authentication-example
  2. Install all required npm packages by running npm install from the command line in the project root folder (where the package.json is located).
  3. Remove or comment out the 2 lines below the comment // setup fake backend located in the /src/index.jsx file.
  4. Start the application by running npm start from the command line in the project root folder, this will launch a browser displaying the React example application and it should be hooked up with the ASP.NET Core JWT Auth API that you already have running.
Running a Vue.js client app with the ASP.NET Core JWT Auth API

For full details about the example VueJS JWT application see the post Vue.js + Vuex - JWT Authentication Tutorial & Example. But to get up and running quickly just follow the below steps.

  1. Download or clone the VueJS tutorial code from https://github.com/cornflourblue/vue-vuex-jwt-authentication-example
  2. Install all required npm packages by running npm install from the command line in the project root folder (where the package.json is located).
  3. Remove or comment out the 2 lines below the comment // setup fake backend located in the /src/index.js file.
  4. Start the application by running npm start from the command line in the project root folder, this will launch a browser displaying the VueJS example application and it should be hooked up with the ASP.NET Core JWT Auth API that you already have running.
ASP.NET Core JWT Authentication Project Structure

The tutorial project is organised into the following folders:
Controllers - define the end points / routes for the web api, controllers are the entry point into the web api from client applications via http requests.
Models - represent request and response models for controller methods, request models define the parameters for incoming requests, and response models can be used to define what data is returned.
Services - contain business logic, validation and data access code.
Entities - represent the application data.
Helpers - anything that doesn't fit into the above folders.

ASP.NET Core JWT Users Controller
**Path: /Controllers/UsersController.cs**

The ASP.NET Core users controller defines and handles all routes / endpoints for the api that relate to users, this includes authentication and standard CRUD operations. Within each route the controller calls the user service to perform the action required, this enables the controller to stay 'lean' and completely separated from the business logic and data access code.

The controller actions are secured with JWT using the [Authorize] attribute, with the exception of the Authenticate method which allows public access by overriding the [Authorize] attribute on the controller with [AllowAnonymous] attribute on the action method. I chose this approach so any new action methods added to the controller will be secure by default unless explicitly made public.

using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Authorization;
using WebApi.Services;
using WebApi.Models;
using System.Linq;

namespace WebApi.Controllers
{
    [Authorize]
    [ApiController]
    [Route("[controller]")]
    public class UsersController : ControllerBase
    {
        private IUserService _userService;

        public UsersController(IUserService userService)
        {
            _userService = userService;
        }

        [AllowAnonymous]
        [HttpPost("authenticate")]
        public IActionResult Authenticate([FromBody]AuthenticateModel model)
        {
            var user = _userService.Authenticate(model.Username, model.Password);

            if (user == null)
                return BadRequest(new { message = "Username or password is incorrect" });

            return Ok(user);
        }

        [HttpGet]
        public IActionResult GetAll()
        {
            var users = _userService.GetAll();
            return Ok(users);
        }
    }
}
ASP.NET Core JWT User Entity
**Path: /Entities/User.cs**

The user entity class represents the data for a user in the application. Entity classes are used to pass data between different parts of the application (e.g. between services and controllers) and can be used to return http response data from controller action methods. If multiple types of entities or other custom data is required to be returned from a controller method then a custom model class should be created in the Models folder for the response.

namespace WebApi.Entities
{
    public class User
    {
        public int Id { get; set; }
        public string FirstName { get; set; }
        public string LastName { get; set; }
        public string Username { get; set; }
        public string Password { get; set; }
        public string Token { get; set; }
    }
}
ASP.NET Core JWT App Settings
**Path: /Helpers/AppSettings.cs**

The app settings class contains properties defined in the appsettings.json file and is used for accessing application settings via objects that are injected into classes using the ASP.NET Core built in dependency injection (DI) system. For example the User Service accesses app settings via an IOptions<AppSettings> appSettings object that is injected into the constructor.

Mapping of configuration sections to classes is done in the ConfigureServices method of the Startup.cs file.

namespace WebApi.Helpers
{
    public class AppSettings
    {
        public string Secret { get; set; }
    }
}
ASP.NET Core JWT Extension Methods
**Path: /Helpers/ExtensionMethods.cs**

Extension methods are used to add convenience methods and extra functionality to existing types in C#.

The extension methods class adds a couple of simple convenience methods for removing passwords from User instances and IEnumerable<User> collections. These methods are called by the Authenticate and GetAll methods in the UserService to ensure the user objects returned don't include passwords.

using System.Collections.Generic;
using System.Linq;
using WebApi.Entities;

namespace WebApi.Helpers
{
    public static class ExtensionMethods
    {
        public static IEnumerable<User> WithoutPasswords(this IEnumerable<User> users) {
            return users.Select(x => x.WithoutPassword());
        }

        public static User WithoutPassword(this User user) {
            user.Password = null;
            return user;
        }
    }
}
ASP.NET Core JWT Authenticate Model
**Path: /Models/AuthenticateModel.cs**

The authenticate model defines the parameters for incoming requests to the /users/authenticate route of the api, because it is set as the parameter to the Authenticate method of the UsersController. When an HTTP POST request is received to the route, the data from the body is bound to an instance of the AuthenticateModel, validated and passed to the method.

ASP.NET Core Data Annotations are used to automatically handle model validation, the [Required] attribute sets both the username and password as required fields so if either are missing a validation error message is returned from the api.

using System.ComponentModel.DataAnnotations;

namespace WebApi.Models
{
    public class AuthenticateModel
    {
        [Required]
        public string Username { get; set; }

        [Required]
        public string Password { get; set; }
    }
}
[Back to top](#projectstructure)
 
ASP.NET Core JWT User Service
**Path: /Services/UserService.cs**

The user service contains a method for authenticating user credentials and returning a JWT token, and a method for getting all users in the application.

I hardcoded the array of users in the example to keep it focused on JWT authentication, in a production application it is recommended to store user records in a database with hashed passwords. For an extended example that includes support for user registration and stores data with Entity Framework Core check out ASP.NET Core 2.2 - Simple API for Authentication, Registration and User Management.

The top of the file contains an interface that defines the user service, below that is the concrete user service class that implements the interface.

On successful authentication the Authenticate method generates a JWT (JSON Web Token) using the JwtSecurityTokenHandler class which generates a token that is digitally signed using a secret key stored in appsettings.json. The JWT token is returned to the client application which must include it in the HTTP Authorization header of subsequent requests to secure routes.

using System;
using System.Collections.Generic;
using System.IdentityModel.Tokens.Jwt;
using System.Linq;
using System.Security.Claims;
using System.Text;
using Microsoft.Extensions.Options;
using Microsoft.IdentityModel.Tokens;
using WebApi.Entities;
using WebApi.Helpers;

namespace WebApi.Services
{
    public interface IUserService
    {
        User Authenticate(string username, string password);
        IEnumerable<User> GetAll();
    }

    public class UserService : IUserService
    {
        // users hardcoded for simplicity, store in a db with hashed passwords in production applications
        private List<User> _users = new List<User>
        { 
            new User { Id = 1, FirstName = "Test", LastName = "User", Username = "test", Password = "test" } 
        };

        private readonly AppSettings _appSettings;

        public UserService(IOptions<AppSettings> appSettings)
        {
            _appSettings = appSettings.Value;
        }

        public User Authenticate(string username, string password)
        {
            var user = _users.SingleOrDefault(x => x.Username == username && x.Password == password);

            // return null if user not found
            if (user == null)
                return null;

            // authentication successful so generate jwt token
            var tokenHandler = new JwtSecurityTokenHandler();
            var key = Encoding.ASCII.GetBytes(_appSettings.Secret);
            var tokenDescriptor = new SecurityTokenDescriptor
            {
                Subject = new ClaimsIdentity(new Claim[] 
                {
                    new Claim(ClaimTypes.Name, user.Id.ToString())
                }),
                Expires = DateTime.UtcNow.AddDays(7),
                SigningCredentials = new SigningCredentials(new SymmetricSecurityKey(key), SecurityAlgorithms.HmacSha256Signature)
            };
            var token = tokenHandler.CreateToken(tokenDescriptor);
            user.Token = tokenHandler.WriteToken(token);

            return user.WithoutPassword();
        }

        public IEnumerable<User> GetAll()
        {
            return _users.WithoutPasswords();
        }
    }
}
ASP.NET Core JWT App Settings (Development)
**Path: /appsettings.Development.json**

Configuration file with application settings that are specific to the development environment.

{
  "Logging": {
    "LogLevel": {
      "Default": "Debug",
      "System": "Information",
      "Microsoft": "Information"
    }
  }
}
ASP.NET Core JWT App Settings
**Path: /appsettings.json**

Root configuration file containing application settings for all environments.

IMPORTANT: The "Secret" property is used by the api to sign and verify JWT tokens for authentication, update it with your own random string to ensure nobody else can generate a JWT to gain unauthorised access to your application.

{
  "AppSettings": {
    "Secret": "THIS IS USED TO SIGN AND VERIFY JWT TOKENS, REPLACE IT WITH YOUR OWN SECRET, IT CAN BE ANY STRING"
  },
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft": "Warning",
      "Microsoft.Hosting.Lifetime": "Information"
    }
  },
  "AllowedHosts": "*"
}
ASP.NET Core JWT Program
**Path: /Program.cs**

The program class is a console app that is the main entry point to start the application, it configures and launches the web api host and web server using an instance of IHostBuilder. ASP.NET Core applications require a host in which to execute.

Kestrel is the web server used in the example, it's a new cross-platform web server for ASP.NET Core that's included in new project templates by default. Kestrel is fine to use on it's own for internal applications and development, but for public facing websites and applications it should sit behind a more mature reverse proxy server (IIS, Apache, Nginx etc) that will receive HTTP requests from the internet and forward them to Kestrel after initial handling and security checks.

using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Hosting;

namespace WebApi
{
    public class Program
    {
        public static void Main(string[] args)
        {
            CreateHostBuilder(args).Build().Run();
        }

        public static IHostBuilder CreateHostBuilder(string[] args) =>
            Host.CreateDefaultBuilder(args)
                .ConfigureWebHostDefaults(webBuilder =>
                {
                    webBuilder.UseStartup<Startup>()
                        .UseUrls("http://localhost:4000");
                });
    }
}
ASP.NET Core JWT Startup
**Path: /Startup.cs**

The startup class configures the request pipeline of the application and how all requests are handled.

using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using WebApi.Helpers;
using WebApi.Services;
using Microsoft.IdentityModel.Tokens;
using System.Text;
using Microsoft.AspNetCore.Authentication.JwtBearer;

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

        public IConfiguration Configuration { get; }

        // This method gets called by the runtime. Use this method to add services to the container.
        public void ConfigureServices(IServiceCollection services)
        {
            services.AddCors();
            services.AddControllers();

            // configure strongly typed settings objects
            var appSettingsSection = Configuration.GetSection("AppSettings");
            services.Configure<AppSettings>(appSettingsSection);

            // configure jwt authentication
            var appSettings = appSettingsSection.Get<AppSettings>();
            var key = Encoding.ASCII.GetBytes(appSettings.Secret);
            services.AddAuthentication(x =>
            {
                x.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
                x.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
            })
            .AddJwtBearer(x =>
            {
                x.RequireHttpsMetadata = false;
                x.SaveToken = true;
                x.TokenValidationParameters = new TokenValidationParameters
                {
                    ValidateIssuerSigningKey = true,
                    IssuerSigningKey = new SymmetricSecurityKey(key),
                    ValidateIssuer = false,
                    ValidateAudience = false
                };
            });

            // configure DI for application services
            services.AddScoped<IUserService, UserService>();
        }

        // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
        public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
        {
            app.UseRouting();

            // global cors policy
            app.UseCors(x => x
                .AllowAnyOrigin()
                .AllowAnyMethod()
                .AllowAnyHeader());

            app.UseAuthentication();
            app.UseAuthorization();

            app.UseEndpoints(endpoints => {
                endpoints.MapControllers();
            });
        }
    }
}
ASP.NET Core JWT Web Api csproj
**Path: /WebApi.csproj**

The csproj (C# project) is an MSBuild based file that contains target framework and NuGet package dependency information for the application.

<Project Sdk="Microsoft.NET.Sdk.Web">
  <PropertyGroup>
    <TargetFramework>netcoreapp3.0</TargetFramework>
  </PropertyGroup>
  <ItemGroup>
    <PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="3.0.0" />
    <PackageReference Include="System.IdentityModel.Tokens.Jwt" Version="5.5.0" />
  </ItemGroup>
</Project>
Thank for reading! Please share if you liked it!