ASP.NET MVC partial not binding when a passing property though - c#

I've been away from ASP.NET MVC for a while so forgotten some of the basics.
I have scoured SO for an answer, but none really seem to apply/work so this may seem like a duplicate question but it's really not, perhaps I just can't see the wood through the trees. I know I'm missing something obvious but cant remember what
I have a partial that I pass the model to that updates a property on the model (AddressDetails & ContactDetails).
Main page
<form asp-action="Create">
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
<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
#await Html.PartialAsync("../AddressDetails/Create.cshtml", Model)
#await Html.PartialAsync("../ContactDetails/Create.cshtml", Model)
<div class="form-group">
<input type="submit" value="Create" class="btn btn-primary" />
</div>
</form>
And partial page
#model CareHome.Models.CareHomes
<div class="form-group">
<h4>AddressDetails</h4>
<hr />
</div>
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
<div class="form-group">
<label asp-for="AddressDetails.NumberStreetName" class="control-label"></label>
<input asp-for="AddressDetails.NumberStreetName" class="form-control" />
<span asp-validation-for="AddressDetails.NumberStreetName" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="AddressDetails.Locality" class="control-label"></label>
<input asp-for="AddressDetails.Locality" class="form-control" />
<span asp-validation-for="AddressDetails.Locality" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="AddressDetails.Town" class="control-label"></label>
<input asp-for="AddressDetails.Town" class="form-control" />
<span asp-validation-for="AddressDetails.Town" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="AddressDetails.PostCode" class="control-label"></label>
<input asp-for="AddressDetails.PostCode" class="form-control" />
<span asp-validation-for="AddressDetails.PostCode" class="text-danger"></span>
</div>
This is working fine when I post data back to the controller
However, I want to reuse the partial which means I want to replace
#model CareHome.Models.CareHomes
in the partial with the property class (see further below) that the model uses.
So when I change it to
main
<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="Name" class="control-label"></label>
<input asp-for="Name" class="form-control" />
<span asp-validation-for="Name" class="text-danger"></span>
</div
#await Html.PartialAsync("../AddressDetails/Create.cshtml", Model.AddressDetails)
#await Html.PartialAsync("../ContactDetails/Create.cshtml", Model.ContactInfo)
<div class="form-group">
<input type="submit" value="Create" class="btn btn-primary" />
</div>
</form>
</div>
</div>
note that im passing the property through to the partial now not the model
#model CareHome.Models.AddressDetails
<div class="form-group">
<h4>AddressDetails</h4>
<hr />
</div>
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
<div class="form-group">
<label asp-for="NumberStreetName" class="control-label"></label>
<input asp-for="NumberStreetName" class="form-control" />
<span asp-validation-for="NumberStreetName" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="Locality" class="control-label"></label>
<input asp-for="Locality" class="form-control" />
<span asp-validation-for="Locality" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="Town" class="control-label"></label>
<input asp-for="Town" class="form-control" />
<span asp-validation-for="Town" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="PostCode" class="control-label"></label>
<input asp-for="PostCode" class="form-control" />
<span asp-validation-for="PostCode" class="text-danger"></span>
</div>
iv now changed the partial to use
#model CareHome.Models.AddressDetails
but when I post this to the controller it comes back null
I tried a million variations on the binding
// POST: CareHomes/Create
// To protect from overposting attacks, enable the specific properties you want to bind to.
// For more details, see http://go.microsoft.com/fwlink/?LinkId=317598.
[HttpPost]
[ValidateAntiForgeryToken]
//Create([Bind("CareHomesId,Name,ContactName,ContactNumber")] CareHomes careHomes)
public async Task<IActionResult> Create([Bind( "CareHomes,AddressDetails,ContactDetails")] CareHomes careHomes)
{
if (ModelState.IsValid)
{
_context.Add(careHomes);
await _context.SaveChangesAsync();
return RedirectToAction(nameof(Index));
}
ViewData["AddressDetailsId"] = new SelectList(_context.AddressDetails, "AddressDetailsId", "NumberStreetName", careHomes.AddressDetailsId);
ViewData["ContactDetailsId"] = new SelectList(_context.ContactDetails, "ContactDetailsId", "ContactName", careHomes.ContactDetailsId);
return View(careHomes);
}
but when I evaluate the ModelState I can see it's always missing. As the propertys of the model bind ok when i pass the model though why do they then not bind when i pass the property though
my classes are like so
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
namespace CareHome.Models
{
public class CareHomes
{
[Required]
[Key, DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int CareHomesId { get; set; }
[Required]
[Column(TypeName = "VARCHAR(256)")]
[StringLength(256, MinimumLength = 3)]
public string Name { get; set; }
public int? AddressDetailsId { get; set; }
public AddressDetails AddressDetails { get; set; }
public int? ContactDetailsId { get; set; }
public ContactDetails ContactInfo { get; set; }
public ICollection<Staff>? StaffMembers { get; set; }
}
}
and one of the properties in question
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
namespace CareHome.Models
{
public class AddressDetails
{
[Required]
[Key, DatabaseGenerated(DatabaseGeneratedOption.Identity)]
public int AddressDetailsId { get; set; }
[Required]
[Column(TypeName = "VARCHAR(256)")]
[StringLength(256, MinimumLength = 3)]
[Display(Name = "House No & Street Name")]
public string NumberStreetName { get; set; }
[Column(TypeName = "VARCHAR(256)")]
[StringLength(256, MinimumLength = 3)]
public string? Locality { get; set; }
[Required]
[Column(TypeName = "VARCHAR(256)")]
[StringLength(256, MinimumLength = 3)]
public string Town { get; set; }
[Required]
[Column(TypeName = "VARCHAR(16)")]
[StringLength(16, MinimumLength = 4)]
[RegularExpression(#"^(([A-Z]{1,2}\d[A-Z\d]?|ASCN|STHL|TDCU|BBND|[BFS]IQQ|PCRN|TKCA) ?\d[A-Z]{2}|BFPO ?\d{1,4}|(KY\d|MSR|VG|AI)[ -]?\d{4}|[A-Z]{2} ?\d{2}|GE ?CX|GIR ?0A{2}|SAN ?TA1)$", ErrorMessage = "Please enter a valid UK post code in upper case")]
public string PostCode { get; set; }
public CareHomes? CareHomes { get; set; }
}
}
I have tried adding bind animations like
[BindProperty]
to the property and adding hidden fields in the partual
#Html.HiddenFor(m => m.AddressDetailsId)
#Html.HiddenFor(m => m.AddressDetails)
As per some suggestions from some of the many SO searches I did, but no dice....so please...what am I missing?
I even tried #html.EditorFor but that seems to have the same problem
EDIT
Using #Jonesopolis suggestion I can see from the form being posted back when it uses the model:
?this.Request.Form.ToArray()
{System.Collections.Generic.KeyValuePair<string, Microsoft.Extensions.Primitives.StringValues>[11]}
...
[4]: {[AddressDetails.CareHomes, {}]}
[5]: {[AddressDetailsId, {}]}
[6]: {[AddressDetails.NumberStreetName, {sad}]}
[7]: {[AddressDetails.Locality, {sad}]}
[8]: {[AddressDetails.Town, {wales}]}
[9]: {[AddressDetails.PostCode, {CF83 8RD}]}
vs when i pass the property
?this.Request.Form.ToArray()
{System.Collections.Generic.KeyValuePair<string, Microsoft.Extensions.Primitives.StringValues>[11]}
...
[4]: {[CareHomes, {}]}
[5]: {[AddressDetailsId, {0}]}
[6]: {[NumberStreetName, {test street}]}
[7]: {[Locality, {}]}
[8]: {[Town, {wales}]}
[9]: {[PostCode, {CF83 8RD}]}
so clearly the "AddressDetails" is missing so MVC cant map the propery to the CareHomes class object on the binding because the property name is missing. So i know what the issue is not how to fix it though, How do I set the property name on the partual propertys so they map back to the parent object class. I though about a costom binder but not having much luck figuring that one out.
On a side note, intrestingly enough if in the partent model I do this :
#Html.EditorFor(m => m.AddressDetails.NumberStreetName)
then bind like so
public async Task<IActionResult> Create([Bind(include: "CareHomes,AddressDetails")] CareHomes careHomes)
I can at least get the EditorFor to pull though on the parent

Finally worked it out, seems model binding wasn't the issue, I just had to set the id and name properties on the form controls in the partial to match that of the object on the model action, e.g. id="AddressDetails_NumberStreetName" name="AddressDetails.NumberStreetName"
so adding
<div class="form-group">
<label asp-for="NumberStreetName" class="control-label"></label>
<input asp-for="NumberStreetName" id="AddressDetails_NumberStreetName" name="AddressDetails.NumberStreetName" class="form-control" />
<span asp-validation-for="NumberStreetName" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="Locality" class="control-label"></label>
<input asp-for="Locality" id="AddressDetails_Locality" name="AddressDetails.Locality" class="form-control" />
<span asp-validation-for="Locality" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="Town" class="control-label"></label>
<input asp-for="Town" id="AddressDetails_Town" name="AddressDetails.Town" class="form-control" />
<span asp-validation-for="Town" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="Postcode" class="control-label"></label>
<input asp-for="Postcode" id="AddressDetails_Postcode" name="AddressDetails.Postcode" class="form-control" />
<span asp-validation-for="Postcode" class="text-danger"></span>
</div>
allows it to properly map to the contoller model
public async Task<IActionResult> Create([Bind(include: "CareHomes, Name,AddressDetails, ContactInfo")] CareHomes careHomes)
I worked it out when I put the partial mark up in the main form and looked at the HTML markup and compared it to when it was a partial. I hope this helps someone else someday

Related

ASP.NET Core MVC : retrieve DateTime from database into view

I'm quite new to ASP.NET Core MVC and I'm having trouble retrieving a DateTime value from the database into the 'Edit' razor view.
I can use the scaffolded views to create a new Activity Item and this displays correctly in the 'Index' list, and in the 'Details' view, but when I attempt to 'Edit' the entry the DateTime value doesn't pull through from the database.
I've done plenty of reading but the main thing I seem to get in search results is information about JQuery Datepickers.
Any advice on where to look, how to resolve would be very much appreciated.
Here is my model:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
namespace MISDataRepo.Models
{
[Table("Activity",Schema = "coir")]
public partial class ActivityItem
{
public ActivityItem()
{
ActivityIdentifier = new HashSet<ActivityIdentifier>();
}
[Key]
public int ActivityItemId { get; set; }
[Required(ErrorMessage = "A valid Activity Name is required.")]
[Display(Name = "Activity Name")]
[StringLength(100)]
public string ActivityName { get; set; }
[Required]
[Display(Name = "Activity Type")]
public int ActivityTypeId { get; set; }
[Required]
[Display(Name = "Date Activity Created")]
[DataType(DataType.Date)]
[DisplayFormat(DataFormatString = "{0:dd/MM/yyyy}", ApplyFormatInEditMode = true)]
public DateTime DateCreated { get; set; }
[Display(Name = "Date Activity Modified")]
[DataType(DataType.Date)]
[DisplayFormat(DataFormatString = "{0:dd/MM/yyyy}", ApplyFormatInEditMode = true)]
public DateTime? DatetModified { get; set; }
[Required]
[Display(Name = "Created By (Employee ID)")]
[RegularExpression("^[1-9][0-9]{6}$", ErrorMessage = "A valid Employee ID is required!")]
public int? CreatedBy { get; set; }
[Display(Name = "Project Co-Ordinator (Employee ID)")]
[RegularExpression("^[1-9][0-9]{6}$", ErrorMessage = "A valid Employee ID is required!")]
public int? PC { get; set; }
[DefaultValue(true)]
public bool Live { get; set; }
public virtual ActivityType ActivityType { get; set; }
public virtual ICollection<ActivityIdentifier> ActivityIdentifier { get; set; }
}
}
Here is the view:
#model MISDataRepo.Models.ActivityItem
#{
ViewData["Title"] = "Edit";
Layout = "~/Views/Shared/_Layout.cshtml";
}
<h1>Edit</h1>
<h4>ActivityItem</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="ActivityItemId" />
<div class="form-group">
<label asp-for="ActivityName" class="control-label"></label>
<input asp-for="ActivityName" class="form-control" />
<span asp-validation-for="ActivityName" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="ActivityTypeId" class="control-label"></label>
<select asp-for="ActivityTypeId" class="form-control" asp-items="ViewBag.ActivityTypeId"></select>
<span asp-validation-for="ActivityTypeId" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="DateCreated" class="control-label"></label>
<input asp-for="#Html.DisplayFor(a => a.DateCreated)" class="form-control" />
<span asp-validation-for="DateCreated" class="text-danger"></span>
#*<input type="hidden" asp-for="DateCreated" type="date" placeholder="Enter Date Created" value="#Model.DateCreated" />*#
</div>
<div class="form-group">
<label asp-for="DatetModified" class="control-label"></label>
<input asp-for="#Html.DisplayFor(a => a.DatetModified)" class="form-control" />
<span asp-validation-for="DatetModified" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="CreatedBy" class="control-label"></label>
<input asp-for="CreatedBy" class="form-control" />
<span asp-validation-for="CreatedBy" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="PC" class="control-label"></label>
<input asp-for="PC" class="form-control" />
<span asp-validation-for="PC" class="text-danger"></span>
</div>
<div class="form-group form-check">
<label class="form-check-label">
<input class="form-check-input" asp-for="Live" /> #Html.DisplayNameFor(model => model.Live)
</label>
</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");}
}
Here are the 'Edit' methods of the controller
// GET: ActivityItems/Edit/5
public async Task<IActionResult> Edit(int? id)
{
if (id == null)
{
return NotFound();
}
var activityItem = await _context.ActivityItem.FindAsync(id);
if (activityItem == null)
{
return NotFound();
}
ViewData["ActivityTypeId"] = new SelectList(_context.ActivityType, "ActivityTypeId", "ActivityTypeName", activityItem.ActivityTypeId);
return View(activityItem);
}
// POST: ActivityItems/Edit/5
// To protect from overposting attacks, enable the specific properties you want to bind to, for
// more details, see http://go.microsoft.com/fwlink/?LinkId=317598.
[HttpPost]
[ValidateAntiForgeryToken]
//public async Task<IActionResult> Edit(int id, [Bind("ActivityItemId,ActivityName,ActivityTypeId,DateCreated,DatetModified,CreatedBy,PC,Live")] ActivityItem activityItem)
public async Task<IActionResult> Edit(int id, [Bind("ActivityItemId,ActivityName,ActivityTypeId,DatetModified,CreatedBy,PC,Live")] ActivityItem activityItem)
{
if (id != activityItem.ActivityItemId)
{
return NotFound();
}
if (ModelState.IsValid)
{
try
{
_context.Update(activityItem);
await _context.SaveChangesAsync();
}
catch (DbUpdateConcurrencyException)
{
if (!ActivityItemExists(activityItem.ActivityItemId))
{
return NotFound();
}
else
{
throw;
}
}
return RedirectToAction(nameof(Index));
}
ViewData["ActivityTypeId"] = new SelectList(_context.ActivityType, "ActivityTypeId", "ActivityTypeName", activityItem.ActivityTypeId);
return View(activityItem);
}
But when I attempt to 'Edit' the entry the DateTime value doesn't pull
through from the database.
Yes, the issue you are having with the your View is pretty obvious due to your HTML Helper atrribute that is #Html.DisplayFor and the Property you have defined within your Model ActivityItem. You are probably getting following issue.
Problem:
How To Resolve:
Either you could use ViewModel or you can redefine your property public DateTime DateCreated { get; set; } by get rid of your annotations. However, I would prefer to use ViewModel. On the other hands, use the property like asp-for="DateCreated" within your edit view and get rid of your additional HTML helper class #Html.DisplayFor. Follow the below steps.
View Model:
public class ActivityItemViewModel
{
public int ActivityItemId { get; set; }
public string ActivityName { get; set; }
public DateTime DateCreated { get; set; }
public DateTime? DatetModified { get; set; }
}
Note: While loading your Edit view you certainly doesn't require annotations so you can ommit that.
View :
In view you are using additional HTML helper class #Html.DisplayFor which is not required in this scenario. You could try as following:
#model DotNet6MVCWebApp.Models.ActivityItemViewModel
#{
ViewData["Title"] = "Edit";
}
<h1>Edit</h1>
<h4>ActivityItem</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="ActivityItemId" />
<div class="form-group">
<label asp-for="ActivityName" class="control-label"></label>
<input asp-for="ActivityName" class="form-control" />
<span asp-validation-for="ActivityName" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="DateCreated" class="control-label"></label>
<input asp-for="DateCreated" class="form-control" />
<span asp-validation-for="DateCreated" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="DatetModified" class="control-label"></label>
<input asp-for="DateCreated" class="form-control" />
<span asp-validation-for="DatetModified" 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="ActivityList">Back to List</a>
</div>
Output:

