I try to get the data of an input via asp-for from a cshtml page to a cshtml.cs page.
cshtml
<div class="form-group">
<label class="col-sm-2 control-label">Name</label>
<div class="col-sm-10">
<textarea name="InputNameEvent" asp-for="NameEvent" class="form-control" placeholder="Name"></textarea>
</div>
</div>
cshtml.cs
[Required]
[MinLength(5)]
[MaxLength(1024)]
public string NameEvent { get; set; }
public string Name2;
public void OnGet()
{
NameEvent = "Test";
}
public void OnPost()
{
Name2 = NameEvent;
}
Test is shown in the Textarea, but in OnPost() NameEvent is NULL
If you want form values to be bound to PageModel properties automatically, you must decorate the property with the BindProperty attribute:
[Required]
[MinLength(5)]
[MaxLength(1024)]
[BindProperty]
public string NameEvent { get; set; }
Or you can add multiple attributes separated by commas:
[Required, MinLength(5), MaxLength(1024), BindProperty]
public string NameEvent { get; set; }
If you are using tag helpers for your inputs, don't supply a name attribute. Let the tag helper generate one automatically, which will ensure that posted values match property names. At the moment, your name attribute (name="InputNameEvent") does not match the property name, so model binding cannot match the name/value pair that gets posted to a page property or parameter.
See more about model binding to PageModel properties in Razor Pages here.
I found my mistake. I needed to put <form method="post"></form> around the div. ALso i needed to add [BindProperty] in cshtml.cs and remove the name attribute in cshtml.
Thanks to Mike :)
cshtml
<form method="post">
<div class="form-group">
<label class="col-sm-2 control-label">Name</label>
<div class="col-sm-10">
<textarea asp-for="NameEvent" class="form-control" placeholder="Name"></textarea>
</div>
</div>
</form>
cshtml.cs
[Required]
[MinLength(5)]
[MaxLength(1024)]
[BindProperty]
public string NameEvent { get; set; }
Related
Im trying to do backend validation for a form, using asp-validation-for in a form, see code below, i notice that only one field returns an error when i do not provide data in the form, see also attached result
#page
#model MoviesApp.Pages.AddMoviesModel
#{
ViewData["Title"] = "Add New Movie";
}
<h3>#ViewData["Title"]</h3>
<hr />
#*<a asp-page-handler="MyOnClick">Click Me</a>*#
<div class="row">
<div class="col-md-6 offset-3">
<form method="post">
<div class="mb-3">
<label for="title" class="form-label">Title</label>
<input name="Title" type="text" class="form-control" id="title" placeholder="Movie Title" />
<span asp-validation-for="#Model.Title" class="text-danger"></span>
</div>
<div class="mb-3">
<label for="rate" class="form-label">Rate</label>
<input name="Rate" type="number" min="1" max="10" class="form-control" id="rate" placeholder="9" />
<span asp-validation-for="#Model.Rate" class="text-danger"></span>
</div>
<div class="mb-3">
<label for="description" class="form-label">Description</label>
<textarea name="Description" class="form-control" id="description" rows="3"></textarea>
<span asp-validation-for="#Model.Description" class="text-danger"></span>
</div>
<button type="submit" class="btn btn-success">Add Movie</button>
</form>
</div>
</div>
Here's the detail source code for the model bit for the above cshtml, find below code for AddMoviesModel
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
using MoviesApp.Data.Models;
namespace MoviesApp.Pages
{
public class AddMoviesModel : PageModel
{
[BindProperty]
public string Title { get; set; }
[BindProperty]
public int Rate { get; set; }
[BindProperty]
public string Description { get; set; }
//[BindProperty]
// public Movie Movie { get; set; }
public void OnGet()
{
//Title = "Welcome";
}
//public void OnGetMyOnClick()
//{
// string stophere = "";
//}
public IActionResult OnPost()
{
string value = $"{Title} - {Rate} - {Description}";
//string value = $"{Movie.Title} - {Movie.Rate} - {Movie.Description}";
if (!ModelState.IsValid)
{
return Page();
}
//return Page();
return Redirect("Movies");
}
}
}
I was able to resolve it by add the namespace
using System.ComponentModel.DataAnnotations;
and including [Required(ErrorMessage="validation message")],
ideally asp-validation-for in a tag when used as in a .net core 6 Razor pages Web application using visual studio 2022 should work, however in visual studio 2019 running .net core 3.1 razor pages web application it does not thus the need to add the DataAnnotation namespace.
see below solution in model
[BindProperty]
[Required(ErrorMessage = "Please enter Title")]
public string Title { get; set; }
[BindProperty]
public int Rate { get; set; }
[BindProperty]
[Required(ErrorMessage = "Please enter Description")]
public string Description { get; set; }
I have been following the documentation here and here, but the validation attributes don't seem to work. I have this in my RModel:
[RegularExpression(#"^[A-Z]+[a-zA-Z'\s]*$")]
[Required]
[StringLength(10)]
public string FirstName { get; set; }
[Required]
[EmailAddress]
public string Email { get; set; }
And this is in my view:
#using (Html.BeginForm("Index", "RHome", FormMethod.Post))
{
<div class="field form-group col-sm-4">
<input type="text" id="FirstName" placeholder=" ">
<label for="FirstName">First Name</label>
<span asp-validation-for="RModel.FirstName"></span>
</div>
<div class="field form-group col-sm-8">
<input id="Email" placeholder=" ">
<label for="Email">Email</label>
<span asp-validation-for="RModel.Email"></span>
</div>
. . .
}
I am using a ViewModel to load in multiple models. The other models are very similar to RModel. I don't know if that will effect anything, but I think it might.
public class ViewModelR
{
public RModel RModel { get; set; }
public KnowledgeModel KnowledgeModel { get; set; }
}
I just want to have server and client side validation to prevent injection and incorrect inputs and stuff. How to I do this?
UPDATE: I added to my view and now when I click submit without filling either input, I seem to be getting a message that implies [required] is working.
The Email: field is required.
The First Name: field is required.
That's great, but I need to get all the other validation working so I can prevent bad values?
I would suggest you to use Validation message scafolding with every input html element you have in your view.
#Html.ValidationMessageFor(model => model.RHome.FirstName, "", new { #class = "text-danger" })
I hope, you have already added at least below js in your view.
jquery.validate.unobtrusive.js
The following simple .NET Core 2.1 MVC code reports "Validation State: Invalid" when I submit to create. Everything works fine without the Owner property; and it works if Owner property is not required.
The Owner is the current user which is in the context of the server side, and it shouldn't be submitted from a client side, so the Create.cshtml doesn't have a Owner input in the form.
The error:
info: Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker[1]
Executing action method AnnouncementApp.Controllers.AnnouncementsController.Create (AnnouncementApp) with arguments (AnnouncementApp.Models.Announcement) - Validation state: Invalid
The model:
using System;
using Microsoft.AspNetCore.Mvc;
using System.ComponentModel.DataAnnotations;
using Microsoft.AspNetCore.Mvc.ModelBinding;
using AnnouncementApp.Models.Attributes;
using Microsoft.AspNetCore.Identity;
//using System.Security.Claims;
namespace AnnouncementApp.Models
{
public class Announcement
{
public int ID { get; set; }
[Required]
public string Content { get; set; }
[Display(Name = "Start Date and Time")]
public DateTime StartDate { get; set; }
[StartEndDate("End Date and Time must be after Start Date and Time")]
[Display(Name = "End Date and Time")]
public DateTime EndDate { get; set; }
[Required]
[BindNever]
public IdentityUser Owner { get; set; }
}
}
The controller method:
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Create([Bind("ID,Content,StartDate,EndDate")] Announcement announcement)
{
if (ModelState.IsValid)
{
var user = await _userManager.GetUserAsync(this.User);
announcement.Owner = user;
_context.Add(announcement);
await _context.SaveChangesAsync();
return RedirectToAction(nameof(Index));
}
return View(announcement);
}
The Create.cshtml
#model AnnouncementApp.Models.Announcement
#{
ViewData["Title"] = "Create";
}
<h2>Create</h2>
<h4>Announcement</h4>
<hr />
<div class="row">
<div class="col-md-4">
<form asp-action="Create">
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
<div class="form-group">
<label asp-for="Content" class="control-label"></label>
<textarea asp-for="Content" class="form-control"></textarea>
<span asp-validation-for="Content" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="StartDate" class="control-label"></label>
<input asp-for="StartDate" class="form-control" />
<span asp-validation-for="StartDate" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="EndDate" class="control-label"></label>
<input asp-for="EndDate" class="form-control" />
<span asp-validation-for="EndDate" class="text-danger"></span>
</div>
<div class="form-group">
<input type="submit" value="Create" class="btn btn-default" />
</div>
</form>
</div>
</div>
<div>
<a asp-action="Index">Back to List</a>
</div>
#section Scripts {
#{await Html.RenderPartialAsync("_ValidationScriptsPartial");}
}
For Announcement, it will apply [Required] for both client validation and database table.
As the comments indicates, you could consider split Announcement to Db Model and ViewModel, you could define a new AnnouncementViewModel for client validation.
For another option, you could try configure the [Required] in the fluent api instead of attribute.
Here are the detail steps.
Change Announcement
public class Announcement
{
public int ID { get; set; }
[Required]
public string Content { get; set; }
[Display(Name = "Start Date and Time")]
public DateTime StartDate { get; set; }
public string OwnerId { get; set; }
//[Required]
[BindNever]
[ForeignKey("OwnerId")]
public IdentityUser Owner { get; set; }
}
Fluent api in ApplicationDbContext
protected override void OnModelCreating(ModelBuilder builder)
{
base.OnModelCreating(builder);
builder.Entity<Announcement>()
.Property(a => a.OwnerId)
.IsRequired();
}
Controller
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Create([Bind("ID,Content,StartDate")] Announcement announcement)
{
if (ModelState.IsValid)
{
var user = await _userManager.GetUserAsync(User);
announcement.Owner = user;
_context.Add(announcement);
await _context.SaveChangesAsync();
return RedirectToAction(nameof(Index));
}
return View(announcement);
}
I am not 100 % sure, what you define as the issue, but if you want to supress the "Model Invalid" error, since you are always setting the Owner property through the HttpContext, you can use the following before validating the model:
ModelState["Owner"].ValidationState = ModelValidationState.Valid
I think your issue is that you tell the router to never bind "Owner", but you still tells it is required, and therefore the ModelState would potentially invalidate it.
As long as the "Required" annotation is used, I do not think the ModelState will validate without it being set correctly.
Example:
ModelState["Owner"].ValidationState = ModelValidationState.Valid
if (ModelState.IsValid)
{
var user = await _userManager.GetUserAsync(this.User);
announcement.Owner = user;
_context.Add(announcement);
await _context.SaveChangesAsync();
return RedirectToAction(nameof(Index));
}
return View(announcement);
public class MyModel
{
public int Id { get; set; }
public string Name { get; set; }
public MyType MyType { get; set; }
public IMyConfig MyConfig { get; set; }
}
public enum MyType
{
FirstConfig,
SecondConfig,
ThirdConfig
}
public interface IMyConfig
{
string BuildFirstJson();
string BuildSecondJson();
}
public class FirstConfig : IMyConfig
{
public string cat { get; set; }
public string dog { get; set; }
public string lion { get; set; }
public string BuildFirstJson()
{
...
}
public string BuildSecondJson()
{
...
}
}
public class SecondConfig : IMyConfig
{
public string bear { get; set; }
public int pig { get; set; }
public string fish { get; set; }
public string shark { get; set; }
public string dolphin { get; set; }
public string BuildFirstJson()
{
...
}
public string BuildSecondJson()
{
...
}
}
//ThirdConfig built similarly
So what I am trying to do is build a form in a razor view that can handle the MyModel class and switches the displayed IMyConfig bindings based on the selected MyType for example, if FirstConfig is selected from the enum list, then FirstProp, SecondProp, ThirdProp text boxes are displayed and when the form is submitted, those properties are correctly built into a FirstConfig object and passed into MyModel as a IMyConfig interface. I have no idea how to accomplish this part, I am plan on using jquery .change() to listen for a switch in the MyType dropdown. But I am not sure how to handle the seperate displaying and automatic model building(if that makes sense).
If that doesn't make sense, the quick version is I am trying to build a razor view form for MyModel and don't how to approach the MyConfig property which is based on the MyType property.
<form asp-action="ActivityCreateSubmit">
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
<div class="form-group">
<label asp-for="Id" class="control-label"></label>
<input asp-for="Id" class="form-control" />
<span asp-validation-for="Id" class="text-danger"></span>
</div>
<div class="form-group" style="display: none;">
<label asp-for="Name" class="control-label"></label>
<input asp-for="Name" class="form-control" value="#ViewBag.AppId" />
<span asp-validation-for="Name" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="MyType" class="control-label"></label>
<select id="selection" asp-for="MyType" asp-items="Html.GetEnumSelectList<MyType>()">
<option value="">Select...</option>
</select>
<span asp-validation-for="MyType" class="text-danger"></span>
</div>
#switch(Model.MyType)
{
case FirstConfig:
<input name="first-input" />
<input name="second-input" />
<input name="third-input" />
break;
case SecondConfig:
... Do something ...
break;
}
<div class="form-group">
<input type="submit" value="Create" class="btn btn-default" />
</div>
</form>
Controller -
//Ignore ActivityTable, it is a dependency injection.
public ActionResult ActivityCreateSubmit(ActivityTable at, MyModel a)
{
at.AddActivity(a)
return View("../Home/Index");
}
//This is the page I am working on creating
public ActionResult ActivityCreate()
{
return (View());
}
I could not get exactly what your problem is, but I guess you need the following (I am glad to edit the answer if that is not what you need).
you can check the selected value in that enum inside your Razor page:
<form>
#switch(Model.MyType)
{
case FirstConfig:
<input name="cat"/>
<input name="dog" />
<input name="lion" />
break;
case SecondConfig:
... Do something ...
break;
}
</form>
UPDATE:
The action ActivityCreateSubmit should have a parameter of some class type the class you require (FirstConfig). The name you gave to each input MUST be identical to the properties in your class FirstConfig, i.e., like this:
<input name="cat"/>
<input name="dog"/>
<input name="lion"/>
Now try to submit, it should work.
I am using ASP.NET Core with VS 2017. I want to allow the users to create an employee record where they can leave the address input field empty i.e. as optional field input.
Using [Bind("Name","Address")] always validates the inputs and the request will always fail when the address field is empty.
Here is the data model.
public class Employee
{
public int ID { get; set; }
public string Name { get; set; }
public string Address { get; set; }
}
and the Create method reading the parameters from Post request has a model binding as follows
public async Task<IActionResult> Create([Bind("Name,Address")] Employee emp)
and the view has a default asp form using Employee Model.
<div class="col-md-10">
<input asp-for="Address" class="form-control" />
<span asp-validation-for="Address" class="text-danger"></span>
</div>
Is there any way to make the address input field as an optional input for Model Binding?
I'm very new to Asp.net core, but from what I've learned so far, this is how I would do it:
<form method="post" asp-controller="YourController" asp-action="Create">
<div>
<input asp-for="Name" placeholder="Name"/>
<div class="stylized-error">
<span asp-validation-for="Name"></span>
</div>
<input asp-for="Address" placeholder="Address"/>
<div class="stylized-error">
<span asp-validation-for="Address"></span>
</div>
<input type="submit" value="Submit" />
<div class="error-list" asp-validation-summary="ModelOnly"></div>
</div>
</form>
You want Address to be optional which is by default true, so you actually want to make Name required:
public class Employee
{
public int ID { get; set; }
[Required]
public string Name { get; set; }
public string Address { get; set; }
}
And your controller:
public async Task<IActionResult> Create(Employee emp)
{
if (ModelState.IsValid)
{
// Do whatever you want here...
}
}
A property is considered optional if it is valid for it to contain
null. If null is not a valid value to be assigned to a property then
it is considered to be a required property.
Later
You can use Data Annotations to indicate that a property is required.
From docs.microsoft