using a javascript variable in asp-route (parameter)? - c#

I'm extremely new to C# and .Net Core and Razor Pages.
I'm trying to create a super simple application where you can submit your first name and last name to a form and it will redirect you to a template which accepts the parameters firstname and surname and will print them out.
So what I'm doing is that I'm currently trying to store the value of the input (only trying with the first name right now) within script tags and then adding the variable within the asp-route-firstname when you submit the form. But it doesn't seem to work. Is this even the right way to try to approach this or am I somehow supposed to do this in the #{} field at the top?
In this case it just prints out {foo} as a string and the hardcoded surname Browder.
#page
#model IndexModel
#{
ViewData["Title"] = "Home page";
}
<div class="text-center">
<h1 class="display-4">Welcome #Model.FirstName</h1>
<p>Learn about building Web apps with ASP.NET Core.</p>
<form method="post" asp-page="/nametemplate" asp-route-firstname="{foo}" asp-route-surname="Browder">
<label for="fname">First name:</label><br>
<input type="text" id="fname" name="fname" value="John"><br>
<label for="lname">Last name:</label><br>
<input type="text" id="lname" name="lname" value="Doe"><br><br>
<input type="submit" value="Submit">
</form>
</div>
<script>
let foo = document.querySelector("#fname").value;
</script>
Thank you a million times in advance!

This is a very basic example to get you started but I highly recommend reading the docs.
Essentially you want to look at model binding. You don't need to use JS as per your example.
Razor Pages Docs
Index.cshtml
#page
#model IndexModel
#{
ViewData["Title"] = "Home page";
}
<div class="text-center">
<h1 class="display-4">Welcome</h1>
<p>Learn about building Web apps with ASP.NET Core.</p>
</div>
<form method="post">
<input asp-for="Firstname" />
<input asp-for="Lastname" />
<input type="submit" value="Submit" />
</form>
Index.cshtml.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Policy;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
using Microsoft.Extensions.Logging;
namespace RazorPageTest.Pages
{
public class IndexModel : PageModel
{
public string Firstname { get; set; }
public string Lastname { get; set; }
private readonly ILogger<IndexModel> _logger;
public IndexModel(ILogger<IndexModel> logger)
{
_logger = logger;
}
public void OnGet()
{
}
public IActionResult OnPost(string firstname, string lastname)
{
return RedirectToPage("Display", new { firstname, lastname });
}
}
}
Display.cshtml.cs (new page)
using Microsoft.AspNetCore.Mvc.RazorPages;
namespace RazorPageTest.Pages
{
public class DisplayModel : PageModel
{
public string Firstname { get; set; }
public string Lastname { get; set; }
public void OnGet(string firstname, string lastname)
{
Firstname = firstname;
Lastname = lastname;
}
}
}
Display.cshtml
#page
#model RazorPageTest.Pages.DisplayModel
#{
ViewData["Title"] = "Display";
}
<h1>#Model.Firstname #Model.Lastname</h1>

Related

ASP.NET Core Razor Pages Form Input Validation Not Working

So, I am developing a theoretically simple enough questionnaire application with user accounts and I am trying to validate the user input. For example here I am trying to make the First name field Required. I have followed some tutorials and it should be simple but I must be missing something. When I check if my model state is valid to reload the page or post the data, I get an error message telling me that the fields are required even though I have provided a value for them. I have removed some unimportant code parts for clarity. What seems to be the problem here?
CreateAdmin.cshtml
#page
#model ResumePostingService.Pages.CRUD.CreateAdminModel
#{
ViewData["Title"] = "Create Admin";
Layout = "~/Pages/SharedPages/_Layout_Admin.cshtml";
}
<div>
<h2>#Model.Messages</h2>
</div>
<h2>Add a new Admin Record</h2>
<hr />
<div class="row">
<div class="col-md-4">
<form method="post">
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
<div class="form-group">
<label asp-for="Admin.FirstName" class="control-label">First Name</label>
<input type="text" asp-for="Admin.FirstName" class="form-control" />
<span asp-validation-for="Admin.FirstName" class="text-danger"></span>
</div>
<div class="form-group">
<input type="submit" value="Create" class="btn btn-success" />
</div>
</form>
</div>
</div>
<div>
<a asp-page="/Admin_Pages/Admin_Index" class="btn btn-danger">Cancel</a>
</div>
#section Scripts {
#{await Html.RenderPartialAsync("_ValidationScriptsPartial");}
}
CreateAdmin.cshtml.cs
namespace ResumePostingService.Pages.CRUD
{
public class CreateAdminModel : PageModel
{
private readonly ResumePostingService.Models.ResumePostingServiceDatabaseContext _context;
public CreateAdminModel(ResumePostingService.Models.ResumePostingServiceDatabaseContext context)
{
_context = context;
}
readonly DataAccessClass objadmin = new DataAccessClass();
[BindProperty]
public Admin Admin { get; set; }
public string Messages { get; set; }
public IActionResult OnGet()
{
if (HttpContext.Session.GetInt32("Admin Id") == null)
{
return RedirectToPage("/SharedPages/Unauthorized");
}
else
{
return Page();
}
}
public ActionResult OnPost()
{
if (!ModelState.IsValid)
{
Messages = string.Join("; ", ModelState.Values
.SelectMany(x => x.Errors)
.Select(x => x.ErrorMessage));
return Page();
}
objadmin.AdAddAdmin(Admin);
return RedirectToPage("/Admin_Pages/Admin_Index", new { actres = 4 });
}
}
}
Admin.cs
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
namespace ResumePostingService.Models
{
public partial class Admin
{
public Admin()
{
}
[Key]
public int AdminId { get; set; }
[Required(AllowEmptyStrings = false, ErrorMessage = "Please enter the name")]
[StringLength(20, MinimumLength = 2, ErrorMessage = "Password cannot be longer than 20 characters and less than 2 characters")]
public string FirstName { get; set; }
}
}

