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.

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.

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

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

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.

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

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.

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.

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.

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.

ASP Net Core, SQL Server, and Angular 7: Web App Authentication

ASP Net Core, SQL Server, and Angular 7: Web App Authentication

The comprehensive step by step tutorial on building Web Application Authentication using ASP.NET Core Web API, Microsoft SQL Server, and Angular 7

Originally published by Didin J at djamware.com

The comprehensive step by step tutorial on building Web Application Authentication using ASP.NET Core Web API, Microsoft SQL Server, and Angular 7. We will create our own Microsoft SQL Server Database and Tables (User and Book). Password in the User table will be encrypted using salted HMACSHA512. The authentication flow describes a sequence diagram below.

Table of contents


  • Create Microsoft SQL Server Database and Tables
  • Create and Configure a new ASP.NET Core Web API Application
  • Generate Models and Context from Microsoft SQL Server Database
  • Create DTO (Data Transfer Object) for Request Body and Response
  • Create Helpers Class for Mapping DTO with Model Classes
  • Create Controller for Books Data
  • Create a Repository for Authentication
  • Create Controller for Authentication
  • Test Secure API using Postman
  • Install or Update Angular 7 CLI and Create Application
  • Add Routes for Navigation between Angular Pages/Component
  • Create a custom Angular 7 HttpInterceptor
  • Create Services for Accessing Book and Authentication API
  • Display List of Book using Angular 7 Material
  • Create a Login and Register Page
  • Run and Test the ASP Net Core, SQL Server, and Angular 7: Web App Authentication

The book API is secure, so only authorized user can access that endpoint otherwise it will return 401 (Unauthorized) error and redirect the user to the login page. Next, the user will log in using email and password then after successful login (credentials validated successfully), it will response success status with JWT token. JWT token will be used to access book endpoint as Authorization headers. So, the token should be store in Angular 7 app and all access to book API securely and seamlessly using Angular 7 Http Interceptors.

The following tools, frameworks, package, and modules are required for this tutorial:

  1. ASP.NET Core SDK
  2. Visual Studio Code
  3. Node.js
  4. Angular 7
  5. SQL Server 2017 Express
  6. Postman
  7. Command prompt (CMD)

We assume that you already install all above required tools. Now, we have to check that DotNet SDK already installed and added to the path. Open command prompt then type this command to make sure DotNet installed and runnable via command prompt.

dotnet --version

You will get this result.

2.1.403

We are using the DotNet Framework SDK version 2.1.403. That's mean you're ready to move to the main steps.

Create Microsoft SQL Server Database and Tables

We will create a Database for this web application with User and Book tables. For that, open Microsoft SQL Server Management Studio then connects to your local SQL Server (we are using SQL Express 2017). Right-click Database on the left pane then clicks New Database menu.

Fill Database Name (we name it "Book Store"), leave owner as default because we will use sa user then click OK button. Next, expand the BookStore Database then right-click tables -> table. Fill the table as below then save as `TblUser`.

Or simply just run this SQL commands.

USE [BookStore]
GO

SET ANSI_NULLS ON
GO

SET QUOTED_IDENTIFIER ON
GO

