I want to use sweet alert with asp.net core c#. To replace my alert system. However I need some guidance.
When I am on a controller say edit and just after the save I want to excute this javascript what is my best way in .net core in web forms days we had registerscript.
I also need to show this message when I create a record
https://sweetalert2.github.io/
swal({
title: "MIS",
text: "Case Created your Case Number is ",
icon: "warning",
buttons: true,
dangerMode: true,
})
1.If you want to alert after save successfully,follow this:
Model:
public class Test
{
public int Id { get; set; }
public string Name { get; set; }
}
Index.cshtml:
#model IEnumerable<Test>
<table class="table">
<thead>
<tr>
<th>
#Html.DisplayNameFor(model => model.Name)
</th>
<th></th>
</tr>
</thead>
<tbody>
#foreach (var item in Model)
{
<tr>
<td>
#Html.DisplayFor(modelItem => item.Name)
</td>
<td>
<a asp-action="Edit" asp-route-id="#item.Id">Edit</a> |
<a asp-action="Details" asp-route-id="#item.Id">Details</a> |
<a asp-action="Delete" asp-route-id="#item.Id">Delete</a>
</td>
</tr>
}
</tbody>
</table>
#section Scripts
{
#if (TempData["notification"] != null)
{
#Html.Raw(TempData["notification"])
}
}
Edit.cshtml:
#model Test
<h4>Test</h4>
<hr />
<div class="row">
<div class="col-md-4">
<form asp-action="Edit">
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
<input type="hidden" asp-for="Id" />
<div class="form-group">
<label asp-for="Name" class="control-label"></label>
<input asp-for="Name" class="form-control" />
<span asp-validation-for="Name" class="text-danger"></span>
</div>
<div class="form-group">
<input type="submit" value="Save" class="btn btn-primary" />
</div>
</form>
</div>
</div>
<div>
<a asp-action="Index">Back to List</a>
</div>
#section Scripts {
#{await Html.RenderPartialAsync("_ValidationScriptsPartial");}
}
Controller:
public class TestsController : Controller
{
private readonly Mvc3_1Context _context;
public TestsController(Mvc3_1Context context)
{
_context = context;
}
public void Alert(int id)
{
var msg = "<script language='javascript'>swal({title: 'MIS',text: 'Case Created your Case Number is "+id+"', icon: 'warning',buttons: true,dangerMode: true})" + "</script>";
TempData["notification"] = msg;
}
// GET: Tests
public async Task<IActionResult> Index()
{
return View(await _context.Test.ToListAsync());
}
// GET: Tests/Edit/5
public async Task<IActionResult> Edit(int? id)
{
if (id == null)
{
return NotFound();
}
var test = await _context.Test.FindAsync(id);
if (test == null)
{
return NotFound();
}
return View(test);
}
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Edit(int id, Test test)
{
if (id != test.Id)
{
return NotFound();
}
if (ModelState.IsValid)
{
_context.Update(test);
await _context.SaveChangesAsync();
Alert(id);//add this method
return RedirectToAction(nameof(Index));
}
return View(test);
}
}
_Layout.cshtml:
<script src="~/lib/jquery/dist/jquery.min.js"></script>
<script src="~/lib/bootstrap/dist/js/bootstrap.bundle.min.js"></script>
<script src="~/js/site.js" asp-append-version="true"></script>
//add this line
<script src="https://unpkg.com/sweetalert/dist/sweetalert.min.js"></script>
Result:
2.If you want to alert before save sucessfully:
Model:
Same as the option one.
Index.cshtml:
#model IEnumerable<Test>
<table class="table">
<thead>
<tr>
<th>
#Html.DisplayNameFor(model => model.Name)
</th>
<th></th>
</tr>
</thead>
<tbody>
#foreach (var item in Model)
{
<tr>
<td>
#Html.DisplayFor(modelItem => item.Name)
</td>
<td>
<a asp-action="Edit" asp-route-id="#item.Id">Edit</a> |
<a asp-action="Details" asp-route-id="#item.Id">Details</a> |
<a asp-action="Delete" asp-route-id="#item.Id">Delete</a>
</td>
</tr>
}
</tbody>
</table>
Edit.cshtml:
#model Test
<h4>Test</h4>
<hr />
<div class="row">
<div class="col-md-4">
<form>
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
<input type="hidden" asp-for="Id" />
<div class="form-group">
<label asp-for="Name" class="control-label"></label>
<input asp-for="Name" class="form-control" />
<span asp-validation-for="Name" class="text-danger"></span>
</div>
<div class="form-group">
<input type="button" value="Save" class="btn btn-primary" onclick="confirmEdit()"/>
</div>
</form>
</div>
</div>
<div>
<a asp-action="Index">Back to List</a>
</div>
#section Scripts {
<script>
function confirmEdit() {
swal({
title: "MIS",
text: "Case Created your Case Number is " + $("#Id").val(),
icon: "warning",
buttons: true,
dangerMode: true,
}).then((willUpdate) => {
if (willUpdate) {
$.ajax({
url: "/tests/edit/"+$("#Id").val(),
type: "POST",
data: {
Id: $("#Id").val(),
Name:$("#Name").val()
},
dataType: "html",
success: function () {
swal("Done!", "It was succesfully edited!", "success")
.then((success) => {
window.location.href="/tests/index"
});
},
error: function (xhr, ajaxOptions, thrownError) {
swal("Error updating!", "Please try again", "error");
}
});
}
});
}
</script>
}
Controller:
public class TestsController : Controller
{
private readonly Mvc3_1Context _context;
public TestsController(Mvc3_1Context context)
{
_context = context;
}
// GET: Tests
public async Task<IActionResult> Index()
{
return View(await _context.Test.ToListAsync());
}
// GET: Tests/Edit/5
public async Task<IActionResult> Edit(int? id)
{
if (id == null)
{
return NotFound();
}
var test = await _context.Test.FindAsync(id);
if (test == null)
{
return NotFound();
}
return View(test);
}
[HttpPost]
public async Task<IActionResult> Edit(int id, [FromForm]Test test)
{
if (id != test.Id)
{
return NotFound();
}
if (ModelState.IsValid)
{
_context.Update(test);
await _context.SaveChangesAsync();
return RedirectToAction(nameof(Index));
}
return View(test);
}
}
_Layout.cshtml:
Same as option one.
Result:
I had to use AJAX on my .NETCORE 3.1 application to implement the Sweet Alert 2.
The syntax is just a little different than yours.
Documentation for Sweet Alert 2 can be found on this link.
A simple example, say you want an early on a button click, you could do something like:
HTML:
<input id="btnSubmit" type="button" class="btn btn-success btn-block" value="Submit" />
jQuery:
<script type="text/javascript">
$(document).ready(function () {
$("#btnSubmit").click(function () {
Swal.fire({
title: 'MIS',
text: "Case Created your Case Number is",
icon: 'error',
confirmButtonText: 'Ok'
})
});
});
</script>
Also, don't forget to add your sweetalert script tags:
<script src="~/filepath/sweetalert2.min.js"></script>
Related
Here is what I have tried
The code runs perfectly until I try to implement it in my ÄdminPortal MVC Area, then the Partial View doesn't popup at all. I'm sure I've missed something simply but being new to this I have been unable to find the answer. TIA for your help
My Controller
using Microsoft.AspNetCore.Mvc;
using Quotemaster.Areas.AdminPortal.Models;
using Quotemaster.data;
namespace Quotemaster.Areas.AdminPortal.Controllers
{
[Area("AdminPortal")]
public class MakesController : Controller
{
private readonly QMContext _context;
public MakesController(QMContext context)
{
_context = context;
}
public IActionResult Index()
{
var makesList = _context.Makes.ToList();
return View(makesList);
}
[HttpGet]
public IActionResult Create()
{
Makes makes = new Makes();
return PartialView("_MakesPartial", makes);
}
[HttpPost]
public IActionResult Create(Makes makes)
{
_context.Makes.Add(makes);
_context.SaveChanges();
var makesList = _context.Makes.ToList();
return View(makesList);
}
}
}
My Index page
#model IEnumerable<Quotemaster.Areas.AdminPortal.Models.Makes>
#{
ViewData["Title"] = "Index";
Layout = "~/Views/Shared/_AdminLayout.cshtml";
}
<div id="AddMake"></div>
<button type="button" class="btn btn-warning" data-bs-toggle="ajax-modal" data-bs-target="#AddMakes"
data-url="#Url.Action("Create")">
Add Make
</button>
<table class="table table-hover">
<thead style="background-color:orange">
<tr>
<th>
Make
</th>
<th></th>
</tr>
</thead>
<tbody>
#foreach (var item in Model) {
<tr>
<td>
#Html.DisplayFor(modelItem => item.Make)
</td>
<td>
<a asp-action="Edit" asp-route-id="#item.MakeId">Edit</a> |
<a asp-action="Details" asp-route-id="#item.MakeId">Details</a> |
<a asp-action="Delete" asp-route-id="#item.MakeId">Delete</a>
</td>
</tr>
}
</tbody>
</table>
<script type="text/javascript">
//Show Add Make Modal
$(function () {
var AddMakesElement = $('#AddMakes');
$('button[data-bs-toggle="ajax-modal"]').click(function (event) {
var url = $(this).data('url');
$.get(url).done(function (data) {
AddMakesElement.html(data);
AddMakesElement.find('.modal').modal('show');
})
})
//Save Add Makeform data
AddMakesElement.on('click', '[data-bs-save="modal"]', function (event) {
var form = $(this).parents('.modal').find('form');
var actionUrl = form.attr("action");
var sendData = form.serialize();
$.post(actionUrl, sendData).done(function (data) {
AddMakesElement.find('.modal').modal('hide');
location.reload(true);
})
})
})
</script>
My partial View
#model Quotemaster.Areas.AdminPortal.Models.Makes
//partial View
<!DOCTYPE html>
<html lang="en">
<head>
<title>Add Makes</title>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
</head>
<body>
<!-- The Modal -->
<div class="modal fade" id="AddMakes" name="AddMakes">
<div class="modal-dialog">
<div class="modal-content">
<!-- Modal Header -->
<div class="modal-header" style="background-color:orange">
<h4 class="modal-title">Add Makes</h4>
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
</div>
<!-- Modal body -->
<div class="modal-body">
<form asp-action="Create" enctype="multipart/form-data" method="post">
<div class="form-group">
<label asp-for="Make"></label>
<input asp-for="Make" class="form-control form-control-sm">
<span asp-validation-for="Make" class="text-danger"></span>
</div>
</form>
</div>
<!-- Modal footer -->
<div class="modal-footer">
<button class="btn btn-warning">Add Make</button>
<button type="button" class="btn btn-danger" data-bs-dismiss="modal">Close</button>
#*<div input typeof="hidden" id="urlMakesData"value="#Url.Action("AddMakes","Ajax")"></div>*#
</div>
</div>
</div>
</div>
</body>
</html>
1.You want to call the Create action and render the html to the following div:
<div id="AddMake"></div>
But you get the wrong element in js herevar AddMakesElement = $('#AddMakes');, it should be AddMake instead of AddMakes.Change to:
var AddMakesElement = $('#AddMake');
2.Be sure your partial view located in one of the following location:
/Areas/AdminPortal/Views/Makes/_MakesPartial.cshtml
/Areas/AdminPortal/Views/Shared/_MakesPartial.cshtml
/Views/Shared/_MakesPartial.cshtml
I am working on a ASP.NET Core CRUD applciation using modal popup i have a master detail models Stock and Article. i used this code to display the modal popup:
StockController:
public IActionResult Index()
{
List<Category> categories = _dbcontext.Category.ToList();
ViewBag.ListCategories = new SelectList(categories, "CategoryId", "CategoryName");
List<Stock> AllStocks = _dbcontext.Stock.ToList();
return View(AllStocks);
}
[HttpGet]
public IActionResult Create()
{
Stock stock = new Stock();
stock.Articles.Add(new Article() { ArticleId = 1 });
return View("_AddStockPartialView", stock);
}
[HttpPost]
public IActionResult Create(Stock stock)
{
if (stock != null)
{
_dbcontext.Stock.Add(stock);
_dbcontext.SaveChanges();
return RedirectToAction("Index");
}
return View();
}
Index.cshtml:
#model IEnumerable<Stock>
#{
ViewData["Title"] = "Index";
Layout = "~/Views/Shared/_Theme.cshtml";
}
<div class="row">
<div class="col-md-12">
<div class="card">
<div class="card-header">
<h3 class="card-title">Stock</h3>
<div class="card-tools">
<button type="button" class="btn btn-info" data-toggle="modal" data-target="#addStock" onclick="GetDetails()">
<i class="fa fa-plus"></i>
Ajouter
</button>
</div>
</div>
<div class="card-body" id="display">
<table class="table table-bordered table-hover">
.....
</table>
</div>
</div>
</div>
</div>
<script>
function GetDetails() {
$.ajax({
type: "Get",
url: "/Stock/Create",
success: function (res) {
$("#display").html(res);
$("#addStock").modal('show');
}
});
}
</script>
_AddStockPartialView.cshtml:
#model GestionStock.Models.Stock
#{
ViewData["Title"] = "_AddStockPartialView";
}
<div class="modal fade " role="dialog" tabindex="-1" id="addStock" aria-labelledby="addStockLabel" aria-hidden="true" data-backdrop="static" data-keyboard="false">
<div class="modal-dialog modal-dialog-scrollable" role="document">
<div class="modal-content">
<div class="modal-header">
<h5>Stock</h5>
</div>
<div class="modal-body">
<form asp-action="Create" method="post">
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
<div class="form-group">
<label asp-for="CategoryId" class="control-label"></label>
<select asp-for="CategoryId" class="form-control" asp-items="ViewBag.ListCategories"></select>
<span asp-validation-for="CategoryId" class="text-danger"></span>
</div>
.......
<table class="table table-striped" id="articleTable">
<thead>
<tr>
<th>Numero serie</th>
<th>Marque</th>
<th>etat</th>
</tr>
</thead>
<tbody>
#for (int i = 0; i < Model.Articles.Count; i++)
{
<tr>
<td>
#Html.EditorFor(x => x.Articles[i].NumeroSerie, new { htmlAttributes = new { #class = "form-control" } })
</td>
<td>
#Html.EditorFor(x => x.Articles[i].Marque, new { htmlAttributes = new { #class = "form-control" } })
</td>
<td>
#Html.EditorFor(x => x.Articles[i].Etat, new { htmlAttributes = new { #class = "form-control" } })
</td>
</tr>
}
</tbody>
</table>
<input type="hidden" id="hdnLastIndex" value="0" />
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-dismiss="modal" #*onclick="javascript:window.location.reload()"*#>Annuler</button>
<button type="submit" class="btn btn-primary">Sauvegarder</button>
</div>
</form>
</div>
</div>
</div>
</div>
Everything works fine and the modal popup is displaying with master detail models. But when i click te button to display the modal popup, the background view (Index.cshtml) is changed like the picture below and the CategoryId SelectList isn't populating:
Although this is the index view which is supposed to display in the background of the modal popup:
So why is Index view chaning when displaying the modal popup?
Below is a work demo, you can refer to it.
In controller, make some change in create action.
[HttpGet]
public IActionResult Create()
{
List<Category> categories = _dbcontext.Category.ToList();
ViewBag.ListCategories = new SelectList(categories, "CategoryId", "CategoryName");
Stock stock = new Stock();
stock.Articles.Add(new Article() { ArticleId = 1 });
return PartialView("_AddStockPartialView", stock);
}
2.In the Index view:
remove table (<table>) before <div class="card-body" id="display">
3.In the _Theme.cshtml, check and make sure you already have below code:
<link rel="stylesheet" href="~/lib/bootstrap/dist/css/bootstrap.min.css" />
<link rel="stylesheet" href="~/css/site.css" asp-append-version="true" />
<link rel="stylesheet" href="~/GestionStock.styles.css" asp-append-version="true" />
...
<script src="~/lib/jquery/dist/jquery.min.js"></script>
<script src="~/lib/bootstrap/dist/js/bootstrap.bundle.min.js"></script>
4.result(I use my model data to show the table) :
I am trying to do CRUD operations on a Master Detail model Department and Employee using modal popup. This is the code I used:
DepartmentController:
[HttpGet]
public IActionResult Create()
{
Department department= new Department();
department.Employees.Add(new Employee() { EmployeeId = 1 });
department.Employees.Add(new Employee() { EmployeeId = 2 });
department.Employees.Add(new Article() { EmployeeId = 3 });
return PartialView("_AddDepartmentPartialView",department);
}
[HttpPost]
public IActionResult Create(Department department)
{
if (department != null)
{
_dbcontext.Department.Add(department);
_dbcontext.SaveChanges();
return RedirectToAction("Index");
}
return View();
}
Index.cshtml:
#model IEnumerable<Department>
#{
ViewData["Title"] = "Index";
Layout = "~/Views/Shared/_Theme.cshtml";
}
<div>
<div class="row">
<div class="col-md-12">
<div class="card">
<div class="card-header">
<h3 class="card-title">Department</h3>
<div class="card-tools">
<button type="button" class="btn btn-info" data-toggle="modal" data-target="#addDepartment">
<i class="fa fa-plus"></i>
Ajouter
</button>
</div>
</div>
<div class="card-body">
.....
</div>
</div>
</div>
</div>
</div>
#await Html.PartialAsync("_AddDepartmentPartialView", new Department())
_AddDepartmentPartialView.cshtml:
#model Department
#{
ViewData["Title"] = "_AddDepartmentPartialView";
}
<div class="modal fade " role="dialog" tabindex="-1" id="addDepartment" aria-labelledby="addDepartmentLabel" aria-hidden="true">
<div class="modal-dialog modal-dialog-scrollable" role="document">
<div class="modal-content">
<div class="modal-header">
.....
</div>
<div class="modal-body" >
.......
<form asp-action="Create" method="post">
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
<table class="table">
<thead>
<tr>
<th>Employee name</th>
<th>Profession</th>
<th>Email</th>
</tr>
</thead>
<tbody>
#for (int i = 0; i < Model.Employees.Count; i++)
{
<tr>
<td>
#Html.EditorFor(x => x.Employees[i].EmployeeName, new { htmlAttributes = new { #class = "form-control" } })
</td>
<td>
#Html.EditorFor(x => x.Employees[i].Profession, new { htmlAttributes = new { #class = "form-control" } })
</td>
<td>
#Html.EditorFor(x => x.Employees[i].Email, new { htmlAttributes = new { #class = "form-control" } })
</td>
</tr>
}
</tbody>
</table>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-dismiss="modal">Annuler</button>
<button type="submit" class="btn btn-primary" >Sauvegarder</button>
</div>
</form>
</div>
</div>
</div>
</div>
But this PartialView displays only the inputs of the Department model and it doesn't displays the rows of the table to insert employees records (it displays only the head of the table).
So, how to pass both Department and Employee to the partial view?
UPDATE
I tried the solution of #Xinran Shen, the modal popup finally appears with both models Department and Employee. But on Ajouter click, the Index view behind the modal popup changed (a table of all departments is supposed to appear but the nothing is displayed), also i have a Dropdownlist in the modal popup it appears empty and it doesn't populated. I think because i am using a custom Layout page but i couldn't find where is the problem exactly. Any help??
In Index.cshtml, You use:
#await Html.PartialAsync("_AddDepartmentPartialView", new Department())
to load the partial View, It will not create partial view by Create get method. And you just pass new Department() into partial View, The Department passed into view is null, So it doesn't display the rows of table.
You can set an onclick event on Ajouter button, When user click the button, It will access Create get method and Initialize Department with the initial value, Then return partial view to the index view.
.............
<button type="button" class="btn btn-info" data-bs-toggle="modal" data-bs-target="#addDepartment" onclick="GetDetails()">
<i class="fa fa-plus"></i>
Ajouter
</button>
..........
<div class="card-body" id="Body">
</div>
...............
<script>
function GetDetails() {
$.ajax({
type: "Get",
url: "/Home/Create",
success: function (res) {
$("#Body").html(res);
$("#addDepartment").modal('show');
}
});
}
</script>
Then when you click button, It will show the full table.
I created an Identity project, using .net core 3 version. I generated a Migrations file, and Startup.cs with some configuration.
public void ConfigureServices(IServiceCollection services)
{
services.AddDbContext<ApplicationDbContext>(options =>
options.UseSqlServer(
Configuration.GetConnectionString("DefaultConnection")));
services.AddDefaultIdentity<IdentityUser>(options => options.SignIn.RequireConfirmedAccount = true)
.AddEntityFrameworkStores<ApplicationDbContext>();
services.AddControllersWithViews();
services.AddRazorPages();
}
But how to modify the rules for creating passwords during registration?
enter image description here
Here is a completed custom validation demo, you can select the parts you need to change:
1.Create UserLoginDto.cs class and set validation for email, password and create UserRegistrationDto.cs class to register and set validation for all properties
public class UserRegistrationDto
{
[Required(ErrorMessage = "Name is required")]
[StringLength(100)]
public string Name { get; set; }
[EmailAddress(ErrorMessage = "Invalid email address")]
[Required(ErrorMessage = "Email is required")]
public string Email { get; set; }
[Required(ErrorMessage = "Password is required")]
[RegularExpression(#"^[a-zA-Z''-'\s]{1,40}$",
ErrorMessage = "Characters are not allowed.")]
public string Password { get; set; }
[Required(ErrorMessage = "Confirm password is required")]
[Compare("Password", ErrorMessage = "The Password and Confirm Password do not match.")]
public string ConfirmPassword { get; set; }
public string PhoneNumber { get; set; }
}
public class UserLoginDto
{
[Required(ErrorMessage = "Email is required")]
[EmailAddress(ErrorMessage = "Invalid email address")]
public string Email { get; set; }
[Required(ErrorMessage = "Password is required")]
[DataType(DataType.Password)]
public string Password { get; set; }
[Display(Name = "Remember me")]
public bool RememberMe { get; set; }
}
2.Inject the UserManager and SignInManager identity classes into their constructors.
public class AccountController : Controller
{
private readonly UserManager<IdentityUser> userManager;
private readonly SignInManager<IdentityUser> signInManager;
public AccountController(UserManager<IdentityUser> userManager,
SignInManager<IdentityUser> signInManager)
{
this.userManager = userManager;
this.signInManager = signInManager;
}
3.Create a register and login method like this
public class AccountController : Controller
{
private readonly UserManager<IdentityUser> userManager;
private readonly SignInManager<IdentityUser> signInManager;
public AccountController(UserManager<IdentityUser> userManager,
SignInManager<IdentityUser> signInManager)
{
this.userManager = userManager;
this.signInManager = signInManager;
}
[HttpGet, AllowAnonymous]
public IActionResult Register()
{
UserRegistrationDto model = new UserRegistrationDto();
return View(model);
}
[HttpPost, AllowAnonymous]
public async Task<IActionResult> Register(UserRegistrationDto request)
{
if (ModelState.IsValid)
{
var userCheck = await userManager.FindByEmailAsync(request.Email);
if (userCheck == null)
{
var user = new IdentityUser
{
UserName = request.Email,
NormalizedUserName = request.Email,
Email = request.Email,
PhoneNumber = request.PhoneNumber,
EmailConfirmed = true,
PhoneNumberConfirmed = true,
};
var result = await userManager.CreateAsync(user, request.Password);
if (result.Succeeded)
{
return RedirectToAction("Login");
}
else
{
if (result.Errors.Count() > 0)
{
foreach (var error in result.Errors)
{
ModelState.AddModelError("message", error.Description);
}
}
return View(request);
}
}
else
{
ModelState.AddModelError("message", "Email already exists.");
return View(request);
}
}
return View(request);
}
[HttpGet]
[AllowAnonymous]
public IActionResult Login()
{
UserLoginDto model = new UserLoginDto();
return View(model);
}
[HttpPost]
[AllowAnonymous]
public async Task<IActionResult> Login(UserLoginDto model)
{
if (ModelState.IsValid)
{
var user = await userManager.FindByEmailAsync(model.Email);
if (user != null && !user.EmailConfirmed)
{
ModelState.AddModelError("message", "Email not confirmed yet");
return View(model);
}
if (await userManager.CheckPasswordAsync(user, model.Password) == false)
{
ModelState.AddModelError("message", "Invalid credentials");
return View(model);
}
var result = await signInManager.PasswordSignInAsync(model.Email, model.Password, model.RememberMe, true);
if (result.Succeeded)
{
await userManager.AddClaimAsync(user, new Claim("UserRole", "Admin"));
return RedirectToAction("Dashboard");
}
else if (result.IsLockedOut)
{
return View("AccountLocked");
}
else
{
ModelState.AddModelError("message", "Invalid login attempt");
return View(model);
}
}
return View(model);
}
[Authorize]
public IActionResult Dashboard()
{
return View();
}
public async Task<IActionResult> Logout()
{
await signInManager.SignOutAsync();
return RedirectToAction("login", "account");
}
4.Create the Register.cshtml view
#model UserRegistrationDto
#{
ViewData["Title"] = "Register";
Layout = "~/Views/Shared/_Layout.cshtml";
}
<div class="container">
<h1>Register</h1>
#Html.ValidationSummary()
<form asp-action="Register" asp-controller="Account" method="post">
<div class="registerdiv">
<div class="form-group col-sm-12">
<label asp-for="#Model.Name" class="col-lg-3 control-label"></label>
<br>
<div class="col-lg-9">
#Html.TextBoxFor(m => m.Name, new { placeholder = "First Name", #class = "form-control" })
#Html.ValidationMessageFor(m => m.Name)
</div>
</div>
<div class="form-group col-sm-12">
<label asp-for="#Model.Email" class="col-lg-3 control-label"></label>
<br>
<div class="col-lg-9">
#Html.TextBoxFor(m => m.Email, new { placeholder = "Email", #class = "form-control" })
#Html.ValidationMessageFor(m => m.Email)
</div>
</div>
<div class="form-group col-sm-12">
<label asp-for="#Model.PhoneNumber" class="col-lg-3 control-label"></label>
<br>
<div class="col-lg-9">
#Html.TextBoxFor(m => m.PhoneNumber, new { placeholder = "Phone Number", #class = "form-control" })
#Html.ValidationMessageFor(m => m.PhoneNumber)
</div>
</div>
<div class="form-group col-sm-12">
<label asp-for="#Model.Password" class="col-lg-3 control-label"></label>
<br>
<div class="col-lg-9">
#Html.TextBoxFor(m => m.Password, new { placeholder = "Password", #class = "form-control" })
#Html.ValidationMessageFor(m => m.Password)
</div>
</div>
<div class="form-group col-sm-12">
<label asp-for="#Model.ConfirmPassword" class="col-lg-3 control-label"></label>
<br>
<div class="col-lg-9">
#Html.PasswordFor(m => m.ConfirmPassword, new { placeholder = "Confirm Password", #class = "form-control" })
#Html.ValidationMessageFor(m => m.ConfirmPassword)
</div>
</div>
<div class="form-group">
<div class="col-sm-12 btn-submit">
<button type="submit" class="btn btn-success">Sign Up</button>
</div>
</div>
</div>
</form>
</div>
<style>
.validation-summary-errors,.field-validation-error {
color: red;
}
</style>
5.Create the Login.cshmt view
#model UserLoginDto
#{
ViewData["Title"] = "Login";
Layout = "~/Views/Shared/_Layout.cshtml";
}
<div class="container">
<h1>Login</h1>
#Html.ValidationSummary()
<form asp-action="Login" asp-controller="Account" method="post">
<div class="logindiv">
<div class="form-group col-sm-12">
<label asp-for="#Model.Email" class="col-lg-3 control-label"></label>
<br>
<div class="col-lg-9">
#Html.TextBoxFor(m => m.Email, new { placeholder = "Email", #class = "form-control" })
#Html.ValidationMessageFor(m => m.Email)
</div>
</div>
<div class="form-group col-sm-12">
<label asp-for="#Model.Password" class="col-lg-3 control-label"></label>
<br>
<div class="col-lg-9">
#Html.PasswordFor(m => m.Password, new { placeholder = "Password", #class = "form-control" })
#Html.ValidationMessageFor(m => m.Password)
</div>
</div>
<div class="form-group">
<div class="col-sm-12 btn-submit">
<button type="submit" class="btn btn-success">Login</button>
<a asp-action="Register" asp-controller="account">Don't have an account?Click to Register</a>
</div>
</div>
</div>
</form>
</div>
6.Create a partial view of _LoginPartial.cshmtl, display the login user name, and the logout button will appear after logging in to the website
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>#ViewData["Title"] - WebApplication221</title>
<link rel="stylesheet" href="~/lib/bootstrap/dist/css/bootstrap.min.css" />
<link rel="stylesheet" href="~/css/site.css" />
</head>
<body>
<header>
<nav class="navbar navbar-expand-sm navbar-toggleable-sm navbar-light bg-white border-bottom box-shadow mb-3">
<div class="container">
<a class="navbar-brand" asp-area="" asp-controller="Home" asp-action="Index">WebApplication221</a>
<button class="navbar-toggler" type="button" data-toggle="collapse" data-target=".navbar-collapse" aria-controls="navbarSupportedContent"
aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
<div class="navbar-collapse collapse d-sm-inline-flex flex-sm-row-reverse">
<partial name="_LoginPartial" />
<ul class="navbar-nav flex-grow-1">
<li class="nav-item">
<a class="nav-link text-dark" asp-area="" asp-controller="Home" asp-action="Index">Home</a>
</li>
<li class="nav-item">
<a class="nav-link text-dark" asp-area="" asp-controller="Home" asp-action="Privacy">Privacy</a>
</li>
</ul>
</div>
</div>
</nav>
</header>
<div class="container">
<main role="main" class="pb-3">
#RenderBody()
</main>
</div>
<footer class="border-top footer text-muted">
<div class="container">
© 2022 - WebApplication221 - <a asp-area="" asp-controller="Home" asp-action="Privacy">Privacy</a>
</div>
</footer>
<script src="~/lib/jquery/dist/jquery.min.js"></script>
<script src="~/lib/bootstrap/dist/js/bootstrap.bundle.min.js"></script>
<script src="~/js/site.js" asp-append-version="true"></script>
#RenderSection("Scripts", required: false)
</body>
</html>
7.Set the custom redirect URL path from ConfigureServices in the Startup.cs class.
public void ConfigureServices(IServiceCollection services)
{
services.AddDbContext<ApplicationDbContext>(options =>
options.UseSqlServer(
Configuration.GetConnectionString("DefaultConnection")));
services.AddDefaultIdentity<IdentityUser>(options => options.SignIn.RequireConfirmedAccount = true)
.AddEntityFrameworkStores<ApplicationDbContext>();
services.ConfigureApplicationCookie(options =>
{
options.LoginPath = $"/account/login";
options.LogoutPath = $"/account/logout";
options.AccessDeniedPath = $"/account/accessDenied";
});
services.AddControllersWithViews();
services.AddRazorPages();
}
8.Result:
Technology Info:
Framework = Asp.Net Core 3.1
IDE = VisualStudio 2019
Problem:
I have a controller with Update and Delete Action Methods. I have UpdateView and DeleteView from where I need to redirect to the respective controller. I have implemented a button that can submit the form. Still I'm facing HTTP ERROR 405 Issues with PUT & DELETE. Can somebody help me to resolve this issue. Thanks in advance
Controller:
[HttpPut]
[ActionName("ModifyEmployee")]
public IActionResult ModifyEmployee(int employeeId, Malips.Data.Employee employee)
{
if (ModelState.IsValid)
{
Malips.Data.Employee employeeDetail = _hrService.EmployeeSystem.UpdateEmployee(employee);
return View("GetEmployee", employeeDetail);
}
return View();
}
[HttpDelete]
public IActionResult DeleteEmployee(int employeeId)
{
_hrService.EmployeeSystem.DeleteEmployee(employeeId);
return View("Index");
}
UpdateView:
#model Employee
#{
ViewBag.Title = "Modify Employee";
}
<div>
<form asp-controller="Hr" asp-action="ModifyEmployee" asp-route-employeeId="#Model.EmpId">
<div class="form-group">
<div asp-validation-summary="All" class="text-danger">
</div>
</div>
#Html.HiddenFor(e => e.EmpId)
<div class="form-group row">
<label asp-for="FirstName" class="col-sm-2">First Name</label>
<input asp-for="FirstName" class="col-sm-10" />
<span asp-validation-for="FirstName" class="text-danger"></span>
</div>
<button type="submit" class="btn btn-info">Update</button>
</form>
</div>
DeleteView:
<form asp-controller="Hr" asp-action="DeleteEmployee" asp-route-employeeId="#Model.EmpId">
<div class="row card" style="width: 18rem;">
<div class="card-body">
<label hidden="hidden">#Model.EmpId</label>
<h5 class="card-title">#Model.FirstName #Model.LastName</h5>
<p class="card-text">#Model.Salary </p>
<button type="submit" class="btn btn-danger">Delete</button>
</div>
</div>
</form>
The current HTML5 does not support PUT or DELETE in forms. You can use it with ajax or httpclient only. Or you can try #Html.BeginForm razor page template if it is possible. #Html.BeginForm has post metod choice.
For now remove [ActionName("ModifyEmployee")], [httpput] and [httpdelete] from your action attributes.
And change
public IActionResult ModifyEmployee(int employeeId, Malips.Data.Employee employee)
to:
public IActionResult ModifyEmployee(Employee employee)
since you don't use and don't need emploeeId. And remove asp-route-employeeId="#Model.EmpId" from ModifyEmployee view too.
Like #Sergey said,You can use it with ajax.Below is a working demo.
UpdateView:
<div>
<form id="update" asp-controller="Hr" asp-action="ModifyEmployee">
<div class="form-group">
<div asp-validation-summary="All" class="text-danger">
</div>
</div>
#Html.HiddenFor(e => e.EmpId)
<div class="form-group row">
<label asp-for="FirstName" class="col-sm-2">First Name</label>
<input asp-for="FirstName" class="col-sm-10" />
<span asp-validation-for="FirstName" class="text-danger"></span>
</div>
<div class="form-group row">
<label asp-for="LastName" class="col-sm-2">First Name</label>
<input asp-for="LastName" class="col-sm-10" />
<span asp-validation-for="LastName" class="text-danger"></span>
</div>
<button type="submit" id="submit" class="btn btn-info">Update</button>
</form>
</div>
#section scripts
{
<script>
$("#submit").click(function (e) {
e.preventDefault();
var data = $('#update').serialize();
$.ajax({
type: "PUT",
url: "/hr/Modifyemployee",
data: data,
success: function (response) {
window.location.href = response.redirectToUrl;
}
});
})
</script>
}
ModifyEmployee Action
[HttpPut]
[ActionName("ModifyEmployee")]
//remember add this.
[ValidateAntiForgeryToken]
public async Task<IActionResult> ModifyEmployee(Employee employee)
{
//....
return new JsonResult(new { redirectToUrl = Url.Action("Index", "Hr") });
}
DeleteView:
<div>
<form id="delete" asp-controller="Hr" asp-action="DeleteEmployee" asp-route-employeeId="#Model.EmpId">
<div class="row card" style="width: 18rem;">
<div class="card-body">
<label hidden="hidden">#Model.EmpId</label>
<h5 class="card-title">#Model.FirstName #Model.LastName</h5>
<button type="submit" id="submit" class="btn btn-danger">Delete</button>
</div>
</div>
</form>
</div>
#section scripts
{
$("#submit").click(function (e) {
e.preventDefault();
$.ajax({
type: "delete",
url: "/hr/DeleteEmployee?id=" + #Model.EmpId,
success: function (response) {
window.location.href = response.redirectToUrl;
}
});
})
</script>
}
DeleteEmployee Action
[HttpDelete]
public async Task<IActionResult> DeleteEmployee(int id)
{
//......
return new JsonResult(new { redirectToUrl = Url.Action("Index", "hr") });
}
Test Result: