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

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");

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; }
}
}

cannot convert between an Identity Class and a local one in ASP.net MVC

I'm currently developing with ASP.NET MVC and after I have created the an error of converting a local class to an Identity one cannot implicitly convert "ListUsers" to "Identity.IdentityUser"(I simplified the error a bit) anyway, here are some bits of code:
ListUsersController.cs:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using ServiceReferenceAuthentication;
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Rendering;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;
using SoftSMS.Data.Data;
using SoftSMS.Data.Entities;
using SoftSMS.Data.Entity;
using SoftSMS.Data.Interfaces;
using SoftSMS.MVC.ViewModels;
namespace SoftSMS.MVC.Controllers
{
public class ListUsersController : Controller
{
private readonly DataContext _context;
private readonly RoleManager<IdentityRole> roleManager;
private readonly UserManager<ListUsers> userManager;
private readonly IConfiguration configuration;
private readonly IUnitOfWork<ListUsers> _users;
//private readonly DataContext _context;
public ListUsersController(IUnitOfWork<ListUsers> Users/*DataContext context*/)
{
_users = Users;
//_context = context;
}
// GET: ListUsers
public IActionResult Index()
{
return View(_users.Entity.GetAll());
}
// GET: ListUsers/Details/5
public async Task<IActionResult> DetailsAsync(Guid? id)
{
if (id == null)
{
return NotFound();
}
...
if (listUsers == null)
{
return NotFound();
}
return View(listUsers);
}
// GET: ListUsers/Create
public IActionResult Create()
{
return View();
}
// POST: ListUsers/Create
// To protect from overposting attacks, please 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> Create([Bind("Id,UserName,FirstName,LastName,Status,Profil")] ListUsers listUsers)
{
try
{
TPFAuthenticationSoapClient.EndpointConfiguration endpointConfiguration = new TPFAuthenticationSoapClient.EndpointConfiguration();
TPFAuthenticationSoapClient servAuth = new TPFAuthenticationSoapClient(endpointConfiguration);
if ((Boolean)TempData["isValid"] == false)
{
IdentityUser u = await userManager.FindByNameAsync(listUsers.UserName);
if (u != null)
{
ViewBag.IsValid = false;
ModelState.AddModelError(string.Empty, "Ce Compte existe déja");
}
else
{
...;
if (x != null)
{
...
return View(listUsers);
}
else
{
...
}
}
}
else
{
...
return RedirectToAction(nameof(Index));
}
return View(listUsers);
}
catch (Exception ex)
{
...
return RedirectToAction(nameof(Create));
}
}
the error is in IdentityUser u = await userManager.FindByNameAsync(listUsers.UserName);
I don't want to create an operator override as it's suggested (nor explicit conversion),
ListUsers.cs:
using Microsoft.AspNet.Identity.EntityFramework;
using SoftSMS.Data.Entities;
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Identity;
namespace SoftSMS.Data.Entity
{ public enum StatusType
{ Banned,Registered,Normal,Warned}
public enum ProfilType
{ Admin,Manager,Agent}
public class ListUsers : IdentityUser
{
[DataType(DataType.Text)]
public string FirstName { get; set; }
[DataType(DataType.Text)]
public string LastName { get; set; }
[DataType(DataType.Text)]
[Required]
public StatusType Status { get; set; }
public ProfilType Profil { get; set; }
public virtual ICollection<MembershipAssociations> MembershipAssociation { get; set; }
public virtual ICollection<Template> TemplateNavigation { get; set; }
public virtual ICollection<SentMsg> SentmsgNavigation { get; set; }
}
}
UsersViewModel.cs:
using Microsoft.AspNetCore.Identity;
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Threading.Tasks;
namespace SoftSMS.MVC.ViewModels
{ public enum StatusType
{ Banned,Registered,Normal,Warned}
public enum ProfilType
{ Admin,Manager,Agent}
public class UsersViewModel : IdentityUser
{
public string FirstName { get; set; }
public string LastName { get; set; }
public StatusType Status { get; set; }
public ProfilType Profil { get; set; }
public List<MembershipAssociationViewModel> MembershipAssociation { get; set; }
public List<SentMsgViewModel> Sentmsg { get; set; }
}
}
and Create.cshtml:
#model SoftSMS.MVC.ViewModels.UsersViewModel
#{ ViewData["Title"] = "Create"; }
#{TempData["isValid"] = ViewBag.isValid;}
<br />
<h3>Nouvel Utilisateur</h3>
<hr />
#*#ViewBag.Result1*#
<br />
<h4 style="color: red;">#TempData["errorMessage"]</h4>
<div class="row">
<div class="col-md-4">
<form asp-action="Create">
<div asp-validation-summary="ModelOnly" class="text-danger"></div>
#if ((Boolean)ViewBag.isValid == false)
{
<div class="form-group">
<label asp-for="UserName" class="control-label">Login</label>
<input asp-for="UserName" class="form-control" />
<span asp-validation-for="UserName" class="text-danger"></span>
</div> }
#if ((Boolean)ViewBag.isValid == true)
{
<input type="hidden" asp-for="Id" />
<div class="form-group">
<label asp-for="UserName" class="control-label">Login</label>
<input asp-for="UserName" class="form-control" disabled="disabled" />
#Html.HiddenFor(model => model.UserName)
</div>
<div class="form-group">
<label asp-for="FirstName" class="control-label">Prenom</label>
<input asp-for="FirstName" class="form-control" disabled="disabled" />
#Html.HiddenFor(model => model.FirstName)
</div>
<div class="form-group">
<label asp-for="LastName" class="control-label">Nom</label>
<input asp-for="LastName" class="form-control" disabled="disabled" />
#Html.HiddenFor(model => model.LastName)
</div>
<div class="form-group">
<label asp-for="Email" class="control-label">Email</label>
<input asp-for="Email" class="form-control" disabled="disabled" />
#Html.HiddenFor(model => model.Email)
</div>
<div class="form-group">
<label asp-for="EstActif" class="control-label">Actif</label>
<select id="Select1" asp-for="EstActif" class="form-control">
<option value="True"> <text>OUI</text></option>
<option value="False"> <text>NON</text></option>
</select>
</div> }
<div class="form-group">
<input type="submit" value="Creer" class="btn btn-primary" />
</div>
</form>
</div>
</div>
<div>
<a asp-action="Index">Liste des utilisateurs</a>
</div>
#section Scripts {
#{await Html.RenderPartialAsync("_ValidationScriptsPartial");}
}
as you could have seen, I had to make the UI in French (even though I don't like it) because I am developing this platform for French people,
if you need another resource, I could share it, but not the entire app, the ...is for a confidential code,
thank you

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

How to use 2 Models in a View

How can I use Two different models into the same view?
Why I need this?
I need to do a create view where the client fills his registry, and I need to have 1 combo box/select form(This form needs to load the strings from the other model).
Here is what I have tried:
Creating a ViewModel for both of the Models that looks like this:
public class CandidateViewModel
{
public int Id { get; set; }
public string Name { get; set; }
public int Number { get; set; }
public string Profile { get; set; }
public Byte[] CV { get; set; }
public string CVNAME { get; set; }
public List<Profile> ProfileList { get; set; }
public string ProfileText { get; set; }
}
ProfileList and ProfileText are from ProfileModel, the rest is from the CandidateModel.
My controller right now looks like this:
public IActionResult Candidate(Candidate candidate, string searchString)
{
using (var aplicationDbContext = new ApplicationContext())
{
var candidates = from m in aplicationDbContext.Candidates select m;
if (!String.IsNullOrEmpty(searchString))
{
candidates = candidates.Where(s => s.Name.Contains(searchString) || s.Number.ToString().Contains(searchString) || s.ProfileText.Contains(searchString));
}
return View(candidates.ToList());
}
}
public IActionResult CandidateCreate()
{
using (var applicationcontext = new ApplicationContext())
{
var ProfileTextFromProfile = applicationcontext.Candidates.Include(q => q.ProfileList);
return View(ProfileTextFromProfile);
}
return View();
}
[HttpPost, ActionName("CandidateCreate")]
[ValidateAntiForgeryToken]
public IActionResult CandidateCreatePost([Bind("Name,Number,Profile,CV,CVID")] Candidate candidate, IFormFile CV,string profileText, int Id)
{
if (ModelState.IsValid)
{
if (CV != null)
{
if (CV.Length > 0)
{
byte[] p1 = null;
using (var fs1 = CV.OpenReadStream())
using (var ms1 = new MemoryStream())
{
fs1.CopyTo(ms1);
p1 = ms1.ToArray();
}
candidate.CVNAME = CV.FileName;
candidate.CV = p1;
}
}
using (var applicationcontext = new ApplicationContext())
{
var ProfileTextFromProfile = applicationcontext.Profile.Include(q => q.ProfileList);
//var ProfileTextFromProfile = applicationcontext.Profile.Include(q => q.ProfileText).Single(q => q.Id == Id);
//ProfileTextFromProfile.ProfileText.Add(new Candidate() { Profile = profileText });
}
candidateRepository.Add(candidate);
candidateRepository.SaveChanges();
return RedirectToAction("Candidate");
}
return View();
}
But I don't know what acctually I need to do after this, I'm really new to this and I'm doing this work as an intership soo I'm still learning, If have any doubts about my question please ask me and I will try to explain.
Also here is my View where I need to use both of the models.
#*model HCCBPOHR.Data.Candidate*#
#model HCCBPOHR.DomainModel.CandidateModel
#{
ViewData["Title"] = "CandidateCreate";
}
<h2>CandidateCreate</h2>
<h4>Candidate</h4>
<hr />
<div class="row">
<div class="col-md-4">
<form method="post" enctype="multipart/form-data" asp-action="CandidateCreate">
<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>
<div class="form-group">
<label asp-for="Number" class="control-label"></label>
<input asp-for="Number" class="form-control" maxlength="9" />
<span asp-validation-for="Number" class="text-danger"></span>
</div>
<div class="form-group">
<label>Selects</label>
<select asp-for="Profile" class=" form-control ">
<option>1</option>
<option>2</option>
<option>3</option>
<option>4</option>
<option>5</option>
</select>
</div>
<div class="form-group">
<label asp-for="CV" type="file" class="control-label"></label>
<input asp-for="CV" type="file" class="form-control" />
</div>
<div class="form-group">
<input type="submit" value="Create" class="btn btn-default" onclick="this.disabled=true;this.form.submit();" />
</div>
</form>
</div>
</div>
<div>
<a asp-action="Index">Back to List</a>
</div>
You can apply MVVM pattern in this scenario.
Here is example:
I will define 3 class in Model folder
public class Post
{
public string Id {get;set;}
public string Content {get;set;}
public string UserId {get;set;}
}
public class Comment
{
public string Id {get;set;}
public string Content {get;set;}
public string PostId {get;set;}
}
// this will hold data for 2 class above
public class PostVM
{
public Post Post {get;set}
public Comment Comment {get;set}
}
Then in my controller I will query to db to get data for post and comment like this
public IActionResult PostDetail(string postId)
{
var post = _postRepository.GetPostById(postId);
var comment = _commentRepository.GetCommentByPostId(postId);
// MVVM model return to the view
var vM = new PostVM
{
Post = post,
Comment = comment
}
}
Finally in my view
#model PostVM
<div> #model.Post.Content </div>
#foreach(var comment in #model.Comment)
{
<div> #comment.Content</div>
}
Please adjust accordingly with your code. If you have any problem please let me know.
Cheers

Edit View not passing data correctly

I'm trying to edit an element through the edit view. While debugging, I've noticed that the object I'm trying to update the database with has null or zeroed fields. The edit view seems to not return the data I'm entering.
Model:
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.Data.Entity;
using Microsoft.Data.Entity.Infrastructure;
namespace METALIMPEX.Models
{
public class Condition
{
[Key]
[Display(Name = "Condition ID")]
[Column("condition_id")]
[Required]
public int conditionID { get; set; }
[Display(Name = "Date and time")]
[Column("condition_date")]
[Timestamp]
[Required]
public DateTime dateTime { get; set; }
[Display(Name = "Component ID")]
[Column("component")]
[Required]
public int componentID { get; set; }
[Display(Name = "Operator ID")]
[Column("operator")]
[Required]
public int operatorID { get; set; }
[Display(Name = "Component status")]
[Column("condition")]
[Required]
public bool condition { get; set; }
[Display(Name = "Comments")]
[Column("remarks")]
[Required]
public string comments { get; set; }
}
public class ConditionDBContext : DbContext
{
public DbSet<Condition> Conditions { get; set; }
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
optionsBuilder.UseSqlServer("Data Source=DELL-XPS\\SQLEXPRESS;Initial Catalog=METALIMPEX;Integrated Security=True");
}
}
}
Controller:
using System.Linq;
using Microsoft.AspNet.Mvc;
using Microsoft.AspNet.Mvc.Rendering;
using Microsoft.Data.Entity;
using METALIMPEX.Models;
using System.Data.SqlClient;
using System.Collections.Generic;
using System.Web;
using System;
namespace METALIMPEX.Controllers
{
public class ConditionController : Controller
{
private ApplicationDbContext _context;
private ConditionDBContext db = new ConditionDBContext();
IList<Condition> conditionList = new List<Condition>();
public ConditionController(ApplicationDbContext context)
{
_context = context;
//DEPRECATED CODE, MANUAL QUERY, PROJECT NOW USES DBCONTEXT
/*string strConnection = "Data Source=DELL-XPS\\SQLEXPRESS;Initial Catalog=METALIMPEX;Integrated Security=True";
string sqlQuery = "SELECT REPLICATE('0',6-LEN(RTRIM(PartID))) + RTRIM(PartID) AS 'Part ID', REPLICATE('0', 6 - LEN(RTRIM(OperatorID))) + RTRIM(OperatorID) AS 'Operator ID', Date_Time AS 'Time', IsPartWorking AS 'Part Status', IsMachineWorking AS 'Machine Status' FROM Defect";
SqlConnection sqlConnection = new SqlConnection(strConnection);
SqlCommand command = new SqlCommand(sqlQuery, sqlConnection);
SqlDataReader Dr;
try {
sqlConnection.Open();
Dr = command.ExecuteReader();
while (Dr.Read())
{
conditionList.Add(new Defect()
{
conditionID = Dr["Part ID"].ToString(),
operatorID = Dr["Operator ID"].ToString(),
dateTime = Dr["Time"].ToString(),
partStatus = (bool)Dr["Part Status"],
machineStatus = (bool)Dr["Machine Status"]
});
};
Dr.Dispose();
}
catch (SqlException) {
throw new InvalidOperationException("An error has occured while connecting to the database");
//OR
//return View("Error");
}*/
}
// GET: Condition
public IActionResult Index()
{
//return View(conditionList);
return View(db.Conditions.ToList());
}
// GET: Condition/Details/5
public IActionResult Details()
{
return View(conditionList);
}
// GET: Condition/Create
public IActionResult Create()
{
return View();
}
// POST: Condition/Create
[HttpPost]
[ValidateAntiForgeryToken]
public IActionResult Create(Condition condition)
{
if (ModelState.IsValid)
{
//_context.Condition.Add(condition);
//_context.SaveChanges();
return RedirectToAction("Index");
}
return View(condition);
}
// GET: Condition/Edit/5
public IActionResult Edit(int id)
{
if (conditionList == null)
{
return HttpNotFound();
}
Condition condition = db.Conditions.Single(m => m.conditionID == id);
return View(condition);
}
// POST: condition/Edit/5
[HttpPost]
[ValidateAntiForgeryToken]
public IActionResult Edit(Condition condition)
{
if (ModelState.IsValid)
{
db.Update(condition);
db.Entry(condition).State = EntityState.Modified;
db.SaveChanges();
return RedirectToAction("Index");
}
return View(condition);
}
// GET: condition/Delete/5
[ActionName("Delete")]
public IActionResult Delete(string id)
{
return View(conditionList);
}
// POST: condition/Delete/5
[HttpPost, ActionName("Delete")]
[ValidateAntiForgeryToken]
public IActionResult DeleteConfirmed(string id)
{
/*Movie movie = db.Movies.Find(id);
if (movie == null)
{
return HttpNotFound();
}
db.Movies.Remove(movie);
db.SaveChanges();
return RedirectToAction("Index");*/
return RedirectToAction("Index");
}
}
}
View:
#model METALIMPEX.Models.Condition
#{
ViewData["Title"] = "Edit";
}
<h2>Edit</h2>
<form asp-action="Edit">
<div class="form-horizontal">
<h4>Condition</h4>
<hr />
<div asp-validation-summary="ValidationSummary.ModelOnly" class="text-danger"></div>
<input type="hidden" asp-for="conditionID" />
<div class="form-group">
<label asp-for="componentID" class="col-md-2 control-label"></label>
<div class="col-md-10">
<input asp-for="componentID" class="form-control" />
<span asp-validation-for="componentID" class="text-danger" />
</div>
</div>
<div class="form-group">
<label asp-for="operatorID" class="col-md-2 control-label"></label>
<div class="col-md-10">
<input asp-for="operatorID" class="form-control" />
<span asp-validation-for="operatorID" class="text-danger" />
</div>
</div>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<div class="checkbox">
<input asp-for="condition" />
<label asp-for="condition"></label>
</div>
</div>
</div>
<div class="form-group">
<label asp-for="dateTime" class="col-md-2 control-label"></label>
<div class="col-md-10">
<input asp-for="dateTime" class="form-control" />
<span asp-validation-for="dateTime" class="text-danger" />
</div>
</div>
<div class="form-group">
<label asp-for="comments" class="col-md-2 control-label"></label>
<div class="col-md-10">
<input asp-for="comments" class="form-control" />
<span asp-validation-for="comments" class="text-danger" />
</div>
</div>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" value="Save" 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>
}
I'm a beginner in .NET so I have no real idea what's wrong here. The edit view was generated by the framework so I assume it should be working.
Any ideas?
The issue is with the parameter name of the Edit Action method. Below is the URL encoded form-data posted from the view on clicking Save button.
conditionID=&dateTime=2013-12-01&componentID=1&operatorID=1&condition=true&comments=
The action parameter name is condition and there is a key-value pair condition=true in the incoming form-data. The MVC model binding process will try to map the parameter/property(in case of complex model) name to the corresponding Route/Query String/Request Body data.
Hence it's trying to map the value of condition in the form-data i.e. true to the action parameter and eventually fails to convert bool to object.
Change the parameter name to any name that doesn't corresponds to any key name in the form-data and it should work.

Categories