Pass email to ResendEmailConfirmation model/view - Identity - asp.net-core

I'm trying to pass the user's email to Identity's ResendEmailConfirmation.cshtml class from the register page, so that it is displayed on view in the Email Input box.
Register Page - The link to redirect the user to the Resend Email Confirmation page
<a asp-area="Identity" asp-page="/Account/resendemailconfirmation" asp-route-email="#Model.Input.Email" class="resend-confirm-email-submit">Resend confirmation email</a>
ResendEmailConfirmation.cshtml - Relevant Parts
public ResendEmailConfirmationModel(UserManager<IdentityUser> userManager, IEmailSender emailSender)
{
_userManager = userManager;
_emailSender = emailSender;
}
[BindProperty]
public InputModel Input { get; set; }
public class InputModel
{
[Required]
[EmailAddress]
public string Email { get; set; }
}
public void OnGet(string email)
{
// My attempt
InputModel inputModel = new InputModel();
inputModel.Email = email;
}
ResendEmailConfirmation View - Email Input Box
<form method="post">
<div asp-validation-summary="All" class="text-danger"></div>
<div class="form-group">
<label asp-for="Input.Email" class="register-heading-style"></label>
<input asp-for="Input.Email" class="form-control" />
<span asp-validation-for="Input.Email" class="text-danger"></span>
</div>
#*<button type="submit" class="btn btn-primary">Resend</button>*#
<button type="submit" class="register-submit"><span>Resend</span></button>
</form>
Thank you