Populate DropDown List in MVC App that Consumes a Web API

I have a simple MVC app that is consuming a web api via REST. The controller in the MVC app makes http calls to the web api to populate views within the MVC app with razor syntax.
I am trying to figure out how to populate a drop down list on one of the 'create' actions. I'm currently just using the scaffolded page:
#model ComicBookInventory.Shared.ComicBookWithAuthorsAndCharactersViewModel
#{
ViewData["Title"] = "CreateComicBook";
Layout = "~/Views/Shared/_Layout.cshtml";
}
<h1>CreateComicBook</h1>
<hr />
<div class="row">
<div class="col-md-4">
<form asp-action="CreateComicBook">
<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">
<label asp-for="Title" class="control-label"></label>
<input asp-for="Title" class="form-control" />
<span asp-validation-for="Title" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="Description" class="control-label"></label>
<input asp-for="Description" class="form-control" />
<span asp-validation-for="Description" class="text-danger"></span>
</div>
<div class="form-group form-check">
<label class="form-check-label">
<input class="form-check-input" asp-for="IsRead" /> #Html.DisplayNameFor(model => model.IsRead)
</label>
</div>
<div class="form-group">
<label asp-for="DateRead" class="control-label"></label>
<input asp-for="DateRead" class="form-control" />
<span asp-validation-for="DateRead" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="Rating" class="control-label"></label>
<input asp-for="Rating" class="form-control" />
<span asp-validation-for="Rating" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="Genre" class="control-label"></label>
<input asp-for="Genre" class="form-control" />
<span asp-validation-for="Genre" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="CoverUrl" class="control-label"></label>
<input asp-for="CoverUrl" class="form-control" />
<span asp-validation-for="CoverUrl" class="text-danger"></span>
</div>
<div class="form-group">
<input type="submit" value="Create" class="btn btn-primary" />
</div>
</form>
</div>
</div>
<div>
<a asp-action="Index">Back to List</a>
</div>
#section Scripts {
#{
await Html.RenderPartialAsync("_ValidationScriptsPartial");
}
}
Which gets populated from this action in the controller:
public async Task<IActionResult> CreateComicBook(ComicBookWithAuthorsAndCharactersViewModel model)
{
string uri = $"https://localhost:5001/api/comicbook/add-book/";
HttpClient client = _httpClientFactory.CreateClient(
name: "ComicBookInventory.Api");
var postTask = await client.PostAsJsonAsync<ComicBookWithAuthorsAndCharactersViewModel>(uri, model);
if (postTask.IsSuccessStatusCode)
{
return RedirectToAction("GetAllComics");
}
else
{
return View(model);
}
}
Here is the view model definition:
namespace ComicBookInventory.Shared
{
public class ComicBookWithAuthorsAndCharactersViewModel
{
public int Id { get; set; }
public string Title { get; set; }
public string Description { get; set; }
public bool IsRead { get; set; }
public DateTime? DateRead { get; set; }
public int? Rating { get; set; }
public string Genre { get; set; }
public string? CoverUrl { get; set; }
/// <summary>
/// Navigation properties
/// </summary>
/// a book can have many authors
public ICollection<string>? AuthorNames { get; set; }
public ICollection<string>? CharacterNames { get; set; }
}
}
My question is, I want to add a drop down checklist to the view, so that when I am creating a comic book, I can select Authors that currently exist in the database. The same for characters.
Here is the entire code base in case anyone is interested: https://github.com/rnemeth90/ComicBookInventoryApp
I normally try and figure things out on my own (I'm relatively new to EF Core, and have very little experience with many-to-many relationships in EF core). I have tried various things and struggled with this for most of my weekend. I feel like this should be relatively simple but cannot figure it out. Please help.
In your Code, I noticed that you used #Html.DropDownList to realzie the selector element, and using form submit to handle the data. So I did a test in my side:
#{
List<SelectListItem> listItems= new List<SelectListItem>();
listItems.Add(new SelectListItem
{
Text = "Exemplo1",
Value = "Exemplo1_v"
});
listItems.Add(new SelectListItem
{
Text = "Exemplo2",
Value = "Exemplo2_v",
Selected = true
});
listItems.Add(new SelectListItem
{
Text = "Exemplo3",
Value = "Exemplo3_v"
});
}
<form asp-action="Create">
<div class="form-group">
AuthorNames
<div class="col-md-10">
#Html.DropDownListFor(model => model.Author, listItems, "-- Select author --")
</div>
</div>
<div class="form-group">
<input type="submit" value="Create" class="btn btn-primary" />
</div>
</form>
My model contains a public string? Author { get; set; } property, and when I click the submit button, the select value will be submitted, so when you want to pass the FullName to your controller, you need to set it as the Value of the SelectListItem.

