ASP.NET Core Razor Page, code behind method not being triggered - asp.net-core

I have a C# Razor Pages project.
I created a Login view in the following structure:
- Pages
- Account
- Login.cshtml
This is the code for my Login view
#page "{handler?}"
#model HAL_WEB.Pages.LoginModel
#{
Layout = "_LayoutLogin";
}
<section class="section register min-vh-100 d-flex flex-column align-items-center justify-content-center py-4">
<div class="container">
<div class="row justify-content-center">
<div class="col-lg-4 col-md-6 d-flex flex-column align-items-center justify-content-center">
<div class="d-flex justify-content-center py-4">
<a href="index.html" class="logo d-flex align-items-center w-auto">
<img src="assets/img/teamtruetech_logo.png" alt="">
<span class="d-none d-lg-block">HAL Admin</span>
</a>
</div><!-- End Logo -->
<div class="card mb-3">
<div class="card-body">
<div class="pt-4 pb-2">
<h5 class="card-title text-center pb-0 fs-4">Login to Your Account</h5>
<p class="text-center small">Enter your username & password to login</p>
</div>
<form id="login-form" class="row g-3 needs-validation" novalidate>
<div class="col-12">
<label for="yourUsername" class="form-label">Username</label>
<div class="input-group has-validation">
<span class="input-group-text" id="inputGroupPrepend"></span>
<input type="text" name="username" class="form-control" id="yourUsername" required>
<div class="invalid-feedback">Please enter your username.</div>
</div>
</div>
<div class="col-12">
<label for="yourPassword" class="form-label">Password</label>
<input type="password" name="password" class="form-control" id="yourPassword" required>
<div class="invalid-feedback">Please enter your password!</div>
</div>
<div class="col-12">
<div class="form-check">
<input class="form-check-input" type="checkbox" name="remember" value="true" id="rememberMe">
<label class="form-check-label" for="rememberMe">Remember me</label>
</div>
</div>
<div class="col-12">
<button class="btn btn-primary w-100" type="submit">Login</button>
</div>
#* <div class="col-12">
<p class="small mb-0">Don't have account? Create an account</p>
</div>*#
</form>
</div>
</div>
</div>
</div>
</div>
</section>
#section Scripts {
<script src="~/assets/js/loginpage.js"></script>
}
And this is the code behind:
using HAL_WEB.Data;
using Microsoft.AspNetCore.Authentication.Cookies;
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
using System.Security.Claims;
namespace HAL_WEB.Pages
{
public class LoginModel : PageModel
{
private readonly ApplicationDBContext _dbContext;
public LoginModel([FromServices] ApplicationDBContext dbContext)
{
_dbContext = dbContext;
}
public void OnGet()
{
}
public async Task<IActionResult> OnPostLoginAsync(string username, string password)
{
// Check if the provided credentials are valid
if (IsValidCredentials(username, password))
{
// If the credentials are valid, log the user in
await HttpContext.SignInAsync(
CookieAuthenticationDefaults.AuthenticationScheme,
new ClaimsPrincipal(new ClaimsIdentity(new[] { new Claim(ClaimTypes.Name, username) }, CookieAuthenticationDefaults.AuthenticationScheme)),
new AuthenticationProperties
{
IsPersistent = true, // Set this to true if you want the user to stay logged in after closing the browser
ExpiresUtc = DateTime.UtcNow.AddDays(7) // Set the expiration time for the cookie
});
// Redirect the user to the home page
return RedirectToPage("/Home");
}
else
{
// If the credentials are invalid, show an error message
ModelState.AddModelError(string.Empty, "Invalid username or password.");
return Page();
}
}
private bool IsValidCredentials(string username, string password)
{
// Replace this with your own validation logic
return username == "admin" && password == "password";
}
public IActionResult OnPostLoginTestAsync()
{
return new JsonResult(true);
}
}
In my Javascript file I tried to call the method OnPostLoginTestAsync or OnPostLoginAsync without success.
I'm getting a "Bad Request 400" error:
This is my Javascript Axios code for calling the method:
// Use Axios to send a POST request to the server with the form data
axios.post('/Account/Login?handler=login', {
username,
password,
})
.then((response) => {
// If the request is successful, redirect the page
window.location.href = '/home';
})
.catch((error) => {
// If there is an error, log it to the console
console.error(error);
});
Any clue what am I doing wrong? I'm going to /Account/Login?handler=login because the call is a Post and what I think is that the method OnPostLoginAsync should be executed.
UPDATE
I found something interesting, I created the following Get method:
public IActionResult OnGetTestAsync()
{
return new JsonResult(true);
}
And in my Javascript, I changed the Axios url to be:
axios.get('/Account/Login?handler=test')
.then(function (response) {
})
.catch(function (error) {
// Handle the error response
});
And I could get the method executed! But when I change the method name back to:
OnPostTestAsync
and my Axios to:
axios.post('/Account/Login?handler=test')
.then(function (response) {
})
.catch(function (error) {
// Handle the error response
});
It never gets executed and I get 400 Bad Request. Any clue?

Related

drop down display empty rows although i get data filled on RefreshDropDownList function?

I work on blazor on .net core 7 . i face issue when display drop down server type
issue is drop down server type display empty although I get data on function RefreshDropDownList(); .
I work on blazor page server names data and inside this page there are drop down servertype
so server type drop down exist on another page ServersNames
server type drop down display empty although function RefreshDropDownList() return 4 items data .
so what is issue and How to solve it ? .
controller action fill drop down is
[HttpGet]
public IActionResult GetAll()
{
return Ok(_IserverTypeService.GetAll());
}
I test action GetAll on controller service type and it return data without any issue
on blazor ui :
<h1>Server Name</h1>
<button type="button" class="btn btn-primary m-2 float-end" data-bs-toggle="modal" data-bs-target="#exampleModal" #onclick="AddClick">
Add ServerNames
</button>
<div class="modal fade" id="exampleModal" tabindex="-1" aria-labelledby="exampleModalLabel" aria-hidden="true">
<div class="modal-dialog modal-lg modal-dialog-centered">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="exampleModalLabel">
#ModalTitle
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</h5>
</div>
<div class="modal-body">
<div class="d-flex flex-row bd-highlight mb-3">
<div class="p-2 w-100 bd-highlight">
<div class="form-group row">
<label for="example-text-input" class="col-3 col-form-label">Server Type</label>
<div class="col-9">
#* <input type="text" class="form-control" #bind="server_Type" />*#
<select class="form-select" #bind="server_Type">
#foreach (var servertype in ServerType)
{
<option value="#servertype.serverTypeId">
#servertype.serverType
</option>
}
</select>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
#code
{
public class ServerNamesClass
{
public string server_Type { get; set; }
}
public class ServerTypesClass
{
public int serverTypeId { get; set; }
public string serverType { get; set; }
}
private IEnumerable<ServerTypesClass> ServerType = Array.Empty<ServerTypesClass>();
protected override async Task OnInitializedAsync()
{
await RefreshDropDownList();
}
private async Task RefreshDropDownList()
{
var request = new HttpRequestMessage(HttpMethod.Get, config["API_URL"] + "ServerTypes");
var client = ClientFactory.CreateClient();
var response = await client.SendAsync(request);
using var responsestream = await response.Content.ReadAsStreamAsync();
ServerType = await JsonSerializer.DeserializeAsync<IEnumerable<ServerTypesClass>>(responsestream);
ServerType = Array.Empty<ServerTypesClass>();
}
private async void AddClick()
{
await RefreshDropDownList();
}
In your RefreshDropDownList() you overwrite your ServerType IEnumerable with an empty list: ServerType = Array.Empty<ServerTypesClass>();. This means that your deserialized data will always be overwritten with an empty list.

How can I show error message in ASP.NET Core MVC?

I want to show an error message when login failed.
This is my html markup:
<form class="modal-content animate" action="/Login/SignInTeacher" method="post">
#Html.AntiForgeryToken()
<div class="imgcontainer">
<span onclick="document.getElementById('id02').style.display='none'" class="close" title="Close Modal">×</span>
<img src="~/images/Login4.png" alt="Avatar" class="img-fluid" style="height: 300px;">
</div>
<div class="container">
<input type="text" class="form-control" name="Email" placeholder="Email Adresiniz" aria-label="Username" aria-describedby="basic-addon1" style="font-size: medium;">
<br>
<input type="password" class="form-control" name="Parola" placeholder="Şifreniz" aria-label="Username" aria-describedby="basic-addon1" style="font-size: medium;">
<br>
<button type="submit" class="btn btn-block btn-outline-success btn-lg">Login</button>
<br>
<label style="font-size: medium; margin-left: 0%;">
<input type="checkbox" checked="checked" name="remember"> Remember me
</label>
</div>
<div class="container" style="background-color:#f1f1f1">
<button type="button" onclick="document.getElementById('id02').style.display='none'" class="btn btn-lg btn-danger">Cancel</button>
<span class="psw">Forgot password?</span>
</div>
</form>
This is my controller code
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> SignInTeacher(Teacher t)
{
SHA1 sha = new SHA1CryptoServiceProvider();
string willbeEncrypted = s.Parola;
string encrypted = Convert.ToBase64String(sha.ComputeHash(Encoding.UTF8.GetBytes(willbeEncrypted)));
var info = c.Teachers.FirstOrDefault(x => x.Email == s.Email && x.Parola == encrypted);
if (info != null)
{
var claims = new List<Claim>
{
new Claim(ClaimTypes.Name,s.Email)
};
var userIdentity = new ClaimsIdentity(claims, "Login");
ClaimsPrincipal claimsPrincipal = new ClaimsPrincipal(userIdentity);
await HttpContext.SignInAsync(claimsPrincipal);
var value = from deger in c.Teachers
where deger.Email == s.Email
select deger.Email;
var nameuser = value;
return RedirectToAction("Main", "Home", new { user = nameuser });
}
return RedirectToAction("Index", "Home");
}
When user logs in successfully, the main page opens; when login fails, the main page does not open return same page (refresh) but I can't show the error message instead of page refresh like this "Username or password is wrong".
I tried it with viewbag but that did not work because this command return RedirectToAction("Index", "Home"); prevent the viewbag message.
when login failed main page does not open return same page(refresh) but I cant achieve show the error message instead of page refresh like this "Username or password is wronng".
To achieve your requirement, you can try to pass error message through TempData, like below.
TempData["ErrorMes"] = "Username or password is wronng";
return RedirectToAction("Index", "Home");
Display error message in Index page
<span class="text-danger">#TempData["ErrorMes"]</span>
I recommend to use ModelState.AddModelError like below, it'll return to the same login view with model error and model state will be invalid
Example :
if(isLoginSuccess)
{
return RedirectToAction("Main", "Home");
}else
{
ModelState.AddModelError("InvalidLogin", "Invalid Login Attempt");
return View(loginViewModel);
}

How to show error message in modal dialog from ASP.NET Core?

I have ASP.NET Core MVC project. In my core project, I am using fluent validation like this:
public class AddEntityViewModelValidator: AbstractValidator<AddEntityViewModel>
{
public AddEntityViewModelValidator()
{
RuleFor(x => x.Name)
.NotEmpty()
.WithMessage("You must enter name.");
}
}
My controller looks like this:
[HttpPost]
public async Task<IActionResult> CreateEntity(AddEntityViewModel addEntityViewModel)
{
try
{
if (!ModelState.IsValid)
{
var errors = ModelState.Values.SelectMany(v => v.Errors.Select(x => x.ErrorMessage)).ToList();
foreach(var error in errors)
{
ModelState.AddModelError("Error: ", error);
}
return View(addEntityViewModel);
}
await _businessLogic.CreateEntity(addEntityViewModel.Entity);
return View(addEntityViewModel);
}
catch (Exception)
{
return View(addEntityViewModel);
}
}
When user doesn't enter the name in model dialog, fluent validation do the work. This list of errors (var errors in controller) contains this error, so this part is working. But in my cshmtl modal-dialog this error message is not showing anywhere.
I have the the button for opening modal dialog:
<div id="PlaceHolderHere"></div>
<button type="button" class="btn btn-success" data-toggle="ajax-modal" data-target="#addEntity"
data-url="#Url.Action("AddEntity", "Entity", new { entityId = Model.Id})">
Add entity
</button>
and my jquery code:
$(function () {
var PlaceHolderElement = $('#PlaceHolderHere');
$('button[data-toggle="ajax-modal"]').click(function (event) {
var url = $(this).data('url');
var decodeUrl = decodeURIComponent(url);
$.get(decodeUrl).done(function (data) {
PlaceHolderElement.html(data);
PlaceHolderElement.find('.modal').modal('show');
})
})
PlaceHolderElement.on('click', '[data-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) {
PlaceHolderElement.find('.modal').modal('hide');
location.reload(true);
})
})
})
Here is my modal-dialog:
#model AddEntityViewModel
<div class="modal fade" id="addEntity">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h2 class="modal-title" id="addEntityLabel">#Model.Title</h3>
</div>
<div class="modal-body">
<form action="CreateEntity">
<div asp-validation-summary="All" class="text-danger wrapper"></div>
<div class="form-group">
<label asp-for="#Model.Entity.Name">Name</label>
<input asp-for="#Model.Entity.Name" class="form-control" />
<span asp-validation-for="#Model.Entity.Name" class="text-danger"></span>
</div>
</form>
</div>
<div class="modal-footer">
<button type="submit" class="btn btn-primary" data-save="modal">Save</button>
<button type="button" class="btn btn-danger" data-dismiss="modal">Close</button>
</div>
</div>
</div>
</div>
So, i have this line:
<div asp-validation-summary="All" class="text-danger wrapper"></div>
but error is still now showing. Any idea how to solve this? Should I change something in my jquery function?