You should use this way to define Input in OnGet():
Register.cshtml.cs to get the email (You didn't show this part of code, so I directly define the value):
public void OnGet()
{
Input =new InputModel()
{
Email = "asd#asd.com"
};
}
Then ResendEmailConfirmation.cshtml.cs to show the email that passed from register page:
public void OnGet(string email)
{
Input = new InputModel() //you get value from Input.Eamil in view, so you should define Input, not inputmodel
{
Email = email
};
}
You do not have to change the razor view pages.
Result:

Related

How to make the form file not required if the path to files already exists in the DB

I have a view model set up as:
public class BookViewModel
{
public int Id { get; set; }
[Display(Name = "Book Name")]
public string Name { get; set; }
public string Path { get; set; }
[Display(Name = "Pdf Book")]
public IFormFile BookPdfFile { get; set; }
}
In the view, I am using the view model properties
<form asp-action="CreateEdit" method="post" enctype="multipart/form-data">
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
<input asp-for="Id" type="hidden" />
<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>
#if (!string.IsNullOrEmpty(Model.BookPath))
{
<div class="form-group">
<label>Uploaded Book:</label>
<a asp-action="Download" asp-route-id="#Model.Id">#Model.Name</a>
</div>
}
<div class="form-group">
<label asp-for="BookPdfFile" class="control-label"></label>
<input class="form-control" type="file" asp-for="BookPdfFile" accept=".pdf">
<span asp-validation-for="BookPdfFile" class="text-danger"></span>
</div>
</form>
Using this View model in the view in this way always asks for the file to be uploaded. If the file is uploaded during the create mode or if it has the file path, how to not ask to make the form file required?
The Book entity is:
public class Book
{
public int Id { get; set; }
[MaxLength(100)]
public string Title { get; set; }
[MaxLength(50)]
public string? Path { get; set; }
public ICollection<BookChapter> Chapters { get; set; }
}
How could I modify my code to make the form file not required if the path already exists in the DB?
On the server side I could add the validation attribute but how would I make that work on the client side as well?
I have yet not worked on posting and saving the files to the controller on HttpPost. So, my controller is just a one-line initializing the view model.
public async Task<IActionResult> CreateBook()
{
BookViewModel bookVM = new BookViewModel();
return View("CreateEdit", bookVM);
}

ModelState.IsValid() does not validate even after the previous ModelState was closed

I am using an if statement which should perform some operations when the model state is valid, but apparently ModelState.IsValid does not return true. I have tried clearing the previous ModelState using ModelState.Clear() but it did not work as well.
Here is my Controller
// This is the first action for which I'm using the model state
[HttpPost]
public async Task<IActionResult> Register(userModel model)
{
if (ModelState.IsValid)
{
userData lcl_userr = new userData
{
username = model.username,
password = model.password,
email = model.email
};
_context.users.Add(lcl_userr);
await _context.SaveChangesAsync();
ViewBag.Success = "Registered successfully";
ModelState.Clear();
return View();
}
return View(model);
}
// And this is the second one
[HttpPost]
public IActionResult Index(userModel model)
{
if (ModelState.IsValid)
{
var findValue = _context.users.Any(o => o.username == model.username);
var findValue2 = _context.users.Any(o => o.password == model.password);
if (findValue && findValue2)
ViewBag.Name = "Success";
}
return View(model);
}
And here's the form
<form method="post" asp-action="Index" asp-controller="Portal">
<div class="text-danger"></div>
<div class="text-warning">#ViewBag.Name</div>
<div class="form-group">
<label class="mt-4 asp-for="username"">Username</label>
<input class="form-control" type="text" required="required" asp-for="username" />
<span></span>
</div>
<div class="form-group">
<label class="mt-4" asp-for="password">Password</label>
<input type="password" class="form-control" required="required" asp-for="password"/>
<span></span>
</div>
<center>Don't have an account? <a asp-controller="Portal" asp-action="Register">Register here</a>.</center>
<center><button value="login" class="btn btn-primary mt-3 w-25 mb-3 align-content-center">Login</button></center>
</form>
The model class being called inside the action and the class members work fine and the values it gets from the form are also working fine, it's just the model state which does not work.
The userModel class
public class userModel
{
[Display(Name = "username")]
[Required]
public string username { get; set; }
[Required]
[Display(Name = "password")]
public string password { get; set; }
[Required]
[Display(Name = "email")]
public string email { get; set; }
}
The second request to public IActionResult Index(userModel model) whose model doesn't contais email. IsValid is false.
[Required]
[Display(Name = "email")]
public string email { get; set; }
The ModelState instance for the email address has an error in the Errors collection.
When MVC creates the model state for the submitted properties, it also goes through each property in the ViewModel and validates the property using attributes associated to it. If any errors are found, they are added to the Errors collection in the property's ModelState.
Solution
Just reomve if (ModelState.IsValid) in Index action and there is no need to add it at all.
or if you insist to keep if (ModelState.IsValid), you need to add email inside form.
<input type="hidden" asp-for="email" />

how use two modeles in one method?

the ModelState is Invalid.I Think I pass Model Wrongly.Any Idea?
controller:
[Authorize]
[HttpPost]
public async Task<IActionResult> SendComment([Bind("CommentID,Comment,Date,AdminId")]AdminReport adminReport,int ReportID)
{
var x = _userReport.UserReports.Find(ReportID);
x.IsViewed = true;
adminReport.UserId = x.UserId;
adminReport.AdminId = _userManager.GetUserId(HttpContext.User);
if (ModelState.IsValid){
_adminReport.Add(adminReport);
await _adminReport.SaveChangesAsync();
return View(); }
return RedirectToAction("SendDoneAdmin");
}
its how I pass a Model:
<div class="card-footer">
<form asp-controller="Admin" asp-action="ُSendComment" method="post">
<input type="hidden" value="#report.ReportID" name="ReportID" />
<button type="submit" class="btn btn-primary">SendComment</button>
</form>
Model:
[Key]
public int CommentID { get; set; }
[Required]
public string Comment { get; set; }
public string AdminId { get; set; }
public string UserId { get; set; }
}`
Your quotation no clear but must know for pass data via Form tag
must all input inside Form tag
Controller
public async Task<IActionResult> SendComment()
{
// write your code....
return View(new AdminReport()); // must return new object
}
POST
Normal write again your action SendComment no any change
HTML
for pass AdminReport model must write flied inside form tag
<form asp-controller="Admin" asp-action="Viewed" method="post">
<input type="hidden" value="#report.ReportID" name="ReportID" />
/* for example */
<input type="hidden" asp-for="model.Comment" />
<button type="submit" class="btn btn-primary">SendComment</button>
</form>
No Problem if you have another view but must return View(new AdminReport());
If you want remove validation for comment prop use below code.
// remove all key
foreach (var key in ModelState.Keys).ToList())
ModelState.Remove(key);
// or for one
ModelState.Remove("comment ");
You put this [Requiried] attribute on the Comment:
[Required]
public string Comment { get; set; }
You will have to include that input in your form in order for the validation to pass.
You can add that field like this:
<div class="card-footer">
<form asp-controller="Admin" asp-action="Viewed" method="post">
<input type="hidden" value="#report.ReportID" name="ReportID" />
<input type="text" name="Comment" />
<button type="submit" class="btn btn-primary">SendComment</button>
</form>

ASP.NET Core 3 Razor Page DataAnnotation Compare attribute returns "Could not find a property named <n>"

I have a ASP.Net Core 3 razor page, a very simple reset password form, which uses a Compare Data Annotation to validate both inputs are the same, however, it doesn't seem to be working. The Required annotation triggers ok, but the Compare always returns ModelState.Valid == false and "Could not find a property named Password." as the error message.
the model is
[BindProperty]
[Required(ErrorMessage = "Password is required.")]
public string Password { get; set; }
[BindProperty]
[Required(ErrorMessage = "Password is required.")]
[Compare(nameof(Password), ErrorMessage = "Passwords don't match")]
public string ConfirmPassword { get; set; }
and the cshtml is
<form method="Post">
<label>New Password</label>
<input asp-for="Password" type="Password" >
<span asp-validation-for="Password" class="text-danger"></span>
<label>Confirm Password</label>
<input asp-for="ConfirmPassword" type="Password" >
<span asp-validation-for="ConfirmPassword" class="text-danger"></span>
<button type="Submit">Reset Password</button>
</form>
I've paired back the code to the complete minimum and just can't seem to see what the issue is...
thanks to Kirk Larkin for pointing me to the github issue detailing this. I decided to create a nested viewmodel class to contain the properties. The Compare annotation now works correctly.
nested class looks like this...
[BindProperty]
public ViewModel viewModel { get; set; }
public class ViewModel {
[Required(ErrorMessage = "Password is required.")]
public string Password { get; set; }
[Required(ErrorMessage = "Confirmation Password is required.")]
[Compare(nameof(Password), ErrorMessage = "Passwords don't match.")]
public string ConfirmPassword { get; set; }
}
and the web page now looks like this...
<form method="Post">
<label>New Password</label>
<input asp-for="viewModel.Password" type="Password" >
<span asp-validation-for="viewModel.Password" class="text-danger"></span>
<label>Confirm Password</label>
<input asp-for="viewModel.ConfirmPassword" type="Password" >
<span asp-validation-for="viewModel.ConfirmPassword" class="text-danger"></span>
<button type="Submit">Reset Password</button>
</form>

Model not being passed to controller

One of my asp.net core pages isn't passing its model back to the controller. I've investigated similar threads in stackoverflow but none could solve my issue - what's different in this particular case?
In the attached MVC, I fill the input box "Enter here some text", then I click on button "CLICK HERE". The debugger enters correctly the controller but the variable "TEST" returns null.
Any geniuses out there able to help me out?
My Model:
namespace MyProgram.Models._04_ModuleTasker
{
public class TaskerViewModel
{
public SelectList SelectListLocations;
public SelectList SelectListUsers;
public SelectList SelectListFilters;
public string SelectedCompanyLocationDesc;
public string SelectedUserId;
public string SelectedFilter;
}
}
My View:
#model MyProgram.Models._04_ModuleTasker.TaskerViewModel
#{
ViewData["Title"] = "AllTasks";
Layout = "~/Views/Shared/_Layout.cshtml";
}
<div class="container-fluid">
<div class="PageTitle">
Tasker
<hr class="TitleHR" />
</div>
<div style="text-align:center;margin-top:20px" class="text-body">
<form asp-controller="Tasker" asp-action="ShowActiveTasksPOST" method="post" role="form">
<input type="text" asp-for="SelectedUserId" /> Enter here some text <br />
<input type="submit" class="btn btn-success InputShortWidth LoginButton" value="CLICK HERE" />
</form>
</div>
</div>
My Controller:
[HttpPost]
public async Task<IActionResult> ShowActiveTasksPOST(TaskerViewModel taskerViewModel)
{
string TEST = taskerViewModel.SelectedUserId;
return RedirectToAction("Index", "Home");
}
To make the binding works, you need to convert the fields to properties with with setters and getters. E.g.:
public string SelectedCompanyLocationDesc { get; set; }
public string SelectedUserId { get; set; }
public string SelectedFilter { get; set; }