shorturl.
at/eORSX
10/10/2022
https://angular.io/guide/setup-local
ng --version
ng new dating-app > Yes > CSS
ng serve
ng add @ng-bootstrap/ng-bootstrap
ng generate component navbar
Program.cs
using System.Text;
using DatingApp.API.Data;
using DatingApp.API.Services;
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.EntityFrameworkCore;
using Microsoft.IdentityModel.Tokens;
var builder = WebApplication.CreateBuilder(args);
var services = builder.Services;
var connectionString = builder.Configuration
.GetConnectionString("Default");
// Add services to the container.
services.AddControllers();
// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
services.AddCors(o =>
o.AddPolicy("CorsPolicy", builder =>
builder.WithOrigins("http://localhost:4200")
.AllowAnyHeader()
.AllowAnyMethod()));
services.AddEndpointsApiExplorer();
services.AddSwaggerGen();
services.AddDbContext<DataContext>(options =>
options.UseSqlServer(connectionString));
services.AddScoped<ITokenService, TokenService>();
services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddJwtBearer(options =>
{
options.TokenValidationParameters = new TokenValidationParameters()
{
ValidateIssuer = false,
ValidateAudience = false,
ValidateLifetime = false,
ValidateIssuerSigningKey = true,
IssuerSigningKey = new SymmetricSecurityKey(
Encoding.UTF8.GetBytes(builder.Configuration["TokenKey"]))
};
});
var app = builder.Build();
// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
{
app.UseSwagger();
app.UseSwaggerUI();
}
app.UseCors("CorsPolicy");
app.UseHttpsRedirection();
app.UseAuthentication();
app.UseAuthorization();
app.MapControllers();
app.Run();
app.component.ts
import { HttpClient } from '@angular/common/http';
import { Component, OnInit } from '@angular/core';
import { AppUser } from './_models/app-user';
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent implements OnInit {
name = 'An Trinh';
users: AppUser[] = [];
constructor(private httpClient: HttpClient) {}
ngOnInit(): void {
this.httpClient.get<AppUser[]>("https://localhost:7219/api/Auth")
.subscribe(
response => this.users = response,
error => console.log(error)
);
}
}
app.component.html
<app-navbar></app-navbar>
<h3 class="text-center">Hello, {{ name }}</h3>
<table class="container table table-striped table-bordered table-hover">
<thead>
<th>Id</th>
<th>Name</th>
<th>Email</th>
</thead>
<tbody>
<tr *ngFor="let user of users">
<td>{{ user.id }}</td>
<td>{{ user.username }}</td>
<td>{{ user.email }}</td>
</tr>
</tbody>
</table>
app-user.ts
export class AppUser {
id: number = 0;
username: string = "";
email: string = "";
}
navbar.component.html
<nav class="navbar navbar-expand-lg bg-light">
<div class="container-fluid">
<a class="navbar-brand" href="#">DATING APP</a>
<div class="collapse navbar-collapse" id="navbarSupportedContent">
<ul class="navbar-nav me-auto mb-2 mb-lg-0">
<li class="nav-item">
<a class="nav-link active" aria-current="page" href="#">Home</a>
</li>
<li class="nav-item">
<a class="nav-link" href="#">Link</a>
</li>
</ul>
<form class="d-flex">
<input
class="form-control me-2"
type="text"
placeholder="Username"
aria-label="Username"
/>
<input
class="form-control me-2"
type="password"
placeholder="Password"
aria-label="Password"
/>
<button class="btn btn-outline-success" type="submit">Login</button>
</form>
</div>
</div>
</nav>
03/10/2022
https://jwt.io
- dotnet add package
Microsoft.AspNetCore.Authentication.JwtBearer
- dotnet add package System.IdentityModel.Tokens.Jwt
Program.cs
using DatingApp.API.Data;
using DatingApp.API.Services;
using Microsoft.EntityFrameworkCore;
var builder = WebApplication.CreateBuilder(args);
var services = builder.Services;
var connectionString = builder.Configuration
.GetConnectionString("Default");
// Add services to the container.
services.AddControllers();
// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
services.AddEndpointsApiExplorer();
services.AddSwaggerGen();
services.AddDbContext<DataContext>(options =>
options.UseSqlServer(connectionString));
services.AddScoped<ITokenService, TokenService>();
services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddJwtBearer(options =>
{
options.TokenValidationParameters = new TokenValidationParameters()
{
ValidateIssuer = false,
ValidateAudience = false,
ValidateLifetime = false,
ValidateIssuerSigningKey = true,
IssuerSigningKey = new SymmetricSecurityKey(
Encoding.UTF8.GetBytes(builder.Configuration["TokenKey"]))
};
});
var app = builder.Build();
// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
{
app.UseSwagger();
app.UseSwaggerUI();
}
app.UseHttpsRedirection();
app.UseAuthentication();
app.UseAuthorization();
app.MapControllers();
app.Run();
TokenService.cs
using System.IdentityModel.Tokens.Jwt;
using System.Security.Claims;
using System.Text;
using Microsoft.IdentityModel.Tokens;
namespace DatingApp.API.Services
{
public class TokenService : ITokenService
{
private readonly IConfiguration _configuration;
public TokenService(IConfiguration configuration)
{
_configuration = configuration;
}
public string CreateToken(string username)
{
var claims = new List<Claim>()
{
new Claim(JwtRegisteredClaimNames.NameId, username),
new Claim(JwtRegisteredClaimNames.Email, $"{username}@dating.app"),
};
var symmetricKey = new SymmetricSecurityKey(
Encoding.UTF8.GetBytes(_configuration["TokenKey"])
);
var tokenDescriptor = new SecurityTokenDescriptor
{
Subject = new ClaimsIdentity(claims),
Expires = DateTime.Now.AddDays(1),
SigningCredentials = new SigningCredentials(
symmetricKey, SecurityAlgorithms.HmacSha512Signature)
};
var tokenHandler = new JwtSecurityTokenHandler();
var token = tokenHandler.CreateToken(tokenDescriptor);
return tokenHandler.WriteToken(token);
}
}
}
ITokenService.cs
using DatingApp.API.Data.Entities;
namespace DatingApp.API.Services
{
public interface ITokenService
{
string CreateToken(string username);
}
}
appsettings.json
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
},
"AllowedHosts": "*",
"TokenKey": "super secret key!",
"ConnectionStrings": {
"Default": "Server=localhost,1433;Database=DatingApp12;User Id=DbEditor;Password=Covid19@@2022;"
}
}
AuthController.cs
using System.Security.Cryptography;
using System.Text;
using DatingApp.API.Data;
using DatingApp.API.Data.Entities;
using DatingApp.API.DTOs;
using DatingApp.API.Services;
using Microsoft.AspNetCore.Mvc;
namespace DatingApp.API.Controllers
{
public class AuthController : BaseController
{
private readonly DataContext _context;
private readonly ITokenService _tokenService;
public AuthController(
DataContext context,
ITokenService tokenService)
{
_context = context;
_tokenService = tokenService;
}
[HttpPost("register")]
public IActionResult Register([FromBody] AuthUserDto authUserDto)
{
authUserDto.Username = authUserDto.Username.ToLower();
if (_context.AppUsers.Any(u => u.Username == authUserDto.Username))
{
return BadRequest("Username is already registered!");
}
using var hmac = new HMACSHA512();
var passwordBytes = Encoding.UTF8.GetBytes(authUserDto.Password);
var newUser = new User
{
Username = authUserDto.Username,
PasswordSalt = hmac.Key,
PasswordHash = hmac.ComputeHash(passwordBytes)
};
_context.AppUsers.Add(newUser);
_context.SaveChanges();
var token = _tokenService.CreateToken(newUser.Username);
return Ok(token);
}
[HttpPost("login")]
public IActionResult Login([FromBody] AuthUserDto authUserDto)
{
authUserDto.Username = authUserDto.Username.ToLower();
var currentUser = _context.AppUsers
.FirstOrDefault(u => u.Username == authUserDto.Username);
if (currentUser == null)
{
return Unauthorized("Username is invalid.");
}
using var hmac = new HMACSHA512(currentUser.PasswordSalt);
var passwordBytes = hmac.ComputeHash(Encoding.UTF8.GetBytes(authUserDto.Password));
for (int i = 0; i < currentUser.PasswordHash.Length; i++)
{
if (currentUser.PasswordHash[i] != passwordBytes[i])
{
return Unauthorized("Password is invalid.");
}
}
var token = _tokenService.CreateToken(currentUser.Username);
return Ok(token);
}
[Authorize]
[HttpGet]
public IActionResult Get()
{
return Ok(_context.AppUsers.ToList());
}
}
}
19/09/2022
- dotnet add package Microsoft.EntityFrameworkCore
- dotnet add package
Microsoft.EntityFrameworkCore.Design
- dotnet add package
Microsoft.EntityFrameworkCore.SqlServer
- dotnet add package Pomelo.EntityFrameworkCore.MySql
- dotnet-ef migrations add InitialDb -o Data/Migrations
- dotnet-ef database update
- dotnet-ef migrations add AddPasswordToUser
- dotnet-ef database update
AuthUserDto.cs
using System.ComponentModel.DataAnnotations;
namespace DatingApp.API.DTOs
{
public class AuthUserDto
{
[Required]
[MaxLength(256)]
public string Username { get; set; }
[Required]
[MaxLength(256)]
public string Password { get; set; }
}
}
BaseController.cs
using Microsoft.AspNetCore.Mvc;
namespace DatingApp.API.Controllers
{
[Route("api/[controller]")]
[ApiController]
public class BaseController : ControllerBase
{
}
}
AuthController.cs
using Microsoft.AspNetCore.Mvc;
namespace DatingApp.API.Controllers
{
public class AuthController : BaseController
{
private readonly DataContext _context;
public AuthController(DataContext context)
{
_context = context;
}
public IActionResult Register([FromBody] AuthUserDto authUserDto)
{
authUserDto.Username = authUserDto.Username.ToLower();
if (_context.AppUsers.Any(u => u.Username == authUserDto.Username))
{
return BadRequest("Username is already registered!");
}
using var hmac = new HMACSHA512();
var passwordBytes = Encoding.UTF8.GetBytes(authUserDto.Password);
var newUser = new User
{
Username = authUserDto.Username,
PasswordSalt = hmac.Key,
PasswordHash = hmac.ComputeHash(passwordBytes)
};
_context.AppUsers.Add(newUser);
_context.SaveChanges();
return Ok(newUser.Username);
}
}
}
Program.cs
using DatingApp.API.Data;
using Microsoft.EntityFrameworkCore;
var builder = WebApplication.CreateBuilder(args);
var services = builder.Services;
var connectionString = builder.Configuration
.GetConnectionString("Default");
// Add services to the container.
services.AddControllers();
// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
services.AddEndpointsApiExplorer();
services.AddSwaggerGen();
services.AddDbContext<DataContext>(options =>
options.UseSqlServer(connectionString));
var app = builder.Build();
// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
{
app.UseSwagger();
app.UseSwaggerUI();
}
app.UseHttpsRedirection();
app.UseAuthorization();
app.MapControllers();
app.Run();
MySQL
// https://github.com/PomeloFoundation/Pomelo.EntityFrameworkCore.MySql
var serverVersion = new MySqlServerVersion(new Version(8, 0, 29));
// Replace 'YourDbContext' with the name of your own DbContext derived class.
services.AddDbContext<DataContext>(
dbContextOptions => dbContextOptions
.UseMySql(connectionString, serverVersion)
.LogTo(Console.WriteLine, LogLevel.Information)
.EnableSensitiveDataLogging()
.EnableDetailedErrors()
);
AppSettings.json
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
},
"AllowedHosts": "*",
"ConnectionStrings": {
"Default": "Server=localhost;Database=DatingApp12;Trusted_Connection=True;"
"Default": "server=localhost;database=DatingApp12;user=user;password=password
}
}
User.cs
using System.ComponentModel.DataAnnotations;
namespace DatingApp.API.Data.Entities
{
public class User
{
[Key]
public int Id { get; set; }
[Required]
[MaxLength(256)]
public string Username { get; set; }
[MaxLength(256)]
public string Email { get; set; }
public byte[] PasswordHash { get; set; }
public byte[] PasswordSalt { get; set; }
}
}
12/09/2022
https://github.com/minhanbkdn/DatingApp/
dotnet new sln -n DatingApp
dotnet new webapi -n DatingApp.API -o
DatingApp.API
dotnet sln add DatingApp.API
code DatingApp.API
29/08/2022
ProductController.cs
using Microsoft.AspNetCore.Mvc;
using ProductManager.Models;
using ProductManager.Services;
namespace ProductManager.Controllers
{
public class ProductController : Controller
{
private readonly IProductService _productService;
public ProductController(IProductService productService)
{
_productService = productService;
}
public IActionResult Index()
{
var products = _productService.GetProducts();
return View(products);
}
public IActionResult Create()
{
var categories = _productService.GetCategories();
return View(categories);
}
public IActionResult Update(int id)
{
var product = _productService.GetProductById(id);
if (product == null) return RedirectToAction("Create");
ViewBag.Product = product;
var categories = _productService.GetCategories();
return View(categories);
}
public IActionResult Save(Product product)
{
_productService.CreateProduct(product);
return RedirectToAction("Index");
}
}
}
IProductService.cs
using ProductManager.Models;
namespace ProductManager.Services
{
public interface IProductService
{
List<Product> GetProducts();
Product? GetProductById(int id);
void CreateProduct(Product product);
void UpdateProduct(Product product);
void DeleteProduct(int id);
List<Category> GetCategories();
}
}
ProductService.cs
using ProductManager.Models;
namespace ProductManager.Services
{
public class ProductService : IProductService
{
private readonly DataContext _context;
public ProductService(DataContext context)
{
_context = context;
}
public void CreateProduct(Product product)
{
_context.Products.Add(product);
_context.SaveChanges();
}
public void DeleteProduct(int id)
{
var existedProduct = GetProductById(id);
if (existedProduct == null) return;
_context.Products.Remove(existedProduct);
_context.SaveChanges();
}
public Product? GetProductById(int id)
{
return _context.Products.FirstOrDefault(p => p.Id == id);
}
public List<Product> GetProducts()
{
return _context.Products
.Include(x => x.Category)
.ToList();
}
public void UpdateProduct(Product product)
{
var existedProduct = GetProductById(product.Id);
if (existedProduct == null) return;
existedProduct.Name = product.Name;
existedProduct.Slug = product.Slug;
existedProduct.Price = product.Price;
existedProduct.Quantity = product.Quantity;
existedProduct.CategoryId = product.CategoryId;
_context.Update(existedProduct);
_context.SaveChanges();
}
public IActionResult Delete(int id)
{
_productService.DeleteProduct(id);
return RedirectToAction("Index");
}
public List<Category> GetCategories()
{
return _context.Category.ToList();
}
}
}
Create.cshtml
@model List<Category>;
@{
ViewData["Title"] = "Product Create Page";
var categories = Model;
}
<form action="/Product/Save" method="post">
<div class="form-group">
<label for="Name">Name</label>
<input type="text" class="form-control" id="Name" name="Name">
</div>
<div class="form-group">
<label for="Slug">Slug</label>
<input type="text" class="form-control" id="Slug" name="Slug">
</div>
<div class="form-group">
<label for="Price">Price</label>
<input type="number" class="form-control" id="Price" name="Price">
</div>
<div class="form-group">
<label for="Quantity">Quantity</label>
<input type="number" class="form-control" id="Quantity" name="Quantity">
</div>
<div class="form-group">
<label for="CategoryId">Category</label>
<select class="form-control" id="CategoryId" name="CategoryId">
@foreach (var category in categories)
{
<option value="@category.Id">
@category.Name
</option>
}
</select>
</div>
<button type="submit" class="btn btn-primary">Submit</button>
</form>
Update.cshtml
@model List<Category>;
@{
ViewData["Title"] = "Product Create Page";
var categories = Model;
var product = ViewBag.Product;
}
<form action="/Product/Save" method="post">
<div class="form-group">
<label for="Id">Id</label>
<input type="text" class="form-control" id="Id" name="Id" value="@product.Id" readonly>
</div>
<div class="form-group">
<label for="Name">Name</label>
<input type="text" class="form-control" id="Name" name="Name" value="@product.Name">
</div>
<div class="form-group">
<label for="Slug">Slug</label>
<input type="text" class="form-control" id="Slug" name="Slug" value="@product.Slug">
</div>
<div class="form-group">
<label for="Price">Price</label>
<input type="number" class="form-control" id="Price" name="Price" value="@product.Price">
</div>
<div class="form-group">
<label for="Quantity">Quantity</label>
<input type="number" class="form-control" id="Quantity" name="Quantity" value="@product.Quantity">
</div>
<div class="form-group">
<label for="CategoryId">Category</label>
<select class="form-control" id="CategoryId" name="CategoryId">
@foreach (var category in categories)
{
@if (category.Id == product.CategoryId)
{
<option value="@category.Id" selected>
@category.Name
</option>
}
else {
<option value="@category.Id">
@category.Name
</option>
}
}
</select>
</div>
<button type="submit" class="btn btn-primary">Submit</button>
</form>
Index.cshtml
@model List<Product>;
@{
ViewData["Title"] = "Product Page";
var products = Model;
}
<div class="text-center">
<h1 class="display-4">Welcome Product Page</h1>
<table class="table table-striped table-hover">
<thead>
<th>ID</th>
<th>Name</th>
<th>Price</th>
<th>Quantity</th>
<th>Category</th>
<th>
<a href="/Product/Create" class="btn btn-primary">Create</a>
</th>
</thead>
<tbody>
@foreach (var product in products)
{
<tr>
<td>@product.Id</td>
<td>@product.Name</td>
<td>@product.Price</td>
<td>@product.Quantity</td>
<td>@product.Category.Name</td>
<td>
<a href="/Product/[email protected]" class="btn btn-success">Update</a>
<a href="/Product/[email protected]" class="btn btn-danger">Delete</a>
</td>
</tr>
}
</tbody>
</table>
</div>
27/08/2022
- Extensions: NuGet Gallery
- dotnet add package Microsoft.EntityFrameworkCore
- dotnet add package
Microsoft.EntityFrameworkCore.Design
- dotnet add package
Microsoft.EntityFrameworkCore.SqlServer
- dotnet add package Pomelo.EntityFrameworkCore.MySql
- dotnet tool install --global dotnet-ef
- dotnet tool update --global dotnet-ef
- Ef-db-context
- asp-add-db-context
"ConnectionStrings": {
"Default":
"Server=localhost;Database=ProductDb12;Trusted_Connection=True;"
}
MySQL:
server=localhost;database=ProductDb12;user=user;password=password
using Microsoft.EntityFrameworkCore;
using ProductManager.Models;
var builder = WebApplication.CreateBuilder(args);
var services = builder.Services;
var connectionString = builder.Configuration.GetConnectionString("Default");
// Add services to the container.
services.AddControllersWithViews();
services.AddDbContext<DataContext>(options =>
options.UseSqlServer(connectionString));
var app = builder.Build();
MySQL
https://github.com/PomeloFoundation/Pomelo.EntityFrameworkCore.MySql
var serverVersion = new MySqlServerVersion(new Version(8, 0, 29));
// Replace 'YourDbContext' with the name of your own DbContext derived class.
services.AddDbContext<DataContext>(
dbContextOptions => dbContextOptions
.UseMySql(connectionString, serverVersion)
.LogTo(Console.WriteLine, LogLevel.Information)
.EnableSensitiveDataLogging()
.EnableDetailedErrors()
);
Product.cs
using System.ComponentModel.DataAnnotations;
namespace ProductManager.Models
{
public class Product
{
[Key]
public int Id { get; set; }
[MaxLength(256)]
public string Name { get; set; }
[MaxLength(256)]
public string Slug { get; set; }
public int Price { get; set; }
public int Quantity { get; set; }
}
}
- dotnet-ef migrations add InitialDb
- dotnet-ef database update
- dotnet-ef migrations add
AddSlugIntoProduct
- dotnet-ef database update
- dotnet-ef migrations add
AddTableCategory
- dotnet-ef database update
Category.cs
namespace ProductManager.Models
{
public class Category
{
public Category()
{
Products = new List<Product>();
}
public int Id { get; set; }
public string Name { get; set; }
public List<Product> Products { get; set; }
}
}
Product.cs
using System.ComponentModel.DataAnnotations;
namespace ProductManager.Models
{
public class Product
{
[Key]
public int Id { get; set; }
[MaxLength(256)]
public string Name { get; set; }
[MaxLength(256)]
public string Slug { get; set; }
public int Price { get; set; }
public int Quantity { get; set; }
public int CategoryId { get; set; }
public Category Category { get; set; }
}
}
DataContext.cs
using Microsoft.EntityFrameworkCore;
namespace ProductManager.Models
{
public class DataContext : DbContext
{
public DataContext(DbContextOptions<DataContext> options) : base(options) { }
public DbSet<Product> Products { get; set; }
public DbSet<Category> Category { get; set; }
protected override void OnModelCreating(ModelBuilder modelBuilder)
{
modelBuilder.Entity<Product>()
.HasOne(p => p.Category)
.WithMany(c => c.Products)
.HasForeignKey(p => p.CategoryId);
base.OnModelCreating(modelBuilder);
}
}
}
ProductController.cs
using Microsoft.AspNetCore.Mvc;
using ProductManager.Models;
namespace ProductManager.Controllers
{
public class ProductController : Controller
{
private readonly DataContext _context;
public ProductController(DataContext context)
{
_context = context;
}
public IActionResult Index()
{
var products = _context.Products.ToList();
return View(products);
}
}
}
IProductService.cs
using ProductManager.Models;
namespace ProductManager.Services
{
public interface IProductService
{
List<Product> GetProducts();
}
}
ProductService.cs
using ProductManager.Models;
namespace ProductManager.Services
{
public class ProductService : IProductService
{
private readonly DataContext _context;
public ProductService(DataContext context)
{
_context = context;
}
public List<Product> GetProducts()
{
return _context.Products.ToList();
}
}
}
ProductController.cs
using Microsoft.AspNetCore.Mvc;
using ProductManager.Services;
namespace ProductManager.Controllers
{
public class ProductController : Controller
{
private readonly IProductService _productService;
public ProductController(IProductService productService)
{
_productService = productService;
}
public IActionResult Index()
{
var products = _productService.GetProducts();
return View(products);
}
}
}
Program.cs