View post form return null?

I am having problems to return a model using a form.
The problem is when I submit the form, the values are null even though I've specified that returns a model
This is my controller
And this is my View that returns null.
#model MyEnglishDictionary.Models.Dictionary
#{
ViewData["Title"] = "Create";
}
<h2>Create</h2>
<form method="post" asp-action="Create">
<div class="p-4 border rounded">
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
<div class="form-group row">
<div class="col-2">
<label asp-for="Word"></label>
</div>
<div class="col-5">
<input asp-for="Word" class="form-control" />
</div>
<span asp-validation-for="Word" class="text-danger"></span>
</div>
<div class="form-group row">
<div class="col-2">
<label asp-for="Meaning"></label>
</div>
<div class="col-5">
<input asp-for="Meaning" class="form-control" />
</div>
<span asp-validation-for="Meaning" class="text-danger"></span>
</div>
<div class="form-group row">
<div class="col-2">
<label asp-for="Pronunciation"></label>
</div>
<div class="col-5">
<input asp-for="Pronunciation" class="form-control" />
</div>
<span asp-validation-for="Pronunciation" class="text-danger"></span>
</div>
<br />
<div class="form-group">
<input type="submit" class="btn btn-primary" value="Create" />
<a asp-action="Index" class="btn btn-success">Back To List</a>
</div>
</div>
</form>
#section Scripts{
#{ await Html.RenderPartialAsync("_ValidationScriptsPartial"); }
}
EDIT
This is my Dictionary controller.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using MyEnglishDictionary.Data;
using MyEnglishDictionary.Models;
namespace MyEnglishDictionary.Controllers
{
public class DictionaryController : Controller
{
private readonly ApplicationDbContext _db;
public DictionaryController(ApplicationDbContext db)
{
_db = db;
}
public IActionResult Index()
{
return View(_db.Dictionaries.ToList());
}
public IActionResult Create()
{
return View();
}
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Create(Models.Dictionary word)
{
if(!ModelState.IsValid)
{
return View(word);
}
_db.Add(word);
await _db.SaveChangesAsync();
return RedirectToAction(nameof(Index));
}
}
}
And this is my Dictionary model
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace MyEnglishDictionary.Models
{
public class Dictionary
{
[Key]
public int Id { get; set; }
[Required]
public string Word { get; set; }
[Required]
public string Meaning { get; set; }
[Required]
public string Pronunciation { get; set; }
public string Link { get; set; }
public DateTime Date { get; set; }
}
}
I am using Net Core 2.1, but I have some few projects that I use the same way to pass the form model from View to controller and they work.
You need to pay attention to the name of the parameter and fields.
For your issue, it is caused by that you defined a field which is Word and the parameter is word which caused the binding failed.
Try to change the public async Task<IActionResult> Create(Models.Dictionary word) to public async Task<IActionResult> Create(Models.Dictionary dictionary).
change the word parameter name to something else like _word, it seems like the compiler doesn't accept it as a parameter name in c#.
public async Task<IActionResult> Create(Models.Dictionary _word)
{
if(!ModelState.IsValid)
{
return View(_word);
}
_db.Add(_word);
await _db.SaveChangesAsync();
return RedirectToAction(nameof(Index));
}
btw, I didn't see it in the reserved keywords list
You have to bind the properties to your model. In your case:
public async Task<IActionResult> Create([Bind("Word, Meaning, Pronounciation")] Dictionary word)
Further reading:
Model Binding

Facing Object reference not set exception even though operation succeeding [duplicate]