ASP.NET Core MVC - posting to a different action name does not bind the values

I'm using a regular html form instead of #html.BeginForm and I have these 2 form tags in my Create.cshtml view file.
I was experimenting with routing, but my post doesn't seem to get the values even if I bind the properties. I've tried in vain but I can't seem to make this work, and can't find the answer from googling.
Create.cshtml
#model Actor
#{
ViewData["Title"] = "Add";
}
<section class="container-xl justify-content-center col-lg-5 col-md-8 col-sm-10">
<div class="row">
<span class="text-center mb-3">
<h5>Add a new record</h5>
</span>
<div>
<form>
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
</form>
<div class="form-group">
<label class="form-label" asp-for="ProfilePictureUrl">Profile Picture</label>
<input class="mb-2 form-control" type="text" asp-for="ProfilePictureUrl" placeholder="Profile picture" />
</div>
<div class="form-group">
<label class="form-label" asp-for="FullName">Full Name</label>
<input class="mb-2 form-control" type="text" placeholder="Full name" asp-for="FullName" />
</div>
<div class="form-group">
<label class="form-label" asp-for="Bio">Biography</label>
<input class="form-control" type="text" placeholder="Bio" asp-for="Bio" />
</div>
<form>
<div class="form-group mt-3">
<a class="btn btn-outline-secondary" asp-action="Index">Show All</a>
<input asp-action="Create2" class="float-end btn btn-outline-success" type="submit" value="Create" />
</div>
</form>
</div>
</div>
</section>
Actor.cs
using System.ComponentModel.DataAnnotations;
namespace MovieProject.Models
{
public class Actor
{
[Key]
public int ActorId { get; set; }
[Display(Name ="Profile Picture")]
public string ProfilePictureUrl { get; set; }
[Display(Name ="Full Name")]
public string FullName { get; set; }
[Display(Name ="Biography")]
public string Bio { get; set; }
}
}
ActorController.cs
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using MovieProject.Data;
using MovieProject.Data.Services;
using MovieProject.Models;
namespace MovieProject.Controllers
{
public class ActorController : Controller
{
private readonly IActorService _service;
public ActorController(IActorService service)
{
_service = service;
}
[HttpPost]
public IActionResult Create2([Bind("ProfilePictureUrl,FullName,Bio")] Actor actorItem)
{
return View("Create");
}
public IActionResult Create()
{
return View();
}
}
}
The methods are getting hit but the post data is null.
Another question is, instead of using MVC convention, can I use a different method name for get and post that is not the same as the view name? How can I get initially load the page for GET using routing that would work in a different view name?
Thanks
can I use a different method name for get and post that is not the
same as the view name?
Yes, you can.
How can I get initially load the page for GET using routing that would
work in a different view name?
return to this view.
public IActionResult Create()
{
return View("aa");
}
Below is a work demo, you can refer to it.
In controller:
public IActionResult Create()
{
return View();
}
[HttpPost]
public IActionResult Create2(Actor actorItem)
{
return View();
}
Create view:
#model nnnn.Models.Actor
#{
ViewData["Title"] = "Create";
}
<h1>Create</h1>
<h4>Actor</h4>
<hr />
<div class="row">
<div class="col-md-4">
<form asp-action="Create2">
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
<div class="form-group">
<label asp-for="ActorId" class="control-label"></label>
<input asp-for="ActorId" class="form-control" />
<span asp-validation-for="ActorId" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="ProfilePictureUrl" class="control-label"></label>
<input asp-for="ProfilePictureUrl" class="form-control" />
<span asp-validation-for="ProfilePictureUrl" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="FullName" class="control-label"></label>
<input asp-for="FullName" class="form-control" />
<span asp-validation-for="FullName" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="Bio" class="control-label"></label>
<input asp-for="Bio" class="form-control" />
<span asp-validation-for="Bio" class="text-danger"></span>
</div>
<div class="form-group">
<input type="submit" value="Create" class="btn btn-primary" />
</div>
</form>
</div>
</div>
<div>
<a asp-action="Index">Back to List</a>
</div>
#section Scripts {
#{await Html.RenderPartialAsync("_ValidationScriptsPartial");}
}
result:

