I am using Razor with MVC 5,C# and a Model(ClassTestQuestion) that is related with another Model(ClassTestQuestionMc).
I Check some checkboxes and when I press submit button (finish) in controller I am getting back null object.
How I can get back the the results?
In View:
#model IEnumerable<OnlineLearningMVC.Models.ClassTestQuestion>
#using (Html.BeginForm("FinishTest", "ClassTestQuestions", FormMethod.Post))
{
#Html.AntiForgeryToken()
foreach (var item in Model)
{
#Html.DisplayFor(model => item.QuestionTx)
#Html.HiddenFor(model => item.Id)
#Html.HiddenFor(model => item.QuestionTx)
<br/>
<br />
foreach (var Question in item.ClassTestQuestionMc)
{
#Html.DisplayFor(model => Question.AnswerTx)
#Html.HiddenFor(model => Question.AnswerTx)
#Html.CheckBoxFor(model => Question.IsChecked)
#Html.HiddenFor(model => Question.IsChecked)
}
}
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" value="FinishTest" class="btn btn-default" />
</div>
</div>
In controller:
public ActionResult ClassCourseTest(int IdCourse)
{
var classTestQuestions = db.ClassTestQuestions.Include(c=>c.ClassTestQuestionMc).Include(c => c.ClassTest).Where(i=>i.ClassTestId== IdCourse);
return View("ClassCourseTest", classTestQuestions.ToList());
}
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult FinishTest(ClassTestQuestion classTestQuestion)
{
return View(classTestQuestion);
}
My ClassTestQuestion Model:
namespace OnlineLearningMVC.Models
{
public class ClassTestQuestion
{
public int Id { set; get; }
public int ClassTestId { set; get; }
public virtual ClassTest ClassTest { set; get; }
[Required]
[DisplayName("Question")]
public string QuestionTx { set; get; }
[Required]
[DisplayName("Order")]
public int OrderInt { get; set; }
[DisplayName("Disabled")]
public bool IsDeleted { set; get; }
public string CreatedFrom { set; get; }
public DateTime CreatedDate { set; get; }
public string UpdatedFrom { set; get; }
public DateTime UpdatedDate { set; get; }
public virtual ICollection<ClassTestQuestionMc> ClassTestQuestionMc { set; get; }
}
My ClassTestQuestionMc Model:
namespace OnlineLearningMVC.Models
{
public class ClassTestQuestionMc
{
public int Id { set; get; }
public int ClassTestQuestionId { set; get; }
public virtual ClassTestQuestion ClassTestQuestion { set; get; }
[Required]
public string AnswerTx { set; get; }
[DisplayName("Is Correct Answer?")]
public bool IsCorrectAnswer { set; get; }
public bool IsChecked { set; get; }
[DisplayName("Disabled")]
public bool IsDeleted { set; get; }
public string CreatedFrom { set; get; }
public DateTime CreatedDate { set; get; }
public string UpdatedFrom { set; get; }
public DateTime UpdatedDate { set; get; }
}
What I see in Browser:
Edit
I have try to change to IEnumerable :
Change ICollection to IList for ClassTestQuestionMc. Then you need to follow array name convention here to make MVC work to handle the view model.
foreach (int i = 0; i < Model.Count; i++)
{
#Html.DisplayFor(model => Model[i].QuestionTx)
#Html.HiddenFor(model => Model[i].Id)
#Html.HiddenFor(model => Model[i].QuestionTx)
<br/>
<br/>
foreach (int j = 0; j < Model[i].ClassTestQuestionMc; j++)
{
#Html.DisplayFor(model => Model[i].ClassTestQuestionMc[j].AnswerTx)
#Html.HiddenFor(model => Model[i].ClassTestQuestionMc[j].AnswerTx)
#Html.CheckBoxFor(model => Model[i].ClassTestQuestionMc[j].IsChecked)
#Html.HiddenFor(model => Model[i].ClassTestQuestionMc[j].IsChecked)
}
}
Related
Every time I get ModelState.isvalid = false. and the employee.ID is null. On the page-html I use asp-for in a hidden so it should match against id, but still comes out null, anyone have an idea?
public Employees Employees {get; set;}
public async Task<IActionResult> OnPost()
{
//if (!ModelState.IsValid)
//{
// var errors = ModelState.SelectMany(x => x.Value.Errors.Select(z => z.Exception));
//}
if (ModelState.IsValid)
{
var dbEmpy = await _db.Employees.FindAsync(Employees.ID);
dbEmpy.FirstName = Employees.FirstName;
dbEmpy.LastName = Employees.LastName;
dbEmpy.Salary = Employees.Salary;
dbEmpy.isCEO = Employees.isCEO;
dbEmpy.isManager = Employees.isManager;
dbEmpy.ManagerId = Employees.ManagerId;
await _db.SaveChangesAsync();
return RedirectToPage("ListEmpolyee/index");
}
return RedirectToPage();
}
}
and page
<div class="border container" style="padding:20px;">
<form method="post">
<input type="hidden" asp-for="Employees.ID" />
<span class="text-danger" asp-validation-summary="ModelOnly"></span>
<div class="form-group row">
<div class="col-4">
<label asp-for="Employees.FirstName"></label>
</div>
</div>
public class Employees
{
[Key]
public int ID { get; set; }
[Required]
public string FirstName { get; set; }
[Required]
public string LastName { get; set; }
[Required]
public decimal Salary { get; set; }
public bool isCEO { get; set; }
public bool isManager { get; set; }
public int? ManagerId { get; set; }
}
I'm working on Online Quiz System.
My models:
EXAM.cs
public Exam()
{
this.Questions = new HashSet<Question>();
}
[Key]
public int Id { get; set; }
[Required]
public string Title { get; set; }
[Required]
public string Description { get; set; }
public ICollection<Question> Questions { get; set; }
[Required]
public int QuestionsCount { get; set; }
Question.cs
public Question()
{
this.Id = Guid.NewGuid().ToString();
this.Choices = new HashSet<Choice>();
}
[Key]
public string Id { get; set; }
[Required]
public string Text { get; set; }
public ICollection<Choice> Choices { get; set; }
public bool IsActive { get; set; }
[Required]
public int ExamId { get; set; }
[ForeignKey(nameof(ExamId))]
public Exam Exam { get; set; }
Choice.cs
public Choice()
{
this.Id = Guid.NewGuid().ToString();
}
[Key]
public string Id { get; set; }
[Required]
public string QuestionId { get; set; }
[ForeignKey(nameof(QuestionId))]
public Question Question { get; set; }
[Required]
public string Text { get; set; }
[Required]
public bool IsTrue { get; set; }
Answer.cs
public Answer()
{
this.Id = Guid.NewGuid().ToString();
}
[Key]
public string Id { get; set; }
[Required]
public string UserId { get; set; }
[ForeignKey(nameof(UserId))]
public ApplicationUser User { get; set; }
[Required]
public string ChoiceId { get; set; }
[ForeignKey(nameof(ChoiceId))]
public Choice Choice { get; set; }
Each question can have many answers. Every answer can be true or false. If a question has more than one answer that is true, then i use checkboxes (multiple choice), in other case i use radiobuttons (single choice).
Take.cshtml - Exam View
<form method="post" class="form-horizontal">
#foreach (var q in Model.Questions)
{
<div class="row">
<div class="col-xs-12">
<div class="box">
<div class="box-header">
<h3 class="box-title">#(counter +". "+q.Text)</h3>
</div>
<!-- /.box-header -->
<div class="box-body table-responsive no-padding">
<table class="table table-hover">
#{
var trueChoices = q.Choices.Where(c => c.IsTrue == true).Count();
var order = Model.AnswersOrder;
var currentChoices = q.Choices;
}
#if (order == OrderType.Fixed)
{
currentChoices = currentChoices.OrderBy(c => c.CreatedOn).ToList();
}
else
{
currentChoices = examService.GetMixedChoices(currentChoices);
}
#foreach (var choice in currentChoices)
{
<tr>
#if (trueChoices <= 1)
{
<td class="col-xs-2"><input name='asd' value='asd' type="radio" /></td>
}
else
{
<td class="col-xs-2"><input name="asd" value='asd' type="checkbox" /></td>
}
<td class="col-xs-8">#choice.Text</td>
</tr>
}
</table>
</div>
<!-- /.box-body -->
</div>
<!-- /.box -->
</div>
</div>
counter++;
}
<div class="box-footer">
<button id="submitExam" type="submit" class="btn btn-block btn-primary">Submit</button>
</div>
</form>
My question is how can i submit this form? I want to put the information in one table with user id and choice id and to check if the selected choice is correct or not.
Thank you!
I have a page that show details of a post and Identified users can add commented on that post.
My problems:
PostID and UserID is FK in Comment model and don't pass from view to controller
CommnetMessage is Null!!
what is wrong?
Comment Model :
public class Comment : System.Object
{
public Comment()
{
this.CommnetDate = General.tzIran();
}
[Key]
public int CommentID { get; set; }
[Required]
public string CommnetMessage { get; set; }
[Required]
public DateTime CommnetDate { get; set; }
public string UserId { get; set; }
[Key, ForeignKey("UserId")]
public virtual ApplicationUser ApplicationUser { get; set; }
public int PostID { get; set; }
[Key, ForeignKey("PostID")]
public virtual Post posts { get; set; }
}
Post Model:
public class Post : System.Object
{
public Post()
{
this.PostDate = General.tzIran();
this.PostViews = 0;
}
[Key]
public int PostID { get; set; }
public string PostName { get; set; }
public string PostSummery { get; set; }
public string PostDesc { get; set; }
public string PostPic { get; set; }
public DateTime PostDate { get; set; }
public int PostViews { get; set; }
public string postMetaKeys { get; set; }
public string PostMetaDesc { get; set; }
public string UserId { get; set; }
[ForeignKey("UserId")]
public virtual ApplicationUser ApplicationUser { get; set; }
public int CategoryID { get; set; }
[ForeignKey("CategoryID")]
public virtual Category Category { get; set; }
public virtual ICollection<Comment> commnets {get; set;}
}
public class ApplicationUser : IdentityUser
{
public string FirstName { get; set; }
public string LastName { get; set; }
/*Realations*/
public virtual ICollection<Comment> Comments { get; set; }
public virtual ICollection<Post> Posts { get; set; }
}
View Model:
public class PostViewModel
{
public ApplicationUser Users { get; set; }
public Post posts { get; set; }
public Category Categories { get; set; }
public IEnumerable<Comment> ListCommnets { get; set; }
public Comment Commnets { get; set; }
}
Controller:
public ActionResult Details(int? id)
{
if (id == null)
{
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
}
var post = db.Posts.Find(id);
post.PostViews += 1;
db.SaveChanges();
if (post == null)
{
return HttpNotFound();
}
return View(new PostViewModel() { posts = post });
}
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Details([Bind(Include = "CommentID,CommnetMessage,CommnetDate,UserId,PostID")] Comment comment , int? id)
{
int pid = comment.PostID;
if (ModelState.IsValid)
{
db.CommentS.Add(comment);
db.SaveChanges();
TempData["notice"] = "پیغام شما با موفقیت ثبت شد.";
return RedirectToAction("success");
}
ViewBag.UserId = new SelectList(db.Users, "Id", "FirstName", comment.UserId);
ViewBag.PostID = id;
return View( new PostViewModel() { posts = db.Posts.Find(id)});
}
public ActionResult success()
{
ViewBag.Message = "از طریق فرم زیر می توانید برایمان پیغام بگذارید.";
return View("Details", new PostViewModel() { ListCommnets = db.CommentS });
}
Comment Partial View:
#using Microsoft.AspNet.Identity
#using FinalKaminet.Models
#using Microsoft.AspNet.Identity.EntityFramework
#model FinalKaminet.ViewModel.PostViewModel
#if (TempData["notice"] != null)
{
<p>#TempData["notice"]</p>
}
#if (Request.IsAuthenticated)
{
var manager = new UserManager<ApplicationUser>(new UserStore<ApplicationUser>(new ApplicationDbContext()));
var user = manager.FindById(User.Identity.GetUserId());
using (Html.BeginForm())
{
#Html.AntiForgeryToken()
<div class="form-horizontal">
#Html.ValidationSummary(true, "", new { #class = "text-danger" })
#Html.HiddenFor(model => model.posts.PostID)
#Html.HiddenFor(model => model.Users.Id)
<div class="form-group">
#Html.LabelFor(model => model.Users.FirstName, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#{
var name = user.FirstName + " " + user.LastName;
}
<input type="text" id="Id" value="#name" disabled="disabled" class="form-control" />
</div>
</div>
<div class="form-group">
#Html.LabelFor(model => model.Commnets.CommnetMessage, htmlAttributes: new { #class = "control-label col-md-2" })
<div class="col-md-10">
#Html.EditorFor(model => model.Commnets.CommnetMessage, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(model => model.Commnets.CommnetMessage, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" value="Send" class="btn btn-default" />
</div>
</div>
</div>
}
}
else
{
<p>#Html.ActionLink("Log in", "Login", "Account", new { returnUrl = Request.Url }, null)</p>
}
As #StephenMuecke stated, model of your view is PostViewModel and all editors, hidden fields are created based on your view model. For example, when you generate hidden field using #Html.HiddenFor(model => model.posts.PostID) and try to post your data MVC model binder tries to bind the value of this field to the model specified at your Action method. In your case it is Comment so , MVC model binder will try bind value of generated hidden field to Comment.posts.PostID which does not exist. To make everything work perfectly you have to use same view model as a argument of your action method:
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Details(PostViewModel viewModel)
{
......
}
Also, again as #StephenMuecke sated, your view model should have only those properties which you need. For example, your PostViewModel should look like something as following:
public class PostViewModel
{
// Actually, you do not need UserId property
// as it should be retrieved inside controller
// from current user data
public string UserId { get; set; }
public string UserName { get; set; }
public int PostID { get; set; }
public string CommentMessage { get; set; }
}
Back to your action method, you have to map view model to your model:
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Details(PostViewModel viewModel)
{
Comment comment = new Comment
{
CommnetMessage = viewModel.CommentMessage,
// and other properties
}
// Save your model and etc.
}
i'm new to mvc and trying to get idea of what i'm doing wrong i create a Dbcontaxt class
public class DataBaseContext : DbContext
{
public DataBaseContext()
: base("DefaultConnection")
{
}
public DbSet<Membership> Membership { get; set; }
public DbSet<OAuthMembership> OAuthMembership { get; set; }
public DbSet<Role> Roles { get; set; }
public DbSet<UserProfile> UserProfiles { get; set; }
public DbSet<Category> Categorys { get; set; }
public DbSet<SubCategory> SubCategorys { get; set; }
public DbSet<Product> Products { get; set; }
public DbSet<Color> Colors { get; set; }
public DbSet<Size> Sizes { get; set; }
public DbSet<Company> Companys { get; set; }
public DbSet<UsersInRoles> UsersInRoles { get; set; }
}
}
and i create a model class to create a strongly type view
[Bind(Exclude = "AddUserToRoleID")]
public class AddUserToRole
{
[ScaffoldColumn(false)]
public int AddUserToRoleID { get; set; }
[Required]
[Display(Name = "User name")]
public string UserName { get; set; }
[Required]
[Display(Name = "Role name")]
public string RoleName { get; set; }
}
}
in the controller i'm trying to create the Details view by adding view and select AddUserToRole as my model for the strongly type view
public ActionResult Details(int id = 0)
{
var UserInRole = db.UserProfiles
.Join(db.UsersInRoles,
u => u.UserId,
uir => uir.UserId,
(u, uir) => new {u = u,uir = uir})
.Join(db.Roles,
temp0 => temp0.uir.RoleId,
r => r.RoleId,
(temp0, r) => new { temp0 = temp0,r = r })
.Where(temp1 => (temp1.temp0.u.UserId == id))
.Select(temp1 => new AddUserToRole {
AddUserToRoleID = temp1.temp0.u.UserId,
UserName = temp1.temp0.u.UserName,
RoleName = temp1.r.RoleName
});
return View(UserInRole);
}
it give me this error
The model item passed into the dictionary is of type
'System.Data.Entity.Infrastructure.DbQuery`1[SeniorProject.Models.AddUserToRole]', but
this dictionary requires a model item of type 'SeniorProject.Models.AddUserToRole'.
and when i cast return View((UsersInRoles)UserInRole); it give me this error
Unable to cast object of type
'System.Data.Entity.Infrastructure.DbQuery`1[SeniorProject.Models.AddUserToRole]'
to type'SeniorProject.Models.UsersInRoles'.
and the view
#model SeniorProject.Models.AddUserToRole
#{
ViewBag.Title = "Details";
}
<h2>Details</h2>
<fieldset>
<legend>AddUserToRole</legend>
<div class="display-label">
#Html.DisplayNameFor(model => model.UserName)
</div>
<div class="display-field">
#Html.DisplayFor(model => model.UserName)
</div>
<div class="display-label">
#Html.DisplayNameFor(model => model.RoleName)
</div>
<div class="display-field">
#Html.DisplayFor(model => model.RoleName)
</div>
</fieldset>
<p>
#Html.ActionLink("Edit", "Edit", new { id=Model.AddUserToRoleID }) |
#Html.ActionLink("Back to List", "Index")
</p>
what should i do in this case?
You need to materialize it. Put FirstOrDefault() at the end of the query
var materializedUser = UserInRole.SingleOrDefault();
return View(materializedUser);
Edit: Following pjotr comment replacing FirstOrDefault() with SingleOrDefault()
I currently have an entity that I'm trying to edit through my MVC 3 web app. I receive an DbUpdateConcurrencyExceptionwhen trying to perform a the client wins approach I got from MSDN's post Using DbContext in EF 4.1 Part 9: Optimistic Concurrency Patterns. The weird part is that this only happens on this particular entity and there I'm not doing anything different from the other. Also, it only happens when updating from a null to a value. The Properties giving the error when updating from null value to a DateTime value are DispositionLetterDate and DateDisposition.
Class:
public class A22
{
public A22()
{
this.IsArchived = false;
this.A22StatusId = (int)AStatus.Open;
}
[Key]
public int Id { get; set; }
[Required]
[StringLength(100, ErrorMessage="A22 Number cannot exceed 100 characters")]
public string Number { get; set; }
[Display(Name="Manual")]
public int ManualId { get; set; }
[Display(Name="SGMLID")]
public string SGMLId { get; set; }
[Required]
[DataType(DataType.Date)]
[Display(Name="Date Received")]
public DateTime DateReceived { get; set; }
[Display(Name= "Status")]
[EnumDataType(typeof(A22Status))]
public int A22StatusId { get; set; }
[Display(Name="Priority")]
[EnumDataType(typeof(A22Priority))]
public int A22PriorityId { get; set; }
[Display(Name="Providing Disposition")]
public string ProvidingDisposition { get; set; }
[Display(Name="Final Disposition")]
public bool FinalDisposition { get; set; }
[Display(Name="Is Archived")]
public bool IsArchived { get; set; }
[Display(Name="Created By")]
public int CreatedById { get; set; }
[Display(Name="Date Created")]
public DateTime DateCreated { get; set; }
[ConcurrencyCheck]
[Display(Name="Date Modified")]
public DateTime DateModified { get; set; }
[Display(Name = "Disposition Date")]
public DateTime? DateDisposition { get; set; }
[Display(Name = "Date Disposition Letter Sent")]
public DateTime? DispositionLetterDate{ get; set; }
// Virtual Properties
[ForeignKey("CreatedById")]
public virtual User CreatedBy { get; set; }
[ForeignKey("ManualId")]
public virtual Manual Manual { get; set; }
public virtual ICollection<A22Manual> A22ManualsImpacted { get; set; }
public virtual ICollection<A22Task> A22TasksImpacted { get; set; }
public virtual ICollection<A22Comment> Comments { get; set; }
public virtual ICollection<A22HistoryLog> HistoryLogs { get; set; }
}
Controller:
[HttpPost]
public ActionResult Edit(A22 a22)
{
var d = new A22Repository().Find(a22.Id);
var changes = TrackChanges(d, a22);
if (ModelState.IsValid) {
if (!string.IsNullOrEmpty(changes))
{
repository.InsertOrUpdate(a22);
this.repository.AddHistory(a22, changes);
repository.Save();
}
return RedirectToAction("Details", new { id = a22.Id });
} else {
ViewBag.PossibleManuals = d.ManualId == default(int) ? manualRepo.GetManualList() :
manualRepo.GetManualList(d.ManualId);
ViewBag.APriority = repository.GetAPriorityList(d.APriorityId);
ViewBag.AStatus = repository.GetAStatusList(d.APriorityId);
return View();
}
}
}
View:
#model TPMVC.Web.Models.A22
#{
Layout = "~/Views/Shared/_BlendLayoutLeftOnly.cshtml";
ViewBag.Title = "Edit";
}
<h2>Edit A22# #Model.Number</h2>
#using (Html.BeginForm())
{
#Html.ValidationSummary(true)
#Html.HiddenFor(model => model.Id)
#Html.HiddenFor(model => model.CreatedById)
#Html.HiddenFor(model => model.DateCreated)
#Html.HiddenFor(model => model.DateModified)
#Html.Partial("_CreateOrEdit")
<div class="newItemLabel">
<strong style="padding-right: 145px;">#Html.LabelFor(model => model.AStatusId)</strong>
#{
Html.Telerik().DropDownList()
.Name("AStatusId")
.BindTo((IEnumerable<SelectListItem>)ViewBag.AStatus)
.HtmlAttributes(new { #style = "width: 200px;" })
.Render();
}
#Html.ValidationMessageFor(model => model.AStatusId)
</div>
<div class="newItemLabel">
<strong style="padding-right: 77px;">#Html.LabelFor(model => model.FinalDisposition)</strong>
#Html.EditorFor(model => model.FinalDisposition)
</div>
<div class="newItemLabel">
<strong style="padding-right: 44px;">#Html.LabelFor(model => model.DateDisposition)</strong>
#{
Html.Telerik().DatePickerFor(model => model.DateDisposition)
.Render();
}
</div>
<div class="newItemLabel">
<strong style="padding-right: 44px;">#Html.LabelFor(model => model.DispositionLetterDate)</strong>
#{
Html.Telerik().DatePickerFor(model => model.DispositionLetterDate)
.Render();
}
</div>
<div class="newItemLabel">
<strong style="padding-right: 110px;">#Html.LabelFor(model => model.IsArchived) </strong>
#Html.EditorFor(model => model.IsArchived)
</div>
<p>
<input type="submit" value="Save" />
</p>
}
<div>
#Html.ActionLink("Back to List", "Index")
</div>
Thinking it was could have been something with the data annotations, I decided to define the properties with this issue to optional using the Fluid API.
modelBuilder.Entity<A22>().Property(a => a.DateDisposition).IsOptional();
modelBuilder.Entity<A22>().Property(a => a.DispositionLetterDate).IsOptional();
I basically need a fresh pair of eyes to see if I'm missing something. Is there other property that is making it behave this way?
Thanks in advance.
I'm mapping nullable DateTime properties like following without IsOptional methods. Also it works fine with MS SQL and MySQL by me.
this.Property(t => t.CreatedDate).HasColumnName("CreatedDate");
this.Property(t => t.ModifiedDate).HasColumnName("ModifiedDate");
in class derived from EntityTypeConfiguration. I'm using Code First approach.