This question already has answers here:
What is a NullReferenceException, and how do I fix it?
(27 answers)
Closed 4 years ago.
I'm getting the following error each Time I try to enter a new Course.
Object reference not set to an instance of an object.
AspNetCore._Views_Admin_Manage_cshtml+<b__23_12>d.MoveNext()
in Manage.cshtml, line 34
Here is my Controller:
using ASP_Project.Data;
using ASP_Project.Models;
using ASP_Project.Services.Interfaces;
using ASP_Project.ViewModels;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Mvc;
using System.Collections.Generic;
using System.Linq;
using System.Security.Claims;
using System.Threading.Tasks;
namespace ASP_Project.Controllers
{
public class AdminController : Controller
{
private readonly UserManager<ApplicationUser> _userManager;
private readonly SchoolContext _schoolContext;
private readonly IAdminRepository _adminRepos;
private readonly ITeacherRepository _teacherRepository;
public AdminController(UserManager<ApplicationUser> userManager,
SchoolContext schoolContext,
IAdminRepository adminRepos,
ITeacherRepository teacherRepository
)
{
_userManager = userManager;
_schoolContext = schoolContext;
_adminRepos = adminRepos;
_teacherRepository = teacherRepository;
}
[HttpGet]
[Authorize(Roles = "Admin")]
public async Task<IActionResult> Index()
{
ClaimsPrincipal currentUser = User;
var user = await _userManager.GetUserAsync(currentUser);
var admin = _adminRepos.GetAdminByUser(user);
return View(new AdminViewModel()
{
FirstName = admin.FirstName,
LastName = admin.LastName,
MiddleName = admin.MiddleName
});
}
[HttpGet]
public IActionResult Manage()
{
IEnumerable<string> teachers = _teacherRepository.TeacherNames();
return View(new CourseViewModel()
{
Teachers = teachers
});
}
[HttpPost]
public async Task<IActionResult> Manage(CourseViewModel courseViewModel)
{
var teacher = _schoolContext.Teacher.Single(t => t.FirstName == courseViewModel.TeacherName);
Course course = new Course()
{
CodeID = courseViewModel.CodeID,
Name = courseViewModel.Name,
NumOfCredits = courseViewModel.NumOfCredits,
TeacherID = teacher.TeacherID
};
await _schoolContext.Course.AddAsync(course);
if (await _schoolContext.SaveChangesAsync() == 0)
return RedirectToAction("Index", "Admin");
return View(courseViewModel);
}
}
}
Here is my View:
#model ASP_Project.ViewModels.CourseViewModel
#{
ViewData["Title"] = "Manage";
}
<h2>Manage</h2>
<div class="row">
<div class="col-md-4">
<form asp-controller="Admin" asp-action="Manage" method="post" class="form-horizontal" role="form">
<h4>Create a new Course.</h4>
<hr />
<div asp-validation-summary="All" class="text-danger"></div>
<div class="form-group">
<label asp-for="CodeID"></label>
<input asp-for="CodeID" class="form-control" />
<span asp-validation-for="CodeID" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="Name"></label>
<input asp-for="Name" class="form-control" />
<span asp-validation-for="Name" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="NumOfCredits"></label>
<input asp-for="NumOfCredits" class="form-control" />
<span asp-validation-for="NumOfCredits" class="text-danger"></span>
</div>
<div>
<label asp-for="TeacherName" class="col-md-2 control-label"></label>
<div class="col-md-10">
<select asp-for="TeacherName" class="form-control" required>
<option value="" disabled selected>Select Teacher</option>
#foreach (var teach in Model.Teachers)
{
<option value="#teach"> #teach </option>
}
</select>
<span asp-validation-for="TeacherName" class="text-danger"></span>
</div>
</div>
<button type="submit" class="btn btn-default">Add</button>
</form>
</div>
</div>
#section Scripts {
#await Html.PartialAsync("_ValidationScriptsPartial")
}
My CourseViewModel:
using ASP_Project.Models;
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Threading.Tasks;
namespace ASP_Project.ViewModels
{
public class CourseViewModel
{
[Required]
public string CodeID { get; set; }
[Required]
public int NumOfCredits { get; set; }
[Required]
public string Name { get; set; }
[Required]
public string TeacherName { get; set; }
public IEnumerable<string> Teachers { get; set; }
}
}
And Finally the Function used to retrieve the names of the teachers:
public IEnumerable<string> TeacherNames() => _schoolContext.Teacher.Select(t => t.FirstName);
What I understood from the exception is that there is either a part of the foreach that needs an await or that one of the Objects is not being defined.
Take note that the operation is doing its job successfully nonetheless and the data is being added to the database, its just that this strange exception keeps showing up.
Edit: Even though #NoCodeFound answer Pointed out that I should debug (and that's what I did to find the answer) yet I was planning on doing that anyway, and I happened to discover the real cause anyway.
Turns out I messed up when I return from the Manage action after POST, since I used:
if (await _schoolContext.SaveChangesAsync() == 0)
return RedirectToAction("Index", "Admin");
return View(courseViewModel);
which was making me go through the courseViewModel again rather than being redirected to the page I needed.
So the fix would simply be:
if (await _schoolContext.SaveChangesAsync() == 0)
return View(courseViewModel);
return RedirectToAction("Index", "Admin");