Decimal not recognized ASP.NET

I'm trying to insert a decimal number in one form but with no success. Everytime, I get this:
My entity is declared like this:
public class Serie
{
public int Id { get; set; }
public string Name { get; set; }
[RegularExpression(#"^\d+\.\d{0,2}$")]
[Range(0, 9999999999999999.99)]
public decimal Price { get; set; }
public string Description { get; set; }
public List<Season> Seasons { get; set; }
public List<Rental> Rentals { get; set; }
public List<Assessment> Assessments { get; set; }
}
On my razor page I have this on html side:
#page
#model Shows4All.Pages.Series.CreateModel
#{
ViewData["Title"] = "Create";
}
<h1>Create</h1>
<h4>Serie</h4>
<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="Serie.Name" class="control-label"></label>
<input asp-for="Serie.Name" class="form-control" />
<span asp-validation-for="Serie.Name" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="Serie.Price" class="control-label"></label>
<input type="number" asp-for="Serie.Price" class="form-control" />
<span asp-validation-for="Serie.Price" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="Serie.Description" class="control-label"></label>
<input asp-for="Serie.Description" class="form-control" />
<span asp-validation-for="Serie.Description" class="text-danger"></span>
</div>
<div class="form-group">
<input type="submit" value="Create" class="btn btn-primary" />
</div>
</form>
</div>
</div>
<div>
<a asp-page="Index">Back to List</a>
</div>
#section Scripts {
#{await Html.RenderPartialAsync("_ValidationScriptsPartial");}
}
I already tried without Data annotation and withou type="number" on html side...but it doesn't work. Any idea how can it be solved?
Try to add locale configuration in your aspet.config file like this:
<configuration>
<system.web>
<globalization culture ="en-US" />
</system.web>
</configuration>
If didn't work, try remove the Regex attribute and test it again.