Validation not getting triggered when value is changed

In Aurelia project, I have created a bootstrap modal that will allow users to enter email addresses. At first when the pop-up is triggered, it applies the validation fine. See below image. This is how it looks like when the pop-up is opened for the first time.
Once you enter the validate email address and click on add btn, I am resetting the value of this.setEmail to "" an empty string. So that way users can type new email address to add. But the validation rule that shows the message Email is required is no longer getting triggered. See below example:
See the Plunker link here. Once the page is loaded. Click on the + icon next to email input. It will open a bootstrap modal.
Below is the code and can be seen at above link as well:
email.ts
import { customElement, useView, bindable, bindingMode, inject, observable } from 'aurelia-framework';
import { ValidationRules, ValidationControllerFactory, Validator } from 'aurelia-validation';
#inject(ValidationControllerFactory)
#customElement('email')
#useView('./email.html')
export class Email {
#bindable public modalName: string;
#bindable public modalValue: string;
#bindable public emailAddress: string;
public emailAddresses = [];
#observable public setEmail: string;
public errorMessage: string;
emailController = null;
constructor(factory) {
this.setEmail = '';
this.emailController = factory.createForCurrentScope();
ValidationRules.ensure('setEmail')
.displayName('Email')
.required()
.email()
.on(this);
}
public bind() {
this.emailController.validate();
}
private joinEmails() {
this.emailAddress = this.emailAddresses.join(";");
}
private isUniqueEmail = (email: string) => {
return (this.emailAddresses.indexOf(email) === -1)
}
public addEmail() {
if (this.setEmail) {
if(!this.isUniqueEmail(this.setEmail))
{
this.errorMessage = "You must provide unique email address.";
return;
}
this.emailAddresses.push(this.setEmail);
this.joinEmails();
this.setEmail = '';
}
else
{
this.errorMessage = "You must provide an email address."
}
}
public setEmailChanged(newValue, oldValue) {
console.log({oldValue: oldValue, newValue: newValue});
}
public removeEmail(index) {
this.emailAddresses.splice(index, 1);
this.joinEmails();
console.log(this);
}
}
email.html
<template>
<!-- Modal -->
<div class="modal fade" id="${modalName}" tabindex="-1" role="dialog" aria-labelledby="myModalLabel">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">×</span></button>
<h4 class="modal-title" id="myModalLabel">Add Email Address</h4>
</div>
<div class="modal-body">
<div class="input-group">
<input type="text" id="setEmail" name="setEmail" class="form-control" value.bind="setEmail & validateOnChangeOrBlur" />
<span class="input-group-btn">
<button class="btn btn-primary"
disabled.bind="emailController.errors.length > 0"
click.delegate="addEmail()">Add
</button>
</span>
</div>
<input type="text" value.bind="emailAddress" hidden />
<span class="text-danger" repeat.for="error of emailController.errors">${error.message}</span>
<span class="text-danger" if.bind="errorMessage">${errorMessage}</span>
<div>
<ul class="list-group" if.bind="emailAddresses.length > 0" style="margin-top: 10px;">
<li class="list-group-item" repeat.for="e of emailAddresses">
${e} <span class="glyphicon glyphicon-remove text-danger pull-right" style="cursor: pointer;" click.delegate="removeEmail($index)"></span>
</li>
</ul>
</div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
</div>
</div>
</div>
</div>
</template>
In your addEmail() function after the line this.setEmail = ''; call the validate again with this.emailController.validate();
The validate() method returns a Promise so you may want to handle any rejections as you would normally see this section of the validation docs Validation Controller specifically the sub section 'validate & reset'.
I'm guessing you expected this to happen automatically because of the 2-way binding and the validateOnChangeOrBlur binding behavior the reason it didn't is that the JavaScript setting the value doesn't trigger DOM events so you need to manually call or fire a synthetic event.