Passing data from view to controller asp.net core razor pages

I am trying to create a simple asp.net core razor web site.
I have a cshtml page:
#page
#using RazorPages
#model IndexModel
#using (Html.BeginForm()) {
<label for="age">How old are you?</label>
<input type="text" asp-for="age">
<br/>
<label for="money">How much money do you have in your pocket?</label>
<input type="text" asp-for="money">
<br/>
<input type="submit" id="Submit">
}
and a cs file:
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
using System;
using System.Threading.Tasks;
namespace RazorPages
{
public class IndexModel : PageModel
{
protected string money { get; set; }
protected string age { get; set; }
public IActionResult OnPost()
{
if (!ModelState.IsValid)
{
return Page();
}
return RedirectToPage("Index");
}
}
}
I want to be able to pass age and money to the cs file and then pass it back to the cshtml file in order to display it on the page after the submit button sends a get request. How can I implement this?
Updated:
The following code does not work.
index.cshtml.cs:
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
using System;
using System.Threading.Tasks;
namespace RazorPages
{
public class IndexModel : PageModel
{
[BindProperty]
public decimal Money { get; set; }
[BindProperty]
public int Age { get; set; }
public IActionResult OnPost()
{
/* if (!ModelState.IsValid)
{
return Page();
}*/
this.Money = Money;
this.Age = Age;
System.IO.File.WriteAllText(#"C:\Users\Administrator\Desktop\murach\exercises\WriteText.txt",
this.Money.ToString());
return RedirectToPage("Index", new { age = this.Age, money = this.Money});
}
}
}
and index.cshtml:
#page
#using RazorPages
#model IndexModel
#using (Html.BeginForm()) {
<label for="Age">How old are you?</label>
<input type="text" asp-for="Age">
<br/>
<label for="Money">How much money do you have in your pocket?</label>
<input type="text" asp-for="Money">
<br/>
<input type="submit" id="Submit">
}
Money: #Model.Money
Age: #Model.Age
Money and age show up as 0s on the page and file regardless of what you type in.
Append your .cshtml file with code that outputs the values you're filling via POST.
MyPage.cshtml
#page
#model IndexModel
#using (Html.BeginForm())
{
<label for="Age">How old are you?</label>
<input type="text" asp-for="Age">
<br />
<label for="Money">How much money do you have in your pocket?</label>
<input type="text" asp-for="Money">
<br />
<input type="submit" id="Submit">
}
Money: #Model.Money
Age: #Model.Age
Now add [BindProperty] to each property in your model, which you want to update from your OnPost():
[BindProperty]
public int Age { get; set; }
[BindProperty]
public decimal Money { get; set; }
Furthermore, as Bart Calixto pointed out, those properties have to be public in order to be accessible from your Page.
The OnPost() method is really simple, since ASP.NET Core is doing all the work in the background (thanks to the binding via [BindProperty]).
public IActionResult OnPost()
{
return Page();
}
So now, you can click on Submit and voila, the page should look like this:
Btw.: Properties are written with a capital letter in the beginning.

Having difficulties displaying my model in my view

I am new to MVC5 and I am building a simple application that can add two numbers.
Model
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
namespace Test.Models
{
public class Solve
{
public decimal a { get; set; }
public decimal b { get; set; }
public decimal Result { get; set; }
}
}
This is my controller
Controller
namespace Test.Controllers
{
public class SolveController : Controller
{
// GET: Solve
public ActionResult Index()
{
return View();
}
[HttpPost]
public ActionResult Index(Solve equation)
{
equation.Result = equation.a + equation.b;
ViewBag.Message = equation;
return View();
}
View
#model Test.Models.Solve
#{
ViewBag.Title = "Index";
}
<h2>Index</h2>
<form method="post">
First Value: <input type="number" name="a"/><br /><br />
Second Value: <input type="number" name="b" /><br /><br />
<input type="submit" name="input" />
</form>
#{
var answer = (Solve)ViewBag.Message;
}
<p>
#answer.Result;
</p>
This is my view. Probably the problem is coming from here. Will be really need some help. Thanks
Return you model like below.
[HttpPost]
public ActionResult Index(Solve equation)
{
equation.Result = equation.a + equation.b;
return View(equation);
}
Your HTMl will be:
#model Test.Models.Solve
#{
ViewBag.Title = "Index";
}
<h2>Index</h2>
<form method="post">
First Value: <input type="number" name="a"/><br /><br />
Second Value: <input type="number" name="b" /><br /><br />
<input type="submit" name="input" />
</form>
<p>
#Model.Result;
</p>

Categories