I'm writing Application on ASP.NET Razor Pages(It's my homerwork).
Topic of this app is "Library" I have adding,deleting,modifying etc.
What i'm trying to do is. When i'm adding a new book, when it's genre of book i want to use dropdown list from database. I have been searching for this but i didn't find working solution for me.
So my Book class is:
Book.cs
public class Book
{
[Key]
public int Id { get; set; }
[Required]
[Display(Name = "Tytuł")]
public string Title { get; set; }
[Required]
[Display(Name = "Autor")]
public string Author { get; set; }
[Required]
[Display(Name = "Gatunek")]
public string Genre { get; set; }
[Required]
[Display(Name = "Rok Wydania")]
public int ReleaseYear { get; set; }
[Required]
[Display(Name = "Okładka")]
public string Cover { get; set; }
[Required]
[Display(Name = "Liczba Stron")]
public int NumberOfPages { get; set; }
[Required]
[Display(Name = "Opis")]
public string Description { get; set; }
}
Next i have Genre class
Genre.cs
[Key]
public int Id { get; set; }
[Required]
[Display(Name = "Gatunek")]
public string Name { get; set; }
I'm adding this to my ApplicationDbContext
ApplicationDbContext.cs
public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options)
: base(options)
{
}
public DbSet<Book> Book { get; set; }
public DbSet<Genre> Genre { get; set; }
AddBook.cshtml.cs
[Authorize(Roles = SD.AdminEndUser)]
public class AddBookModel : PageModel
{
private readonly ApplicationDbContext _db;
[BindProperty]
public Book Book { get; set; }
public AddBookModel(ApplicationDbContext db)
{
_db = db;
}
public IActionResult OnGet()
{
return Page();
}
public async Task <IActionResult> OnPostAsync(ServiceType ServiceType)
{
if(!ModelState.IsValid)
{
return Page();
}
_db.Book.Add(Book);
await _db.SaveChangesAsync();
return RedirectToPage("Index");
}
And
AddBook.cs
<form method="post">
<div class="border backgroundWhite">
<div class="form-group row">
<div class="col-2">
<label asp-for="Book.Title"></label>
</div>
<div class="col-5">
<input asp-for="Book.Title" class="form-control" />
</div>
<span asp-validation-for="Book.Title" class="text-danger"></span>
</div>
<div class="form-group row">
<div class="col-2">
<label asp-for="Book.Author"></label>
</div>
<div class="col-5">
<input asp-for="Book.Author" class="form-control" />
</div>
<span asp-validation-for="Book.Author" class="text-danger"></span>
</div>
<div class="form-group row">
<div class="col-2">
<label asp-for="Book.Genre"></label>
</div>
<div class="col-5">
<input asp-for="Book.Genre" class="form-control" />
</div>
<span asp-validation-for="Book.Genre" class="text-danger"></span>
</div>
<div class="form-group row">
<div class="col-2">
<label asp-for="Book.ReleaseYear"></label>
</div>
<div class="col-5">
<input asp-for="Book.ReleaseYear" class="form-control" />
</div>
<span asp-validation-for="Book.ReleaseYear" class="text-danger"></span>
</div>
<div class="form-group row">
<div class="col-2">
<label asp-for="Book.NumberOfPages"></label>
</div>
<div class="col-5">
<input asp-for="Book.NumberOfPages" class="form-control" />
</div>
<span asp-validation-for="Book.NumberOfPages" class="text-danger"></span>
</div>
<div class="form-group row">
<div class="col-2">
<label asp-for="Book.Cover"></label>
</div>
<div class="col-5">
<input asp-for="Book.Cover" class="form-control" />
</div>
<span asp-validation-for="Book.Cover" class="text-danger"></span>
</div>
<div class="form-group row">
<div class="col-2">
<label asp-for="Book.Description"></label>
</div>
<div class="col-5">
<input asp-for="Book.Description" class="form-control" />
</div>
<span asp-validation-for="Book.Description" class="text-danger"></span>
</div>
<div class="form-group row">
<div class="col-5 offset-2">
<partial name="_AddAndBackToListButton" />
</div>
</div>
</div>
I have working connection with Db. I just don't know what i should do next to make dropdownlist. I'm not interested in solution with controllers!
Any ideas ?
Thank you for assistance!
This is a possible repeat of:
How to write a simple Html.DropDownListFor()? (Answered Jun 16 '10 )
But anyway, I'll try and answer:
If you're writing it in Razor syntax, you can just use the same solution as the link above. Create an HtmlDropdownFor, and as the argument perform a LINQ query on your List<Genre> (list of of genres, or dictionary of genres, whichever iterable you might need)
Otherwise, you can just manually write a <select></select> input inside each of the HTML form that requires it. Obviously this is more time-consuming, but you can find more info on how to do that, at w3 schools: HTML Form Elements, specifically the section about <select>
Related
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:
I am trying to Insert a new record into my database. But when try to add a "User" of any role, I get the following error, Screenshot. For my class layout, I have a "User" class, and then the subclasses, Parent/SubjectCoordinator/Teacher/Secretary/Student.
I'm using EF6, VS2022, C#.
What could be the possible cause of it? Thanks.
This is my program.cs
using Microsoft.EntityFrameworkCore;
using Microsoft.AspNetCore.Authentication.Cookies;
using Attempt7.Data;
using Microsoft.AspNetCore.Identity;
using Microsoft.Extensions.DependencyInjection;
var builder = WebApplication.CreateBuilder(args);
string connString = builder.Configuration.GetConnectionString("DefaultConnection");
// Add services to the container.
builder.Services.AddControllersWithViews();
builder.Services.AddSession();
builder.Services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
builder.Services.AddControllers();
builder.Services.AddDbContext<ApplicationDBContext>(options =>
{
options.UseSqlServer(builder.Configuration.GetConnectionString("DefaultConnection"));
});
var app = builder.Build();
// Configure the HTTP request pipeline.
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler("/Home/Error");
// The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
app.UseHsts();
}
app.UseSession();
app.UseDefaultFiles();
app.UseStaticFiles();
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseAuthorization();
app.UseSession();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
app.MapControllerRoute(
name: "default",
pattern: "{controller=Home}/{action=Index}/{id?}");
app.Run();
This is my User Class
public abstract class User
{
[Key]
public int UserID { get; set; }
public string Name { get; set; }
[Required]
public string Surname { get; set; }
public DateTime DOB { get; set; }
public string Gender { get; set; }
public string CellNumber { get; set; }
[Required(ErrorMessage = "This field is required")]
[DataType(DataType.Password)]
public string Password { get; set; }
[Required(ErrorMessage = "This field is required")]
public string Email { get; set; }
public string AddressLine1 { get; set; }
public string AddressLine2 { get; set; }
public int SuburbID { get; set; }
public DateTime DateHired { get; set; }
public string Title { get; set; }
public int RoleID { get; set; }
public string AlternativeContactNumber { get; set; }
public string AlternativeContactFullName { get; set; }
public string ErrorMessage { get; set; } = "";
public virtual Suburb Suburb { get; set; }
[ForeignKey(nameof(RoleID))]
public virtual Role Role { get; set; }
}
This is my Teacher Class.
public class Teacher : User
{
[Required]
public DateTime DateJoined { get; set; } = DateTime.Now;
[StringLength(1)]
[Required]
public char Is_Active { get; set; } = 'T';
[ForeignKey("UserID")]
public virtual User User { get; set; }
}
This is my Student Class
public class Student : User
{
[Required]
public DateTime DateJoined { get; set; } = DateTime.Now;
[StringLength(1)]
[Required]
public char Is_Active { get; set; } = 'T';
[ForeignKey("UserID")]
public virtual User User { get; set; }
}
The other 3 subclasses are similar with the difference being their unique properties.
And this is the controller action I'm calling
public IActionResult Create()
{
ViewData["RoleID"] = new SelectList(_db.Role, "RoleID", "RoleName");
ViewData["SuburbID"] = new SelectList(_db.Suburb, "SuburbID", "SuburbID");
return View();
}
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Create([FromServices][Bind("UserID,Name,Surname,DOB,Gender,CellNumber,Password,Email,AddressLine1,AddressLine2,SuburbID,DateHired,Title,RoleID,AlternativeContactNumber,AlternativeContactFullName,ErrorMessage")] User user)
{
int SelectedRole = user.RoleID;
if (ModelState.IsValid)
{
if (SelectedRole == 1)//Student
{
Student student = new Student();
student = (Student)user;
_db.Add(student);
}
else if (SelectedRole == 2)//Teacher
{
Teacher teacher = new Teacher();
teacher = (Teacher)user;
_db.Add(teacher);
}
else if (SelectedRole == 3)//SubjectCoordinator
{
SubjectCoordinator subjectcoordinator = new SubjectCoordinator();
subjectcoordinator = (SubjectCoordinator)user;
_db.Add(subjectcoordinator);
}
else if (SelectedRole == 4)//Parent
{
Parent parent = new Parent();
parent = (Parent)user;
_db.Add(parent);
}
else if (SelectedRole == 5)//Secretary
{
Secretary secretary = new Secretary();
secretary = (Secretary)user;
_db.Add(secretary);
}
await _db.SaveChangesAsync();
return RedirectToAction("Index");
}
ViewData["RoleID"] = new SelectList(_db.Role, "RoleID", "RoleName", user.RoleID);
ViewData["SuburbID"] = new SelectList(_db.Suburb, "SuburbID", "SuburbID", user.SuburbID);
return View(user);
}
I'm using an generated view.
#model Attempt7.Models.User
#{
ViewData["Title"] = "Create";
}
<h1>Create</h1>
<h4>User</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="RoleID" class="control-label"></label>
<select asp-for="RoleID" class ="form-control" asp-items="ViewBag.RoleID"></select>
</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>
<div class="form-group">
<label asp-for="Surname" class="control-label"></label>
<input asp-for="Surname" class="form-control" />
<span asp-validation-for="Surname" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="DOB" class="control-label"></label>
<input asp-for="DOB" class="form-control" />
<span asp-validation-for="DOB" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="Gender" class="control-label"></label>
<input asp-for="Gender" class="form-control" />
<span asp-validation-for="Gender" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="CellNumber" class="control-label"></label>
<input asp-for="CellNumber" class="form-control" />
<span asp-validation-for="CellNumber" class="text-danger"></span>
</div>-->
<div class="form-group">
<label asp-for="Password" class="control-label"></label>
<input asp-for="Password" class="form-control" />
<span asp-validation-for="Password" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="Email" class="control-label"></label>
<input asp-for="Email" class="form-control" />
<span asp-validation-for="Email" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="AddressLine1" class="control-label"></label>
<input asp-for="AddressLine1" class="form-control" />
<span asp-validation-for="AddressLine1" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="AddressLine2" class="control-label"></label>
<input asp-for="AddressLine2" class="form-control" />
<span asp-validation-for="AddressLine2" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="SuburbID" class="control-label"></label>
<select asp-for="SuburbID" class ="form-control" asp-items="ViewBag.SuburbID"></select>
</div>
<div class="form-group">
<label asp-for="DateHired" class="control-label"></label>
<input asp-for="DateHired" class="form-control" />
<span asp-validation-for="DateHired" 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="AlternativeContactNumber" class="control-label"></label>
<input asp-for="AlternativeContactNumber" class="form-control" />
<span asp-validation-for="AlternativeContactNumber" class="text-danger"></span>
</div>
<div class="form-group">
<label asp-for="AlternativeContactFullName" class="control-label"></label>
<input asp-for="AlternativeContactFullName" class="form-control" />
<span asp-validation-for="AlternativeContactFullName" 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");}
}
This is also the layout of my User table Screenshot in SQL Server
I get the error below each time I click on the "Add Product". I would be so thankful for any tips on why I get this error
SqlException: The INSERT statement conflicted with the FOREIGN KEY constraint "FK_Products_Categories_CategoryId". The conflict occurred in database "eCommerce", table "dbo.Categories", column 'CategoryId'. The statement has been terminated.
Home view:
<div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1">
<ul class="nav navbar-nav">
<li><a asp-controller="Home" asp-action="Index">Home</a></li>
<li><a asp-controller="Product" asp-action="AddProduct">Add product</a></li>
enter code here
</ul>
</div>
AppDbContext.cs
public class AppDbContext : IdentityDbContext<IdentityUser>
{
public AppDbContext(DbContextOptions<AppDbContext> options) : base(options)
{
}
public DbSet<Category> Categories { get; set; }
public DbSet<Product> Products { get; set; }
}
My models:
Product.cs and Category.cs models:
public class Product
{
public int ProductId { get; set; }
public string Name { get; set; }
public string ShortDescription { get; set; }
public string LongDescription { get; set; }
public decimal Price { get; set; }
public string ImageUrl { get; set; }
public string ImageThumbnailUrl { get; set; }
public bool IsProductOfTheWeek { get; set; }
public bool InStock { get; set; }
public int CategoryId { get; set; }
public Category Category { get; set; }
}
public class Category
{
public int CategoryId { get; set; }
public string CategoryName { get; set; }
public string Description { get; set; }
public List<Product> Products { get; set; }
}
My controller: Productontroller.cs
[HttpPost]
public IActionResult AddProduct(Product product)
{
if (ModelState.IsValid)
{
_appDbContext.Products.Add(product);
_appDbContext.SaveChanges();
return RedirectToAction("SeedComplete");
}
return View(product);
}
public IActionResult SeedComplete()
{
ViewBag.SeedCompleteMessage = "Thanks for adding the product!";
return View();
}
My view:
AddProduct.cshtml
#model Product
<form asp-action="AddProduct" method="post" class="form-horizontal" role="form">
<h4>You're just one step away.</h4>
<div asp-validation-summary="All" class="text-danger"></div>
<div class="form-group">
<label asp-for="Name" class="col-md-2 control-label"></label>
<div class="col-md-5">
<input asp-for="Name" class="form-control" />
<span asp-validation-for="Name" class="text-danger"></span>
</div>
</div>
<div class="form-group">
<label asp-for="Price" class="col-md-2 control-label"></label>
<div class="col-md-5">
<input asp-for="Price" class="form-control" />
<span asp-validation-for="Price" class="text-danger"></span>
</div>
</div>
<div class="form-group">
<label asp-for="ShortDescription" class="col-md-2 control-label"></label>
<div class="col-md-5">
<input asp-for="ShortDescription" class="form-control" />
<span asp-validation-for="ShortDescription" class="text-danger"></span>
</div>
</div>
<div class="form-group">
<label asp-for="LongDescription" class="col-md-2 control-label"></label>
<div class="col-md-5">
<input asp-for="LongDescription" class="form-control" />
<span asp-validation-for="LongDescription" class="text-danger"></span>
</div>
</div>
<div class="form-group">
<label asp-for="ImageUrl" class="col-md-2 control-label"></label>
<div class="col-md-5">
<input asp-for="ImageUrl" class="form-control" />
<span asp-validation-for="ImageUrl" class="text-danger"></span>
</div>
</div>
<div class="form-group">
<label asp-for="ImageThumbnailUrl" class="col-md-2 control-label"></label>
<div class="col-md-5">
<input asp-for="ImageThumbnailUrl" class="form-control" />
<span asp-validation-for="ImageThumbnailUrl" class="text-danger"></span>
</div>
</div>
<div class="form-group">
<label asp-for="IsProductOfTheWeek" class="col-md-2 control-label"></label>
<div class="col-md-5">
<input asp-for="IsProductOfTheWeek" class="form-control" />
<span asp-validation-for="IsProductOfTheWeek" class="text-danger"></span>
</div>
</div>
<div class="form-group">
<label asp-for="InStock" class="col-md-2 control-label"></label>
<div class="col-md-5">
<input asp-for="InStock" class="form-control" />
<span asp-validation-for="InStock" class="text-danger"></span>
</div>
</div>
<div class="form-group">
<div class="col-md-offset-2 col-md-5">
<input id="btn" type="submit" class="btn btn-primary" value="Complete the seed" />
</div>
</div>
</form>
SeedComplete.cshtml:
<h1>#ViewBag.SeedCompleteMessage </h1>
I don't see in the cshtml where you would be setting CategoryId, which means it is likely getting set to 0, which would cause a foreign key constraint violation.
Set a breakpoint in your controller code on this line:
_appDbContext.Products.Add(product);
And see if the CategoryId is 0.
I have a model Event with a ViewModel, Controller and View.
In this case it is about the CreateView
Model
using System;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
namespace Verbonding.Models
{
public class Event
{
public int Id { get; set; }
[Required]
public string Name { get; set; }
[Required]
public string Description { get; set; }
[Required]
public DateTime EventStart { get; set; }
public DateTime EventEnd { get; set; }
public int OrganizationId { get; set; }
public int AddressId { get; set; }
[ForeignKey("Category")]
public int CategoryId { get; set; }
public virtual Organization Organization { get; set; }
public virtual Address Address { get; set; }
public virtual Category Category { get; set; }
}
}
ViewModel
using System;
using System.Collections.Generic;
namespace Verbonding.Models.EventViewModels
{
public class CreateViewModel
{
public string Name { get; set; }
public int? CategoryId { get; set; }
public List<Category> Categories { get; set; }
public string Description { get; set; }
public string LocationName { get; set; }
public string Street { get; set; }
public string HouseNr { get; set; }
public string PostalCode { get; set; }
public string City { get; set; }
public DateTime EventStartDate { get; set; }
public DateTime EventEndDate { get; set; }
}
}
Controller
I removed the actions that are not required for this question.
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Rendering;
using Microsoft.EntityFrameworkCore;
using Verbonding.Data;
using Verbonding.Models;
using Verbonding.Services;
using Verbonding.Models.EventViewModels;
using Microsoft.AspNetCore.Authorization;
namespace Verbonding.Controllers
{
public class EventsController : Controller
{
private readonly ApplicationDbContext _context;
private IEventData _eventData;
private IOrganizationData _organizationData;
private IAddressData _addressData;
private ICategoryData _categoryData;
private ICountryData _countryData;
public EventsController(IEventData eventData,
IOrganizationData organizationData,
IAddressData addressData,
ICategoryData categoryData,
ICountryData countryData)
{
_eventData = eventData;
_organizationData = organizationData;
_addressData = addressData;
_categoryData = categoryData;
_countryData = countryData;
}
[Authorize]
public IActionResult Create()
{
CreateViewModel model = new CreateViewModel();
var categories = _categoryData.GetChildCategories();
model.Categories = new List<Category>(categories);
return View(model);
}
[Authorize]
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Create(CreateViewModel model)
{
if (ModelState.IsValid)
{
Category category = _categoryData.Get(model.CategoryId.GetValueOrDefault());
Country country = _countryData.Get(1);
_eventData.Add(model.Name, category, model.Description, model.LocationName, model.Street,
model.HouseNr, model.PostalCode, model.City, country, model.EventStartDate, model.EventEndDate);
_eventData.Commit();
await _context.SaveChangesAsync();
return RedirectToAction("Index");
}
else
{
var categories = _categoryData.GetChildCategories();
model.Categories = new List<Category>(categories);
}
return View(model);
}
}
}
View
#model Verbonding.Models.EventViewModels.CreateViewModel
#{
ViewData["Title"] = "Create";
}
<h2>Create</h2>
<form asp-action="Create">
<div class="form-horizontal">
<hr />
<h4>Algemene gegevens</h4>
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
<div class="form-group">
<label asp-for="Name" class="col-md-2 control-label"></label>
<div class="col-md-10">
<input asp-for="Name" class="form-control" />
<span asp-validation-for="Name" class="text-danger" />
</div>
</div>
<div class="form-group">
<label asp-for="CategoryId" class="col-md-2 control-label"></label>
<div class="col-md-10">
<select asp-for="CategoryId" asp-items="#(new SelectList(Model.Categories, "Id", "Name"))" class="form-control">
<option>Please select a Category</option>
</select>
</div>
</div>
<div class="form-group">
<label asp-for="Description" class="col-md-2 control-label"></label>
<div class="col-md-10">
<textarea asp-for="Description" class="form-control" rows="5" cols="100"></textarea>
<span asp-validation-for="Description" class="text-danger" />
</div>
</div>
<hr />
<h4>Adresgegevens Evenement Evenement</h4>
<div class="form-group">
<label asp-for="LocationName" class="col-md-2 control-label"></label>
<div class="col-md-10">
<input asp-for="LocationName" class="form-control" />
<span asp-validation-for="LocationName" class="text-danger" />
</div>
</div>
<div class="form-group">
<label asp-for="Street" class="col-md-2 control-label"></label>
<div class="col-md-10">
<div><input asp-for="Street" class="form-control" style="width: 200px; float: left"/></div>
<div><input asp-for="HouseNr" class="form-control" style="width: 60px; float: left; margin-left: 20px" /></div>
<span asp-validation-for="Street" class="text-danger" />
<span asp-validation-for="HouseNr" class="text-danger" />
</div>
</div>
<div class="form-group">
<label asp-for="PostalCode" class="col-md-2 control-label"></label>
<div class="col-md-10">
<input asp-for="PostalCode" class="form-control" />
<span asp-validation-for="PostalCode" class="text-danger" />
</div>
</div>
<div class="form-group">
<label asp-for="City" class="col-md-2 control-label"></label>
<div class="col-md-10">
<input asp-for="City" class="form-control" />
<span asp-validation-for="City" class="text-danger" />
</div>
</div>
<hr />
<h4>Tijden Evenement</h4>
<div class="form-group">
<label asp-for="EventStartDate" class="col-md-2 control-label"></label>
<div class="col-md-10">
<input asp-for="EventStartDate" class="form-control" />
<span asp-validation-for="EventStartDate" class="text-danger" />
</div>
</div>
<div class="form-group">
<label asp-for="EventEndDate" class="col-md-2 control-label"></label>
<div class="col-md-10">
<input asp-for="EventEndDate" class="form-control" />
<span asp-validation-for="EventEndDate" class="text-danger" />
</div>
</div>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" value="Opslaan" class="btn btn-default" />
</div>
</div>
</div>
</form>
<div>
<a asp-action="Index">Back to List</a>
</div>
#section Scripts {
#{await Html.RenderPartialAsync("_ValidationScriptsPartial");}
}
Now when I test this, the page does reload, and the fields that have been entered stay there, but there are no validation errors.
What can I do to get the validation errors on the page?
Update
I found out that the properties of the DateTime type are required by default,
so I have changed these.
In the model:
[DisplayFormat(ApplyFormatInEditMode = true, DataFormatString = "{0:dd-MM-yyyy HH:mm}")]
public DateTime EventStart { get; set; }
[DisplayFormat(ApplyFormatInEditMode = true, DataFormatString = "{0:dd-MM-yyyy HH:mm}")]
public DateTime? EventEnd { get; set; }
In the ViewModel:
public DateTime EventStartDate { get; set; }
public DateTime? EventEndDate { get; set; }
This seems to have the desired effect for these fields.
Update 2
Based on the comments from Dai I have updated the Model and ViewModel.
To test it out I started with the Name property and left the rest as it is.
In the Model:
public string Name { get; set; }
In the ViewModel:
[required]
public string Name { get; set; }
At first this did not have the desired effect. (But also no errors)
Then I changed required to Required with a capital R, and that did the trick.
I also needed to add using System.ComponentModel.DataAnnotations;, but that was nicely handled by Visual Studio.
try to create file _ViewImports.chtml into your Views folder. Then add following lines to the file:
#using Microsoft.AspNetCore.Identity
#addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
I try to reinterpretate [this simple tutorial][1]
In Book model I remove ScaffoldColumn(false) above public int AuthorID to have select AuthorID in my view.
After rebiuld I can see this select in Books/Create but it has no options.
In my database I can see, that all my items added in SampleData model has BookID and AuthorID.
Why it has no result in html ?
Edited:
My Book.cs
using System.ComponentModel.DataAnnotations;
namespace ContosoBooks.Models
{
public class Book
{
public int BookID { get; set; }
[Required]
public string Title { get; set; }
public int Year { get; set; }
[Range(1, 500)]
public decimal Price { get; set; }
public string Genre { get; set; }
public int AuthorID { get; set; }
// Navigation property
public virtual Author Author { get; set; }
}
}
My Author.cs
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
namespace ContosoBooks.Models
{
public class Author
{
public int AuthorID { get; set; }
[Required]
[Display(Name = "Last Name")]
public string LastName { get; set; }
[Display(Name = "First Name")]
public string FirstMidName { get; set; }
public virtual ICollection<Book> Books { get; set; }
}
}
My Scaffolded generated View for Books Create (Create.cshtml)
#model ContosoBooks.Models.Book
#{
ViewData["Title"] = "Create";
}
<h2>Create</h2>
<form asp-action="Create">
<div class="form-horizontal">
<h4>Book</h4>
<hr />
<div asp-validation-summary="ValidationSummary.ModelOnly" class="text-danger"></div>
<div class="form-group">
<label asp-for="AuthorID" class="col-md-2 control-label"></label>
<div class="col-md-10">
<select asp-for="AuthorID" class ="form-control"></select>
</div>
</div>
<div class="form-group">
<label asp-for="Genre" class="col-md-2 control-label"></label>
<div class="col-md-10">
<input asp-for="Genre" class="form-control" />
<span asp-validation-for="Genre" class="text-danger" />
</div>
</div>
<div class="form-group">
<label asp-for="Price" class="col-md-2 control-label"></label>
<div class="col-md-10">
<input asp-for="Price" class="form-control" />
<span asp-validation-for="Price" class="text-danger" />
</div>
</div>
<div class="form-group">
<label asp-for="Title" class="col-md-2 control-label"></label>
<div class="col-md-10">
<input asp-for="Title" class="form-control" />
<span asp-validation-for="Title" class="text-danger" />
</div>
</div>
<div class="form-group">
<label asp-for="Year" class="col-md-2 control-label"></label>
<div class="col-md-10">
<input asp-for="Year" class="form-control" />
<span asp-validation-for="Year" class="text-danger" />
</div>
</div>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" value="Create" class="btn btn-default" />
</div>
</div>
</div>
</form>
<div>
<a asp-action="Index">Back to List</a>
</div>
#section Scripts {
<script src="~/lib/jquery/dist/jquery.min.js"></script>
<script src="~/lib/jquery-validation/dist/jquery.validate.min.js"></script>
<script src="~/lib/jquery-validation-unobtrusive/jquery.validate.unobtrusive.min.js"></script>
}
[1]: http://docs.asp.net/en/latest/tutorials/your-first-aspnet-application.html
On your create page it won't display the ID because it has no value and the application is anticipating the ID will be generated when the object is inserted into the database.