Aurelia -- Route Change on Form Submission Issue

Aurelia newbie here and I have hit a wall.
So, this code works just fine and the route change happens, but it only happens after the Submit button on the home.html file is clicked TWICE. On the first Submit button click, I get the following error: ERROR [app-router] Error: Route not found: /anonymous-wow-armory-profile/.
My question is why does it work after two form submissions, but not the first one? I know I am missing something in the process here.
home.html
<template>
<div class="container-fluid">
<div class="row">
<div class="col-md-12 nav-home text-center">
Create Profile
Bug Report
</div>
</div>
<div class="row">
<div class="col-md-12">
<div class="logo">
<img src="dist/assets/images/logo.png" alt="Logo" />
</div>
</div>
</div>
<div class="row row-bottom-pad">
<div class="col-md-4"></div>
<div class="col-md-4">
<div class="profile-creation-box">
<div class="box-padding">
<strong>Masked Armory</strong> is the most well known anonymous World of Warcraft (WoW) profile source in the Real Money Trading (RMT) market. We take everything to the next level with offering alternate gear sets, sorted reputation display, Feat of Strength / Legacy achievement display, and much more!<br /><br />
Come make a profile at Masked Armory today and see that we are the best solution for all of your anonymous WoW Armory profile needs!
</div>
</div>
</div>
<div class="col-md-4"></div>
</div>
<div class="row">
<div class="col-md-4"></div>
<div class="col-md-4 container-bottom-pad">
<div class="profile-creation-box">
<div class="box-padding">
<form class="form-horizontal" role="form" submit.delegate="submit()">
<div class="form-group">
<label class="col-sm-3 control-label">Region</label>
<div class="col-sm-9">
<label class="radio-inline">
<input type="radio" name="region_name" value="us" checked.bind="postData.region"> United States
</label>
<label class="radio-inline">
<input type="radio" name="region_name" value="eu" checked.bind="postData.region"> Europe
</label>
</div>
</div>
<div class="form-group">
<label for="server_name" class="col-sm-3 control-label">Server</label>
<div class="col-sm-9">
<input type="text" class="form-control" id="server_name" placeholder="Server Name" value.bind="postData.serverName">
</div>
</div>
<div class="form-group">
<label for="character_name" class="col-sm-3 control-label">Character</label>
<div class="col-sm-9">
<input type="text" class="form-control" id="character_name" name="character_name" placeholder="Character Name" value.bind="postData.characterName">
</div>
</div>
<div class="form-group">
<div class="col-sm-offset-3 col-sm-9">
<div class="checkbox">
<label>
<input type="checkbox" id="altgear" name="altgear"> Add Alternate Gearset
</label>
</div>
</div>
</div>
<div class="form-group">
<div class="col-sm-offset-3 col-sm-9">
<button type="submit" class="btn btn-danger">Create Armory Profile</button>
</div>
</div>
</form>
</div>
</div>
</div>
<div class="col-md-4"></div>
</div>
</div>
</template>
home.js
import {inject} from 'aurelia-framework';
import {HttpClient} from 'aurelia-http-client';
import {Router} from 'aurelia-router';
#inject(Router)
export class Home {
postData: Object = {};
data: string = '';
code: string = '';
loading: boolean = false;
http: HttpClient = null;
apiUrl: string = 'http://localhost:8000/api/v1';
constructor(router) {
this.http = new HttpClient().configure(x => {
x.withBaseUrl(this.apiUrl);
x.withHeader('Content-Type', 'application/json');
});
this.maRouter = router;
}
submit() {
console.log(this.postData);
this.http.post('/armory', JSON.stringify(this.postData)).then(response => {
this.data = response.content;
this.code = response.statusCode.toString();
this.loading = false;
});
this.maRouter.navigateToRoute('armory', {id: this.data});
}
}
armory.js
import {inject} from 'aurelia-framework';
import {HttpClient} from 'aurelia-http-client';
export class Armory {
postData: Object = {};
data: string = '';
code: string = '';
loading: boolean = false;
http: HttpClient = null;
apiUrl: string = 'http://localhost:8000/api/v1';
profileId: number = 0;
constructor() {
this.loading = true;
this.http = new HttpClient().configure(x => {
x.withBaseUrl(this.apiUrl);
x.withHeader('Content-Type', 'application/json');
});
}
activate(params, routeConfig) {
this.profileId = params.id;
this.getArmoryData();
}
getArmoryData() {
return this.http.get("/armory/" + this.profileId).then(response => {
this.data = response.content;
console.log(this.data);
this.code = response.statusCode.toString();
this.loading = false;
});
}
}
What am I missing here?
Thanks for your help!
Please, provide your router configuration
Anyway I see some issues already. You try to navigate when this.data is not set, just wait for response:
this.http.post('/armory', JSON.stringify(this.postData)).then(response => {
this.data = response.content;
this.code = response.statusCode.toString();
this.loading = false;
this.maRouter.navigateToRoute('armory', {id: this.data});
});
and we do activate page only if this.getArmoryData() succeed here (if needed), also canActivate() maybe used too
activate(params, routeConfig) {
this.profileId = params.id;
return this.getArmoryData();
}
also would be better to set this.loading = true;, inside armory .activate() and in home.js in submit() before sending data