CREATE TABLE [dbo].[TblUser](
    [UserID] [int] IDENTITY(1,1) NOT NULL,
    [FullName] varchar NULL,
    [Email] varchar NULL,
    [Password] varbinary NULL,
    [Salt] varbinary NULL,
 CONSTRAINT [PK_TblUser] 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

Next, create a Book table using these SQL commands.

USE [BookStore]
GO

SET ANSI_NULLS ON
GO

SET QUOTED_IDENTIFIER ON
GO

CREATE TABLE [dbo].[TblBook](
    [BookID] [int] IDENTITY(1,1) NOT NULL,
    [ISBN] varchar NULL,
    [Title] varchar NULL,
    [Author] varchar NULL,
    [Description] varchar NULL,
    [Publisher] varchar NULL,
    [PublishedYear] [int] NULL,
    [Price] [decimal](18, 0) NULL,
 CONSTRAINT [PK_TblBook] PRIMARY KEY CLUSTERED
(
    [BookID] 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

Create and Configure a new ASP.NET Core Web API Application

A slightly different ASP.NET Core application creation, we will use the command prompt. Of course, you can use the more easiest way when using Microsoft Visual Studio. In the command prompt go to your projects folder then type this command.

dotnet  new webapi –o AspNetAngularAuth –n AspNetAngularAuth

You will the output like below in the Command Prompt.

The template "ASP.NET Core Web API" was created successfully.

Processing post-creation actions...
Running 'dotnet restore' on AspNetAngularAuth\AspNetAngularAuth.csproj...
  Restoring packages for C:\Users\DIDIN\Projects\AspNetAngularAuth\AspNetAngularAuth.csproj...
  Generating MSBuild file C:\Users\DIDIN\Projects\AspNetAngularAuth\obj\AspNetAngularAuth.csproj.nuget.g.props.
  Generating MSBuild file C:\Users\DIDIN\Projects\AspNetAngularAuth\obj\AspNetAngularAuth.csproj.nuget.g.targets.
  Restore completed in 5.8 sec for C:\Users\DIDIN\Projects\AspNetAngularAuth\AspNetAngularAuth.csproj.

Restore succeeded.

That's mean, you can open directly as a folder from Visual Studio Code as well as CSharp Project/Solution from Microsoft Visual Studio. Or you can call this new ASP.NET Core Web API Project by type this command.

cd AspNetAngularAuth
code .

The project will be opened by Visual Studio Code. Next, open terminal from the menu or press Ctrl+Shift+. Run these commands to installs all required packages.</p><pre class="ql-syntax" spellcheck="false">dotnet add package Microsoft.EntityFrameworkCore.Tools -v 2.1.2 dotnet add package Microsoft.EntityFrameworkCore.SqlServer -v 2.1.2 dotnet add package Microsoft.EntityFrameworkCore.SqlServer.Design -v 1.1.6 dotnet add package Microsoft.VisualStudio.Web.CodeGeneration.Design -v 2.1.5 dotnet add package Microsoft.VisualStudio.Web.CodeGeneration.Tools -v 2.0.4 dotnet add package AutoMapper.Extensions.Microsoft.DependencyInjection -v 5.0.1 </pre><p>If you see a notification like below, just click Restore button.</p><p><img src="https://s3-ap-southeast-1.amazonaws.com/djamblog/article-270119063810.png"></p><p>Now, you will have these packages with the right version installed shown in <code>AspNetAngularAuth.csproj</code> file.</p><pre class="ql-syntax" spellcheck="false"> &lt;ItemGroup&gt; &nbsp; &lt;PackageReference Include="AutoMapper.Extensions.Microsoft.DependencyInjection" Version="5.0.1" /&gt; &nbsp; &lt;PackageReference Include="Microsoft.AspNetCore.App" /&gt; &nbsp; &lt;PackageReference Include="Microsoft.AspNetCore.Razor.Design" Version="2.1.2" PrivateAssets="All" /&gt; &nbsp; &lt;PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer" Version="2.1.2" /&gt; &nbsp; &lt;PackageReference Include="Microsoft.EntityFrameworkCore.SqlServer.Design" Version="1.1.6" /&gt; &nbsp; &lt;PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="2.1.2"&gt; &nbsp; &nbsp; &lt;IncludeAssets&gt;runtime; build; native; contentfiles; analyzers&lt;/IncludeAssets&gt; &nbsp; &nbsp; &lt;PrivateAssets&gt;all&lt;/PrivateAssets&gt; &nbsp; &lt;/PackageReference&gt; &nbsp; &lt;PackageReference Include="Microsoft.VisualStudio.Web.CodeGeneration.Design" Version="2.1.5" /&gt; &nbsp; &lt;PackageReference Include="Microsoft.VisualStudio.Web.CodeGeneration.Tools" Version="2.0.4" /&gt; &lt;/ItemGroup&gt; </pre><p>Next, build the DotNet application to make sure there's no error in package dependencies.</p><pre class="ql-syntax" spellcheck="false">dotnet build </pre><p>You must see this output when everything on the right path.</p><pre class="ql-syntax" spellcheck="false">Build succeeded. &nbsp; &nbsp; 0 Warning(s) &nbsp; &nbsp; 0 Error(s) </pre><p>Next, we have to configure connections to Microsoft SQL Server Database. First, open and edit <code>appsettings.json</code> then add these lines before loggingJSON object.</p><pre class="ql-syntax" spellcheck="false"> "ConnectionStrings": { &nbsp; "SQLConnection": "Server=.;Database=BookStore;Trusted_Connection=True;User Id=sa;Password=q;Integrated Security=false;MultipleActiveResultSets=true" }, </pre><p>Add this configuration for Token secret.</p><pre class="ql-syntax" spellcheck="false">"AppSettings": { &nbsp;&nbsp; &nbsp;"Token": "MySecretTokenForJwt" }, </pre><p>Open and editStartup.csthen add this line insideConfigureServicesbracket.</p><pre class="ql-syntax" spellcheck="false">services.AddDbContext&lt;BookStoreContext&gt;(options =&gt; options.UseSqlServer(Configuration.GetConnectionString("SQLConnection"))); </pre><p>Don't worry <code>BookStoreContext</code> will be added later when generate context and data models. For now, you can comment out this line then uncomment after Models and Context generation and set the imports to it. Next, add this line to enable CORS after the above line.</p><pre class="ql-syntax" spellcheck="false"> services.AddCors(); </pre><p>Next, add these lines to configure JWT Authentication token.</p><pre class="ql-syntax" spellcheck="false">services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme) &nbsp; .AddJwtBearer(options =&gt; { &nbsp; &nbsp; &nbsp; options.TokenValidationParameters = new TokenValidationParameters &nbsp; &nbsp; &nbsp; { &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ValidateIssuerSigningKey = true, &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; IssuerSigningKey = new SymmetricSecurityKey(Encoding.ASCII &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; .GetBytes(Configuration.GetSection("AppSettings:Token").Value)), &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ValidateIssuer = false, &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; ValidateAudience = false &nbsp; &nbsp; &nbsp; }; &nbsp; }); </pre><p>Also, add these lines inside <code>Configure</code> bracket.</p><pre class="ql-syntax" spellcheck="false"> app.UseCors(x =&gt; x.AllowAnyOrigin().AllowAnyHeader().AllowAnyMethod()); app.UseAuthentication(); </pre><p>Don't forget to import the library or module that added in the Configuration.</p><h2><br></h2><h2><strong>Generate Models and Context from Microsoft SQL Server Database</strong></h2><p>We will use the Code Generation Tools package to generate all models that represent all tables in theBookStoreDatabase including theBookStoreContext. Run this command to generate the models and their context.</p><pre class="ql-syntax" spellcheck="false">dotnet ef dbcontext scaffold "Server=.;Database=BookStore;Trusted_Connection=True;User Id=sa;Password=q;Integrated Security=false;" Microsoft.EntityFrameworkCore.SqlServer -o Models </pre><p>You will see the generated Models and Context inside the Models folder.</p><p><img src="https://s3-ap-southeast-1.amazonaws.com/djamblog/article-270419111940.png"></p><p>Remove unused lines (without commenting out) to clear the error in BookStoreContext. If you're not using Models and Context generator, the contents of Models/TblUser.cs` looks like these.

using System;
using System.Collections.Generic;

namespace AspNetAngularAuth.Models
{
    public partial class TblUser
    {
        public int UserId { get; set; }
        public string FullName { get; set; }
        public string Email { get; set; }
        public byte[] Password { get; set; }
        public byte[] Salt { get; set; }
    }
}

The Models/TblBook.cs look like these.

using System;
using System.Collections.Generic;

namespace AspNetAngularAuth.Models
{
    public partial class TblBook
    {
        public int BookId { get; set; }
        public string Isbn { get; set; }
        public string Title { get; set; }
        public string Author { get; set; }
        public string Description { get; set; }
        public string Publisher { get; set; }
        public int? PublishedYear { get; set; }
        public decimal? Price { get; set; }
    }
}

And the Models/BookStoreContext.cs looks like these.

using System;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Metadata;

namespace AspNetAngularAuth.Models
{
    public partial class BookStoreContext : DbContext
    {
        public BookStoreContext()
        {
        }

        public BookStoreContext(DbContextOptions<BookStoreContext> options)
            : base(options)
        {
        }

        public virtual DbSet<TblBook> TblBook { get; set; }
        public virtual DbSet<TblUser> TblUser { get; set; }

        protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
        {
            if (!optionsBuilder.IsConfigured)
            {
               optionsBuilder.UseSqlServer("Server=.;Database=BookStore;Trusted_Connection=True;User Id=sa;Password=q;Integrated Security=false;");
            }
        }

        protected override void OnModelCreating(ModelBuilder modelBuilder)
        {
            modelBuilder.Entity<TblBook>(entity =>
            {
                entity.HasKey(e => e.BookId);

                entity.Property(e => e.BookId).HasColumnName("BookID");

                entity.Property(e => e.Author)
                    .HasMaxLength(50)
                    .IsUnicode(false);

                entity.Property(e => e.Description)
                    .HasMaxLength(200)
                    .IsUnicode(false);

                entity.Property(e => e.Isbn)
                    .HasColumnName("ISBN")
                    .HasMaxLength(50)
                    .IsUnicode(false);

                entity.Property(e => e.Price).HasColumnType("decimal(18, 0)");

                entity.Property(e => e.Publisher)
                    .HasMaxLength(50)
                    .IsUnicode(false);

                entity.Property(e => e.Title)
                    .HasMaxLength(100)
                    .IsUnicode(false);
            });

            modelBuilder.Entity<TblUser>(entity =>
            {
                entity.HasKey(e => e.UserId);

                entity.Property(e => e.UserId).HasColumnName("UserID");

                entity.Property(e => e.Email)
                    .HasMaxLength(50)
                    .IsUnicode(false);

                entity.Property(e => e.FullName)
                    .HasMaxLength(50)
                    .IsUnicode(false);

                entity.Property(e => e.Password).HasMaxLength(128);

                entity.Property(e => e.Salt).HasMaxLength(128);
            });
        }
    }
}

Create DTO (Data Transfer Object) for Request Body and Response

To specify the request body and response fields, we will use a Data Transfer Object (DTO). For that, create a new DTOs folder and BookListDto.cs, LoginDto.cs, RegisterDto.cs files inside that folder. Next, open and edit Dtos/LoginDto.cs then replace all CSharp codes with these.

using System.ComponentModel.DataAnnotations;

namespace AspNetAngularAuth.Dtos
{
    public class LoginDto
    {
        [Required]
        public string Email { get; set; }
        [Required]
        public string Password { get; set; }
    }
}

Next, open and edit Dtos/RegisterDto.cs then replace all CSharp codes with these.

using System.ComponentModel.DataAnnotations;

namespace AspNetAngularAuth.Dtos
{
    public class RegisterDto
    {
        [Required]
        [StringLength(50, MinimumLength = 3, ErrorMessage = "Email must be at least 3 characters")]
        public string FullName { get; set; }
        [Required]
        [StringLength(50, MinimumLength = 3, ErrorMessage = "Email must be at least 3 characters")]
        public string Email { get; set; }
        [Required]
        [StringLength(64, MinimumLength = 8, ErrorMessage = "You must provide password between 8 and 20 characters")]
        public string Password { get; set; }
    }
}


Create Helpers Class for Mapping DTO with Model Classes

To create a helper for mapping DTO to Model classes, create the folder Helpers in the root of the project folder then create a file AutoMapperProfile.cs inside that new folder. Open and edit this new file then replace all codes with this.

using AspNetAngularAuth.Dtos;
using AspNetAngularAuth.Models;
using AutoMapper;

namespace AspNetAngularAuth.Helpers
{
    public class AutoMapperProfile: Profile
    {
        public AutoMapperProfile()
        {
            CreateMap<TblBook, BookListDto>();
            CreateMap<LoginDto, TblUser>();
            CreateMap<RegisterDto, TblUser>();
        }
    }
}

Next, open and edit again Startup.cs then add this line inside ConfigureServices.

services.AddAutoMapper();

Don't forget to auto import the library in ConfigureServices.


Create Controller for Books Data

To get a list of the book using API, we have to create a CSharp file Controllers/BookController.cs. Open and edit Controllers/BookController.cs then replace all CSharp codes with these.

using System.Threading.Tasks;
using AspNetAngularAuth.Models;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;

namespace AspNetAngularAuth.Controllers
{
    [Authorize]
    [Route("api/[controller]")]
    [ApiController]
    public class BookController: ControllerBase
    {
        private readonly BookStoreContext _context;
        public BookController(BookStoreContext context)
        {
            _context = context;
        }

        [HttpGet]
        public async Task<IActionResult> GetBooks()
        {
            var data = await _context.TblBook.ToListAsync();
            return Ok(data);
        }
    }
}

There's an [Authorized] annotation which means this API resource is secured. So, only authorized user can access this API endpoint.

Create a Repository for Authentication

Before creating a file for Authentication repository, we have to create a repositories folder first with the name Repositories in the root of the project folder. Next, create a file with the name Repositories/AuthRepository.cs. Open and edit that file then replace all CSharp codes with these.

using System.Threading.Tasks;
using AspNetAngularAuth.Models;
using Microsoft.EntityFrameworkCore;

namespace AspNetAngularAuth.Repositories
{
    public class AuthRepository: IAuthRepository
    {
        private readonly BookStoreContext _context;

        public AuthRepository(BookStoreContext context)
        {
            _context = context;
        }

        public async Task<TblUser> Login(string email, string password)
        {
            var user = await _context.TblUser.FirstOrDefaultAsync(x => x.Email == email);
            if (user == null)
                return null;

            if (!VerifyPasswordHash(password, user.Password, user.Salt))
                return null;

            return user; // auth successful
        }

        public async Task<TblUser> Register(TblUser user, string password)
        {
            byte[] passwordHash, salt;
            CreatePasswordHash(password, out passwordHash, out salt);
            user.Password = passwordHash;
            user.Salt = salt;

            await _context.TblUser.AddAsync(user);
            await _context.SaveChangesAsync();

            return user;
        }

        private bool VerifyPasswordHash(string password, byte[] passwordHash, byte[] salt)
        {
            using (var hmac = new System.Security.Cryptography.HMACSHA512(salt))
            {
                var computedHash = hmac.ComputeHash(System.Text.Encoding.UTF8.GetBytes(password));
                for (int i = 0; i < computedHash.Length; i++)
                {
                    if (computedHash[i] != passwordHash[i]) return false;
                }
            }
            return true;
        }

        private void CreatePasswordHash(string password, out byte[] passwordHash, out byte[] salt)
        {
            using (var hmac = new System.Security.Cryptography.HMACSHA512())
            {
                salt = hmac.Key;
                passwordHash = hmac.ComputeHash(System.Text.Encoding.UTF8.GetBytes(password));
            }
        }

        public async Task<bool> UserExists(string Username)
        {
            if (await _context.TblUser.AnyAsync(x => x.Email == Username))
                return true;
            return false;
        }
    }
}

Next, create an interface file with the name IAuthRepository.cs then replace all CSharp code with these.

using System.Threading.Tasks;
using AspNetAngularAuth.Models;

namespace AspNetAngularAuth.Repositories
{
     public interface IAuthRepository
     {
             Task<TblUser> Register(TblUser user, string password);
             Task<TblUser> Login(string username, string password);
             Task<bool> UserExists(string username);
     }
}

Next, open and edit again Startup.cs then add this line inside ConfigureServices bracket.

services.AddScoped<IAuthRepository, AuthRepository>();

Also, import the required classes and libraries.

Create Controller for Authentication

Now, we have to create an endpoint for user login and register. Create a CSharp file with the name Controllers/AuthController.cs then open that file and replace all CSharp codes with these.

using System;
using System.IdentityModel.Tokens.Jwt;
using System.Security.Claims;
using System.Text;
using System.Threading.Tasks;
using AspNetAngularAuth.Dtos;
using AspNetAngularAuth.Models;
using AspNetAngularAuth.Repositories;
using AutoMapper;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Configuration;
using Microsoft.IdentityModel.Tokens;

namespace AspNetAngularAuth.Controllers
{
    [Route("api/[controller]")]
    [ApiController]
    public class AuthController: ControllerBase
    {
        private readonly IAuthRepository _repo;
        private readonly IConfiguration _config;
        private readonly IMapper _mapper;

        public AuthController(IAuthRepository repo, IConfiguration config, IMapper mapper)
        {
            _mapper = mapper;
            _config = config;
            _repo = repo;
        }

        [HttpPost("register")]
        public async Task<IActionResult> Register(RegisterDto registerDto)
        {
            registerDto.Email = registerDto.Email.ToLower();
            if (await _repo.UserExists(registerDto.Email))
                return BadRequest("Email already exists");

            var userToCreate = _mapper.Map<TblUser>(registerDto);
            var createdUser = await _repo.Register(userToCreate, registerDto.Password);
            return StatusCode(201, new { email = createdUser.Email, fullname = createdUser.FullName });
        }

        [HttpPost("login")]
        public async Task<IActionResult> Login(LoginDto loginDto)
        {
            var userFromRepo = await _repo.Login(loginDto.Email.ToLower(), loginDto.Password);
            if (userFromRepo == null)
                return Unauthorized();

            var claims = new[]
            {
                new Claim(ClaimTypes.NameIdentifier, userFromRepo.UserId.ToString()),
                new Claim(ClaimTypes.Name, userFromRepo.Email)
            };

            var key = new SymmetricSecurityKey(Encoding.UTF8
                .GetBytes(_config.GetSection("AppSettings:Token").Value));
            var creds = new SigningCredentials(key, SecurityAlgorithms.HmacSha512Signature);
            var tokenDescriptor = new SecurityTokenDescriptor
            {
                Subject = new ClaimsIdentity(claims),
                Expires = DateTime.Now.AddDays(1),
                SigningCredentials = creds
            };

            var tokenHandler = new JwtSecurityTokenHandler();
            var token = tokenHandler.CreateToken(tokenDescriptor);

            return Ok(new {token = tokenHandler.WriteToken(token), email = userFromRepo.Email, fullname = userFromRepo.FullName});
        }
    }
}


Test Secure API using Postman

Now, we have to run the ASP.NET Core Web API from the Terminal by typing this command.

dotnet watch run

Watch keyword is the additional command for monitoring any change in the codes then reloading the ASP.NET Core Web API application. Next, open or run the Postman application. Use the GET method and fill the right column after the GET method with localhost:5000/api/Book, Headers key with Content-Type, Headers value with application/json. You will see 401 response after sending the request.

That's mean, only authorized user can access the /api/Book endpoint. Next, we have to register a user first before login and get the authentication token. In the Postman, change the Method to POST, change the address to /api/auth/Register and fill the body (raw) with this JSON data.


Next, login using above successfully registered email and password. Change the address to /api/auth/Login and body (raw) as below.

Now, you can get the Token from the response and put as Authorization -> Bearer Token value to GET book data.

Install or Update Angular 7 CLI and Create Application

Before installing the Angular 7 CLI, make sure you have installed Node.js https://nodejs.organd can open Node.js command prompt. Next, open the Node.js command prompt then type this command to install Angular 7 CLI.

npm install -g @angular/cli

Next, create an Angular 7 application by typing this command in the root of ASP.NET Core application/project directory.

ng new client

Where client is the name of the Angular 7 application. You can specify your own name, we like to name it client because it's put inside ASP.NET Core Project directory. If there's a question, we fill them with Y and SCSS. Next, go to the newly created Angular 7 application.

cd client

Run the Angular 7 application for the first time.

ng serve

Now, go to localhost:4200 and you should see this page.


Add Routes for Navigation between Angular Pages/Component

On the previous steps, we have to add Angular 7 Routes when answering the questions. Now, we just added the required pages for CRUD (Create, Read, Update, Delete) Supplier data. Type this commands to add the Angular 7 components or pages.

ng g component book
ng g component auth/login
ng g component auth/register

Open src/app/app.module.ts then you will see those components imported and declared in @NgModule declarations. Next, open and edit src/app/app-routing.module.ts then add these imports.

import { BookComponent } from './book/book.component';
import { LoginComponent } from './auth/login/login.component';
import { RegisterComponent } from './auth/register/register.component';

Add these arrays to the existing routes constant.

const routes: Routes = [
  {
    path: 'book',
    component: BookComponent,
    data: { title: 'List of Books' }
  },
  {
    path: 'login',
    component: LoginComponent,
    data: { title: 'Login' }
  },
  {
    path: 'register',
    component: RegisterComponent,
    data: { title: 'Register' }
  }
];

Open and edit src/app/app.component.html and you will see the existing router outlet. Next, modify this HTML page to fit the CRUD page.

<div style="text-align:center">
  <h1>
    Welcome to {{ title }}!
  </h1>
  <img width="150" alt="Angular Logo" src="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAyNTAgMjUwIj4KICAgIDxwYXRoIGZpbGw9IiNERDAwMzEiIGQ9Ik0xMjUgMzBMMzEuOSA2My4ybDE0LjIgMTIzLjFMMTI1IDIzMGw3OC45LTQzLjcgMTQuMi0xMjMuMXoiIC8+CiAgICA8cGF0aCBmaWxsPSIjQzMwMDJGIiBkPSJNMTI1IDMwdjIyLjItLjFWMjMwbDc4LjktNDMuNyAxNC4yLTEyMy4xTDEyNSAzMHoiIC8+CiAgICA8cGF0aCAgZmlsbD0iI0ZGRkZGRiIgZD0iTTEyNSA1Mi4xTDY2LjggMTgyLjZoMjEuN2wxMS43LTI5LjJoNDkuNGwxMS43IDI5LjJIMTgzTDEyNSA1Mi4xem0xNyA4My4zaC0zNGwxNy00MC45IDE3IDQwLjl6IiAvPgogIDwvc3ZnPg==">
</div>
<div class="container">
  <router-outlet></router-outlet>
</div>

Open and edit src/app/app.component.scss then replace all SCSS codes with this.

.container {
  padding: 20px;
}
Create a custom Angular 7 HttpInterceptor

Before creating a custom Angular 7 HttpInterceptor, create a folder with the name client/src/app/interceptors. Next, create a file for the custom Angular 7 HttpInterceptor with the name client/src/app/interceptors/token.interceptor.ts. Open and edit that file the add these imports.

import { Injectable } from '@angular/core';
import {
    HttpRequest,
    HttpHandler,
    HttpEvent,
    HttpInterceptor,
    HttpResponse,
    HttpErrorResponse
} from '@angular/common/http';
import { Observable, throwError } from 'rxjs';
import { map, catchError } from 'rxjs/operators';
import { Router } from '@angular/router';

Create a class that implementing HttpInterceptor method.

@Injectable()
export class TokenInterceptor implements HttpInterceptor {

}

Inject the required module to the constructor inside the class.

constructor(private router: Router) {}

Implement a custom Interceptor function.

intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {

    const token = localStorage.getItem('token');
    if (token) {
      request = request.clone({
        setHeaders: {
          'Authorization': 'Bearer ' + token
        }
      });
    }
    if (!request.headers.has('Content-Type')) {
      request = request.clone({
        setHeaders: {
          'content-type': 'application/json'
        }
      });
    }
    request = request.clone({
      headers: request.headers.set('Accept', 'application/json')
    });
    return next.handle(request).pipe(
      map((event: HttpEvent<any>) => {
        if (event instanceof HttpResponse) {
          console.log('event--->>>', event);
        }
        return event;
      }),
      catchError((error: HttpErrorResponse) => {
        console.log(error);
        if (error.status === 401) {
          this.router.navigate(['login']);
        }
        if (error.status === 400) {
          alert(error.error);
        }
        return throwError(error);
      }));
}

Next, we have to register this custom HttpInterceptor and HttpClientModule. Open and edit client/src/app.module.ts then add these imports.

import { HTTP_INTERCEPTORS, HttpClientModule } from '@angular/common/http';
import { TokenInterceptor } from './interceptors/token.interceptor';

Add HttpClientModule to the @NgModule imports array.

imports: [
  BrowserModule,
  AppRoutingModule,
  HttpClientModule
],

Add the Interceptor modules to the provider array of the @NgModule.

providers: [
  {
    provide: HTTP_INTERCEPTORS,
    useClass: TokenInterceptor,
    multi: true
  }
],

Now, the HTTP interceptor is ready to intercept any request to the API.

Create Services for Accessing Book and Authentication API

To accessing the ASP Net Core Web API from Angular 7 application, we have to create services for that. Type these commands to generate the Angular 7 services from the client folder.

ng g service auth
ng g service book

Next, open and edit client/src/app/auth.service.ts then add these imports.

import { HttpClient } from '@angular/common/http';
import { Observable, of } from 'rxjs';
import { catchError, tap } from 'rxjs/operators';

Declare a variable as ASP Net Core Web API URL.

apiUrl = 'http://192.168.0.5:5000/api/auth/';

Inject the HttpClient module inside the constructor.

constructor(private http: HttpClient) { }

Create all required functions for Login, Logout, Register, and helper functions.

login(data: any): Observable<any> {
  return this.http.post<any>(this.apiUrl + 'login', data)
    .pipe(
      tap(_ => this.log('login')),
      catchError(this.handleError('login', []))
    );
}

register(data: any): Observable<any> {
  return this.http.post<any>(this.apiUrl + 'register', data)
    .pipe(
      tap(_ => this.log('login')),
      catchError(this.handleError('login', []))
    );
}

private handleError<T>(operation = 'operation', result?: T) {
  return (error: any): Observable<T> => {

    // TODO: send the error to remote logging infrastructure
    console.error(error); // log to console instead

    // TODO: better job of transforming error for user consumption
    this.log(${operation} failed: ${error.message});

    // Let the app keep running by returning an empty result.
    return of(result as T);
  };
}

/** Log a HeroService message with the MessageService */
private log(message: string) {
  console.log(message);
}

Next, create an object class that represents Book data client/src/app/book/book.ts then replace all file contents with these.

export class Book {
    bookId: number;
    isbn: string;
    title: string;
    author: string;
    description: string;
    publisher: string;
    publishedYear: number;
    price: number;
}

Next, open and edit client/src/app/services/book.service.ts then replace all codes with this.

import { Injectable } from '@angular/core';
import { Book } from './book/book';
import { HttpClient } from '@angular/common/http';
import { Observable, of } from 'rxjs';
import { catchError, tap } from 'rxjs/operators';

@Injectable({
  providedIn: 'root'
})
export class BookService {

  apiUrl = 'http://192.168.0.5:5000/api/book';

  constructor(private http: HttpClient) { }

  getBooks(): Observable<Book[]> {
    return this.http.get<Book[]>(this.apiUrl + 'book')
      .pipe(
        tap(_ => this.log('fetched books')),
        catchError(this.handleError('getBooks', []))
      );
  }

  private handleError<T>(operation = 'operation', result?: T) {
    return (error: any): Observable<T> => {

      // TODO: send the error to remote logging infrastructure
      console.error(error); // log to console instead

      // TODO: better job of transforming error for user consumption
      this.log(${operation} failed: ${error.message});

      // Let the app keep running by returning an empty result.
      return of(result as T);
    };
  }

  /** Log a HeroService message with the MessageService */
  private log(message: string) {
    console.log(message);
  }
}


Display List of Book using Angular 7 Material

To display a list of books to the Angular 7 template. First, open and edit client/src/app/book/book.component.ts then add these imports.

import { Book } from './book';
import { BookService } from '../book.service';
import { AuthService } from '../auth.service';
import { Router } from '@angular/router';

Next, inject the Book and Auth Services to the constructor.

constructor(private bookService: BookService, private authService: AuthService, private router: Router) { }

Declare these variables before the constructor.

data: Book[] = [];
displayedColumns: string[] = ['bookId', 'isbn', 'title'];
isLoadingResults = true;

Create a function for consuming or get a book list from the booking service.

getBooks(): void {
  this.bookService.getBooks()
    .subscribe(books => {
      this.data = books;
      console.log(this.data);
      this.isLoadingResults = false;
    }, err => {
      console.log(err);
      this.isLoadingResults = false;
    });
}

Call this function from ngOnInit.

ngOnInit() {
  this.getBooks();
}

Add a function for log out the current session.

logout() {
  localStorage.removeItem('token');
  this.router.navigate(['login']);
}

Next, for the user interface (UI) we will use Angular 7 Material and CDK. There's a CLI for generating a Material component like Table as a component, but we will create or add the Table component from scratch to existing component. Type this command to install Angular 7 Material.

ng add @angular/material

If there are some questions, answer them like below.

? Choose a prebuilt theme name, or "custom" for a custom theme: Purple/Green       [ Preview: https://material.angular.i
o?theme=purple-green ]
? Set up HammerJS for gesture recognition? Yes
? Set up browser animations for Angular Material? Yes

Next, we have to register all required Angular Material components or modules to src/app/app.module.ts. Open and edit that file then add this imports.

import {
  MatInputModule,
  MatPaginatorModule,
  MatProgressSpinnerModule,
  MatSortModule,
  MatTableModule,
  MatIconModule,
  MatButtonModule,
  MatCardModule,
  MatFormFieldModule } from '@angular/material';

Also, modify FormsModule import to add ReactiveFormsModule.

import { FormsModule, ReactiveFormsModule } from '@angular/forms';

Register the above modules to @NgModule imports.

imports: [
  BrowserModule,
  FormsModule,
  HttpClientModule,
  AppRoutingModule,
  ReactiveFormsModule,
  BrowserAnimationsModule,
  MatInputModule,
  MatTableModule,
  MatPaginatorModule,
  MatSortModule,
  MatProgressSpinnerModule,
  MatIconModule,
  MatButtonModule,
  MatCardModule,
  MatFormFieldModule
],

Next, open and edit client/src/app/book/book.component.html then replace all HTML tags with this Angular 7 Material tags.

<div class="example-container mat-elevation-z8">
  <div class="example-loading-shade"
       *ngIf="isLoadingResults">
    <mat-spinner *ngIf="isLoadingResults"></mat-spinner>
  </div>
  <div class="button-row">
    <a mat-flat-button color="primary" (click)="logout()">Logout</a>
  </div>
  <div class="mat-elevation-z8">
    <table mat-table [dataSource]="data" class="example-table">

      <!-- Book ID Column -->
      <ng-container matColumnDef="bookId">
        <th mat-header-cell *matHeaderCellDef>Book ID</th>
        <td mat-cell *matCellDef="let row">{{row.bookId}}</td>
      </ng-container>

      <!-- ISBN Column -->
      <ng-container matColumnDef="isbn">
        <th mat-header-cell *matHeaderCellDef>ISBN</th>
        <td mat-cell *matCellDef="let row">{{row.isbn}}</td>
      </ng-container>

      <!-- Title Column -->
      <ng-container matColumnDef="title">
        <th mat-header-cell *matHeaderCellDef>Title</th>
        <td mat-cell *matCellDef="let row">{{row.title}}</td>
      </ng-container>

      <tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
      <tr mat-row matRowDef="let row; columns: displayedColumns;"></tr>
    </table>
  </div>
</div>

Finally, we have to align the style for this page. Open and edit client/src/app/book/book.component.scss then replace all SCSS codes with these.

/ Structure */
.example-container {
    position: relative;
    padding: 5px;
}

.example-table-container {
    position: relative;
    max-height: 400px;
    overflow: auto;
}

table {
    width: 100%;
}

.example-loading-shade {
    position: absolute;
    top: 0;
    left: 0;
    bottom: 56px;
    right: 0;
    background: rgba(0, 0, 0, 0.15);
    z-index: 1;
    display: flex;
    align-items: center;
    justify-content: center;
}

.example-rate-limit-reached {
    color: #980000;
    max-width: 360px;
    text-align: center;
}

/* Column Widths */
.mat-column-number,
.mat-column-state {
    max-width: 64px;
}

.mat-column-created {
    max-width: 124px;
}

.mat-flat-button {
    margin: 5px;
}


Create a Login and Register Page

This time for authentication part. Open and edit client/src/app/auth/login/login.component.ts then add these imports.

import { FormControl, FormGroupDirective, FormBuilder, FormGroup, NgForm, Validators } from '@angular/forms';
import { AuthService } from '../../auth.service';
import { Router } from '@angular/router';
import { ErrorStateMatcher } from '@angular/material/core';

Declare these variables before the constructor.

loginForm: FormGroup;
email = '';
password = '';
matcher = new MyErrorStateMatcher();
isLoadingResults = false;

Inject the imported modules to the constructor.

constructor(private formBuilder: FormBuilder, private router: Router, private authService: AuthService) { }

Initialize NgForm to the NgOnInit function.

ngOnInit() {
  this.loginForm = this.formBuilder.group({
    'email' : [null, Validators.required],
    'password' : [null, Validators.required]
  });
}

Add a function to submit the login form.

onFormSubmit(form: NgForm) {
  this.authService.login(form)
    .subscribe(res => {
      console.log(res);
      if (res.token) {
        localStorage.setItem('token', res.token);
        this.router.navigate(['book']);
      }
    }, (err) => {
      console.log(err);
    });
}

Add a function to go to the Register page.

register() {
  this.router.navigate(['register']);
}

Add a class that handles the form validation below this class.

/** Error when invalid control is dirty, touched, or submitted. */
export class MyErrorStateMatcher implements ErrorStateMatcher {
  isErrorState(control: FormControl | null, form: FormGroupDirective | NgForm | null): boolean {
    const isSubmitted = form && form.submitted;
    return !!(control && control.invalid && (control.dirty || control.touched || isSubmitted));
  }
}

Next, open and edit client/src/app/auth/login/login.component.html then replace all HTML tags with these.

<div class="example-container mat-elevation-z8">
  <div class="example-loading-shade"
       *ngIf="isLoadingResults">
    <mat-spinner *ngIf="isLoadingResults"></mat-spinner>
  </div>
  <mat-card class="example-card">
    <form [formGroup]="loginForm" (ngSubmit)="onFormSubmit(loginForm.value)">
      <mat-form-field class="example-full-width">
        <input matInput type="email" placeholder="Email" formControlName="email"
               [errorStateMatcher]="matcher">
        <mat-error>
          <span *ngIf="!loginForm.get('email').valid && loginForm.get('email').touched">Please enter your email</span>
        </mat-error>
      </mat-form-field>
      <mat-form-field class="example-full-width">
        <input matInput type="password" placeholder="Password" formControlName="password"
               [errorStateMatcher]="matcher">
        <mat-error>
          <span ngIf="!loginForm.get('password').valid && loginForm.get('password').touched">Please enter your password</span>
        </mat-error>
      </mat-form-field>
      <div class="button-row">
        <button type="submit" [disabled]="!loginForm.valid" mat-flat-button color="primary">Login</button>
      </div>
      <div class="button-row">
        <button type="button" mat-flat-button color="primary" (click)="register()">Register</button>
      </div>
    </form>
  </mat-card>
</div>

Next, give this page a style by open and edit client/src/app/auth/login/login.component.scss then applies these styles codes.

/ Structure */
.example-container {
  position: relative;
  padding: 5px;
}

.example-form {
  min-width: 150px;
  max-width: 500px;
  width: 100%;
}

.example-full-width {
  width: 100%;
}

.example-full-width:nth-last-child() {
  margin-bottom: 10px;
}

.button-row {
  margin: 10px 0;
}

.mat-flat-button {
  margin: 5px;
}

Next, for register page, open and edit client/src/app/auth/register/register.component.ts then replace all Typescript codes with these.

import { Component, OnInit } from '@angular/core';
import { FormControl, FormGroupDirective, FormBuilder, FormGroup, NgForm, Validators } from '@angular/forms';
import { AuthService } from '../../auth.service';
import { Router } from '@angular/router';
import { ErrorStateMatcher } from '@angular/material/core';

@Component({
  selector: 'app-register',
  templateUrl: './register.component.html',
  styleUrls: ['./register.component.scss']
})
export class RegisterComponent implements OnInit {

  registerForm: FormGroup;
  fullName = '';
  email = '';
  password = '';
  isLoadingResults = false;
  matcher = new MyErrorStateMatcher();

  constructor(private formBuilder: FormBuilder, private router: Router, private authService: AuthService) { }

  ngOnInit() {
    this.registerForm = this.formBuilder.group({
      'fullName' : [null, Validators.required],
      'email' : [null, Validators.required],
      'password' : [null, Validators.required]
    });
  }

  onFormSubmit(form: NgForm) {
    this.authService.register(form)
      .subscribe(res => {
        this.router.navigate(['login']);
      }, (err) => {
        console.log(err);
        alert(err.error);
      });
  }

}

/** Error when invalid control is dirty, touched, or submitted. */
export class MyErrorStateMatcher implements ErrorStateMatcher {
  isErrorState(control: FormControl | null, form: FormGroupDirective | NgForm | null): boolean {
    const isSubmitted = form && form.submitted;
    return !!(control && control.invalid && (control.dirty || control.touched || isSubmitted));
  }
}


Next, open and edit client/src/app/auth/register/register.component.html then replace all HTML tags with these.

<div class="example-container mat-elevation-z8">
  <div class="example-loading-shade"
       *ngIf="isLoadingResults">
    <mat-spinner *ngIf="isLoadingResults"></mat-spinner>
  </div>
  <mat-card class="example-card">
    <form [formGroup]="registerForm" (ngSubmit)="onFormSubmit(registerForm.value)">
      <mat-form-field class="example-full-width">
        <input matInput type="fullName" placeholder="Full Name" formControlName="fullName"
                [errorStateMatcher]="matcher">
        <mat-error>
          <span *ngIf="!registerForm.get('fullName').valid && registerForm.get('fullName').touched">Please enter your Full Name</span>
        </mat-error>
      </mat-form-field>
      <mat-form-field class="example-full-width">
        <input matInput type="email" placeholder="Email" formControlName="email"
               [errorStateMatcher]="matcher">
        <mat-error>
          <span *ngIf="!registerForm.get('email').valid && registerForm.get('email').touched">Please enter your email</span>
        </mat-error>
      </mat-form-field>
      <mat-form-field class="example-full-width">
        <input matInput type="password" placeholder="Password" formControlName="password"
               [errorStateMatcher]="matcher">
        <mat-error>
          <span ngIf="!registerForm.get('password').valid && registerForm.get('password').touched">Please enter your password</span>
        </mat-error>
      </mat-form-field>
      <div class="button-row">
        <button type="submit" [disabled]="!registerForm.valid" mat-flat-button color="primary">Register</button>
      </div>
    </form>
  </mat-card>
</div>

Finally, open and edit client/src/app/auth/register/register.component.scss then replace all SCSS codes with these.

/ Structure */
.example-container {
  position: relative;
  padding: 5px;
}

.example-form {
  min-width: 150px;
  max-width: 500px;
  width: 100%;
}

.example-full-width {
  width: 100%;
}

.example-full-width:nth-last-child() {
  margin-bottom: 10px;
}

.button-row {
  margin: 10px 0;
}

.mat-flat-button {
  margin: 5px;
}


Run and Test the ASP Net Core, SQL Server, and Angular 7: Web App Authentication

Let's test the whole ASP Net Core and Angular 7 Web application. First, we have to run the ASP Net Core Web API from the Visual Studio Code Terminal.

dotnet watch run

Next, run this command from the CMD to run Angular 7 application.

cd client
ng serve

If you get this error in the Visual Studio Code terminal while running Angular 7 in the browser.

Failed to authenticate HTTPS connection.
System.Security.Authentication.AuthenticationException: Authentication failed, see inner exception. ---> System.ComponentModel.Win32Exception: An unknown error occurred while processing the certificate
   --- End of inner exception stack trace ---
   at System.Net.Security.SslState.StartSendAuthResetSignal(ProtocolToken message, AsyncProtocolRequest asyncRequest, ExceptionDispatchInfo exception)
   at System.Net.Security.SslState.CheckCompletionBeforeNextReceive(ProtocolToken message, AsyncProtocolRequest asyncRequest)
   at System.Net.Security.SslState.StartSendBlob(Byte[] incoming, Int32 count, AsyncProtocolRequest asyncRequest)
   at System.Net.Security.SslState.ProcessReceivedBlob(Byte[] buffer, Int32 count, AsyncProtocolRequest asyncRequest)
   at System.Net.Security.SslState.StartReadFrame(Byte[] buffer, Int32 readBytes, AsyncProtocolRequest asyncRequest)
   at System.Net.Security.SslState.PartialFrameCallback(AsyncProtocolRequest asyncRequest)
--- End of stack trace from previous location where exception was thrown ---
   at System.Net.Security.SslState.ThrowIfExceptional()
   at System.Net.Security.SslState.InternalEndProcessAuthentication(LazyAsyncResult lazyResult)
   at System.Net.Security.SslState.EndProcessAuthentication(IAsyncResult result)
   at System.Net.Security.SslStream.EndAuthenticateAsServer(IAsyncResult asyncResult)
   at System.Net.Security.SslStream.<>c.<AuthenticateAsServerAsync>b__51_1(IAsyncResult iar)
   at System.Threading.Tasks.TaskFactory1.FromAsyncCoreLogic(IAsyncResult iar, Func2 endFunction, Action1 endAction, Task1 promise, Boolean requiresSynchronization)
--- End of stack trace from previous location where exception was thrown ---
   at Microsoft.AspNetCore.Server.Kestrel.Https.Internal.HttpsConnectionAdapter.InnerOnConnectionAsync(ConnectionAdapterContext context)

Just, open and edit Properties/launchSettings.json then replace the applicationUrl in AspNetAngularAuth object with this.

"applicationUrl": "http://192.168.0.5:5000;http://localhost:5000",

Then re-run again ASP Net Core Web API. And here they are, the Angular 7 authentication app looks like.

That it's, the ASP Net Core, SQL Server, and Angular 7: Web App Authentication. You can find the full source code in our GitHub.

That just the basic. If you need more deep learning about ASP.NET Core, Angular or related you can take the following cheap course:


Angular 8 (formerly Angular 2) - The Complete Guide

Angular Crash Course for Busy Developers

Originally published by Didin J at djamware.com

==========================================

Thanks for reading :heart: If you liked this post, share it with all of your programming buddies! Follow me on Facebook | Twitter

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_

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

Step 3

Right-click the Models folder from Solution Explorer and go to Add >> New Item >> data.

Click on the ADO.NET Entity Data Model option and click Add.

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

Add the connection properties, select database name on the next page, and click OK.

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

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

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.

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

The following Page will be displayed.

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.!

Login and Registration ASP.NET Web API Using Angular 8

Login and Registration ASP.NET Web API Using Angular 8

Get started with creating user accounts in an Angular 8 application. In this article, we will learn the step by step process of creating login and registration pages in a Web API using Angular 8

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

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

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

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

Step 3

Right-click the Models folder from Solution Explorer and go to Add >> New Item >> data.

Click on the ADO.NET Entity Data Model option and click Add.

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

Add the connection properties, select database name on the next page, and click OK.

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

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

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.

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

The following Page will be displayed.

Summary

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