How to fix http error 400 with microsoft ASP.NET MVC create command

I'm setting up a first C# ASP.NET MVC application using Microsofts tutorial. https://learn.microsoft.com/en-us/aspnet/core/tutorials/first-mvc-app/adding-model?view=aspnetcore-2.2&tabs=visual-studio
In the process of this tutorial, it asks to check if the create movies works, but when I attempt to use it, I get an HTTP error 400 - bad request. I believe the data I am entering is accurate, but I can't seem to get anything but a bad request, does anyone know how to fix this.
Model class:
using System;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
namespace MvcMovie.Models
{
public class Movie
{
public int Id { get; set; }
public string Title { get; set; }
[Display(Name = "Release Date")]
[DataType(DataType.Date)]
public DateTime ReleaseDate { get; set; }
public string Genre { get; set; }
[Column(TypeName = "decimal(18, 2)")]
public decimal Price { get; set; }
}
}
Razor view:
#model MvcMovie.Models.Movie
#{
ViewData["Title"] = "Create";
}
<h1>Create</h1>
<h4>Movie</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="Title" class="control-label"></label>
<input asp-for="Title" class="form-control" />
<span asp-validation-for="Title" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="ReleaseDate" class="control-label"></label>
<input asp-for="ReleaseDate" class="form-control" />
<span asp-validation-for="ReleaseDate" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="Genre" class="control-label"></label>
<input asp-for="Genre" class="form-control" />
<span asp-validation-for="Genre" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="Price" class="control-label"></label>
<input asp-for="Price" class="form-control" />
<span asp-validation-for="Price" class="text-danger"></span>
</div>
<div class="form-group">
<input type="submit" value="Create" 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 action method:
public async Task<IActionResult> Create([Bind("Id,Title,ReleaseDate,Genre,Price")] Movie movie)
{
if (ModelState.IsValid)
{
_context.Add(movie);
await _context.SaveChangesAsync();
return RedirectToAction(nameof(Index));
}
return View(movie);
}
The expected output is to add to the database, but but the actual output is bad request.
Do you have httpPost over method of controller and why you not use model?
[HttpPost]
public async Task<IActionResult> Create([Bind("Id,Title,ReleaseDate,Genre,Price")] ....
I was using google chrome, and firefox. Apparently it won't let me test on anything except edge or IE

Categories

Resources