Debugging Model Referenced by Razor View - asp.net-mvc

Total newbie in ASP.Net MVC and Razor Pages.
I have a Razor View with the model referenced declared on top:
#model TestApplication.Models.Registration
How would I be able to debug the model? I've tried setting breakpoints in the model but when debugging, the breakpoints are not being hit.
Code is as follows:
Register.cshtml
#model TestApplication.Models.Registration
#{
string labelClass = "ctrl-label col-sm-4",
controlSize = "col-sm-8";
}
<div class="row">
<div class="col-md-7 col-md-offset-2">
<h2>#TestApplication.Resources.General.Register</h2>
#using (Html.BeginForm("Register", "Account", FormMethod.Post, new{role = "form", #class = "form-horizontal" }))
{
<div class="form-group">
<h3 class="#labelClass">
<small>#TestApplication.Resources.General.CreateAccount</small></h3>
</div>
<hr />
<div class="form-group #Html.ValidationErrorFor(m => m.EmailAddress, "has-error has-feedback")">
#Html.LabelFor(p => p.EmailAddress, new { #class = labelClass })
<div class="#controlSize">
#Html.FormTextBoxFor(p => p.EmailAddress, new { #class = "form-control" })
#if (!Html.IsValid(m => m.EmailAddress))
{
<span class="glyphicon glyphicon-remove form-control-feedback"></span>
}
<span class="hint">#TestApplication.Resources.Forms.RegisterHintEmailAddress</span>
#Html.ValidationMessageFor(m => m.EmailAddress, null, new { #class = "help-block" })
</div>
</div>
<div class="form-group #Html.ValidationErrorFor(m => m.Username, "has-error has-feedback")">
#Html.LabelFor(p => p.Username, new { #class = labelClass })
<div class="#controlSize">
#Html.FormTextBoxFor(p => p.Username, new { #class = "form-control" })
#if (!Html.IsValid(m => m.Username))
{
<span class="glyphicon glyphicon-remove form-control-feedback"></span>
}
#Html.ValidationMessageFor(m => m.Username, null, new { #class = "help-block" })
</div>
</div>
<div class="form-group">
<label class="#labelClass">#TestApplication.Resources.Forms.RegisterLabelStartService</label>
<div class="#controlSize">
#* I AM GETTING AN ERROR ON THIS LINE... *#
#*#foreach(var m in Model.Services)
{
<div class="radio">
<label>
#Html.RadioButtonFor(p => p.StartServiceId, m.Id)
#m.DisplayName
</label>
</div>
}*#
</div>
</div>
}
</div>
</div>
Registration.cs
using System.Linq;
using System.Web;
using System.Web.Mvc;
using System.Web.Security;
using System.Globalization;
using System.ComponentModel.DataAnnotations;
using DataAnnotationsExtensions;
using TestApplication.Resources;
namespace TestApplication.Models
{
public class Registration
{
[Email(ErrorMessageResourceName = "InvalidEmail", ErrorMessageResourceType = typeof(ErrorMessages))]
[Required(ErrorMessageResourceName = "RequiredEmailAddress", ErrorMessageResourceType = typeof(ErrorMessages))]
[HtmlAttribute("placeholder", "PlaceholderEmailAddress", ResourceType = typeof(Forms))]
[Display(Name = "RegisterLabelEmailAddress", ResourceType = typeof(Forms))]
public string EmailAddress { get; set; }
[Email(ErrorMessageResourceName = "InvalidUsername", ErrorMessageResourceType = typeof(ErrorMessages))]
[Required(ErrorMessageResourceName = "RequiredUsername", ErrorMessageResourceType = typeof(ErrorMessages))]
[HtmlAttribute("placeholder", "PlaceholderUsername", ResourceType = typeof(Forms))]
[Display(Name = "RegisterLabelUsername", ResourceType = typeof(Forms))]
[CustomValidation(typeof(Registration), "CheckIfUserExists")]
public string Username { get; set; }
[Display(Name = "RegisterLabelStartService", ResourceType = typeof(Forms))]
public int StartServiceId { get; set; }
public ReadOnlyCollection<ServicePlugin> Services { get; private set; }
public Registration()
{
this.Services = new ReadOnlyCollection<ServicePlugin>(new List<ServicePlugin> { new ServicePlugin { Id = 1, DisplayName = "Mobile Services" }, new ServicePlugin { Id = 2, DisplayName = "Cable Services" } });
}
}
}
ServicePlugin.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
namespace TestApplication.Models
{
public class ServicePlugin
{
public int Id { get; set; }
public string DisplayName { get; set; }
}
}
AccountController.cs
[AllowAnonymous]
public ActionResult Register()
{
return this.View();
}
I commented out part of the razor view (the one with ERROR) as I am not able to properly debug the class tied to this.
Specifically, I want to debug this line in Registration.cs file:
**public Registration()**
to figure out how it is being populated and being used in the view.
Appreciate any insight on doing this.
P.S. When I remove the comment on the Register.cshtml where error is happening, I am getting the error:
Object Reference not set to an instance of the object.
I can set a breakpoint in this line:
#foreach(var m in Model.Services)
but Model is null and throws the error:
An exception of type 'System.NullReferenceException' occurred in appXXXX.dll but was not handled in user code.
So pretty much I think I need to understand how all of these tie up together.

In your Account controller you need to instantiate and then pass the Model to the view, using an overload of the View method:
[AllowAnonymous]
public ActionResult Register()
{
return View(new Models.Registration());
}

Related

ASP.Net MVC: User must select one check box validate at client side

I have UI where i am showing 3 checkboxes and each refer to different property of model class. i am using jquery unobtrusive validation just by mvc data annotation. i want when user submit form then user has to select one checkbox otherwise client side error message will display and form will not be submitted.
i can do it by jquery but i want to do it by mvc data annotation.
see my model class
public class Customer
{
[Required]
[Display(Name = "First Name")]
public string FirstName { get; set; }
[Required]
[Display(Name = "Last Name")]
public string LastName { get; set; }
[Display(Name = "Mail to me")]
public bool SelfSend { get; set; }
[Display(Name = "3rd party")]
public bool thirdParty { get; set; }
[Display(Name = "Others")]
public bool Others { get; set; }
}
Controller
[ValidateAntiForgeryToken()]
[HttpPost]
public ActionResult Index(Customer customer)
{
if (customer.Others == false || customer.SelfSend == false || customer.thirdParty == false)
ModelState.AddModelError("Error", "Must select one option");
return View();
}
with the below code i can validate any checkboxes is selected or not from server side code and add model error which show error at client side.
but i want to do validation by client side using normal data annotation.
see my razor code
<div class="row">
<div class="col-md-8">
<section id="testform">
#using (Html.BeginForm("Index", "Customers", FormMethod.Post, new { #class = "form-horizontal", role = "form" }))
{
#Html.AntiForgeryToken()
<h4>Enter customer info.</h4>
<hr />
#Html.ValidationSummary(true, "", new { #class = "text-danger" })
<div class="form-group">
#Html.LabelFor(m => m.FirstName, new { #class = "col-md-2 control-label" })
<div class="col-md-10">
#Html.TextBoxFor(m => m.FirstName, new { #class = "form-control" })
#Html.ValidationMessageFor(m => m.FirstName, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
#Html.LabelFor(m => m.LastName, new { #class = "col-md-2 control-label" })
<div class="col-md-10">
#Html.TextBoxFor(m => m.LastName, new { #class = "form-control" })
#Html.ValidationMessageFor(m => m.LastName, "", new { #class = "text-danger" })
</div>
</div>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<div class="checkbox">
#Html.CheckBoxFor(m => m.SelfSend)
#Html.LabelFor(m => m.SelfSend)
</div>
</div>
<div class="col-md-offset-2 col-md-10">
<div class="checkbox">
#Html.CheckBoxFor(m => m.thirdParty)
#Html.LabelFor(m => m.thirdParty)
</div>
</div>
<div class="col-md-offset-2 col-md-10">
<div class="checkbox">
#Html.CheckBoxFor(m => m.Others)
#Html.LabelFor(m => m.Others)
</div>
</div>
<div class="col-md-offset-2 col-md-10">
#Html.ValidationMessage("Error", "", new { #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>
}
</section>
</div>
</div>
#section Scripts {
#Scripts.Render("~/bundles/jqueryval")
}
You can try to write a customer model validation attribute.
add CheckBoxAuthAttribute in your one of three validation property.
There is a method protected virtual ValidationResult IsValid(object value, ValidationContext validationContext) in you can override inValidationAttribute.
public class CheckBoxAuthAttribute : ValidationAttribute
{
public CheckBoxAuthAttribute(params string[] propertyNames)
{
this.PropertyNames = propertyNames;
}
public string[] PropertyNames { get; private set; }
protected override ValidationResult IsValid(object value, ValidationContext validationContext)
{
var properties = this.PropertyNames.Select(validationContext.ObjectType.GetProperty);
var values = properties
.Select(p => p.GetValue(validationContext.ObjectInstance, null))
.OfType<bool>();
if (values.Contains(true) || (bool)value == true)
{
return null;
}
return new ValidationResult(this.FormatErrorMessage(validationContext.DisplayName));
}
}
public class Customer
{
[Required]
[Display(Name = "First Name")]
public string FirstName { get; set; }
[Required]
[Display(Name = "Last Name")]
public string LastName { get; set; }
[Display(Name = "Mail to me")]
[CheckBoxAuth("thirdParty", "Others", ErrorMessage = "Must select one option"))]
public bool SelfSend { get; set; }
[Display(Name = "3rd party")]
public bool thirdParty { get; set; }
[Display(Name = "Others")]
public bool Others { get; set; }
}
Since you want one of 3 possible options to be selected, then use radio buttons and bind to a property with a required attribute.
Start by defining a view model
public class CustomerVM
{
[Required]
[Display(Name = "First Name")]
public string FirstName { get; set; }
[Required]
[Display(Name = "Last Name")]
public string LastName { get; set; }
[Required]
public int? Mailing { get; set; } // see notes below
}
And in the view
#model CustomerVM
....
#using (Html.BeginForm())
{
....
<label>
#Html.RadioButtonFor(m => m.Mailing, 1, new { id = ""})
<span>Mail to me</span>
</label>
<label>
#Html.RadioButtonFor(m => m.Mailing, 2, new { id = ""})
<span>3rd party</span>
</label>
.... // ditto for "Others"
#Html.ValidationMessageFor(m => m.Mailing)
....
}
and the POST method will be
[HttpPost]
public ActionResult Index(CustomerVM model)
{
if(!ModelState.IsValid)
{
return View(model);
}
.... // map to instance of data model, save and redirect
}
Note that if these options are unlikely to change, it would be more appropriate to make the property an enum rather than an int, for example
public enum Mailing
{
[Display(Name = "Mail to me")]
SelfSend = 1,
[Display(Name = "3rd party")]
ThirdParty = 2,
[Display(Name = "Others")]
Others = 3
}
public class CustomerVM
{
....
[Required]
public Mailing? Mailing { get; set; }
}
and the view code would be
#Html.RadioButtonFor(m => m.Mailing, Mailing.SelfSend, new { id = ""})

ASP.NET MVC database table getting null value

I am creating a simple CRUD application using ASP.NET MVC with Entity Framework, Data are being saved but the values are null when I check it from Database ..
Below I shared different class and files:-
EmployeeController class:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using ASP.NETMVCCRUD.Models;
using System.Data.Entity.Validation;
namespace ASP.NETMVCCRUD.Controllers
{
public class EmployeeController : Controller
{
// GET: Employee
public ActionResult Index()
{
return View();
}
public ActionResult GetData()
{
using (DBModel db = new DBModel())
{
List<Employee> emplist = db.Employees.ToList<Employee>();
return Json(new { data = emplist }, JsonRequestBehavior.AllowGet);
}
}
[HttpGet]
public ActionResult AddOrEdit(int id=0) {
return View(new Employee());
}
[HttpPost]
public ActionResult AddOrEdit(Employee emp)
{
using (DBModel db = new DBModel())
{
db.Employees.Add(emp);
db.SaveChanges();
return Json(new {success = true, message="Saved Successfully",JsonRequestBehavior.AllowGet });
}
}
}
}
AddOrEdit.cshtml
#model ASP.NETMVCCRUD.Models.Employee
#{
Layout = null;
}
#using (Html.BeginForm("AddOrEdit", "Employee", FormMethod.Post, new {onsubmit="return SubmitForm(this)" }))
{
#Html.HiddenFor(Model => Model.EmployeeID)
<div class="form-group">
#Html.HiddenFor(Model => Model.Name, new { #class = "control-label" })
#Html.EditorFor(Model => Model.Name, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(Model => Model.Name)
</div>
<div class="form-group">
#Html.HiddenFor(Model => Model.Position, new { #class = "control-label" })
#Html.EditorFor(Model => Model.Position, new { htmlAttributes = new { #class = "form-control" } })
#Html.ValidationMessageFor(Model => Model.Position)
</div>
<div class="form-group">
#Html.HiddenFor(Model => Model.Office, new { #class = "control-label" })
#Html.EditorFor(Model => Model.Office, new { htmlAttributes = new { #class = "form-control" } })
</div>
<div class="form-group">
#Html.HiddenFor(Model => Model.Age, new { #class = "control-label" })
#Html.EditorFor(Model => Model.Age, new { htmlAttributes = new { #class = "form-control" } })
</div>
<div class="form-group">
#Html.HiddenFor(Model => Model.Salary, new { #class = "control-label" })
<div class="input-group">
<span class="input-group-addon">$</span>
#Html.EditorFor(Model => Model.Salary, new { htmlAttributes = new { #class = "form-control" } })
</div>
</div>
<div class="form-group">
<input type="submit" value="Submit" class="btn btn-primary"/>
<input type="reset" value="Reset" class="btn " />
</div>
}
Employee.cs
namespace ASP.NETMVCCRUD.Models
{
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
public partial class Employee
{
public int EmployeeID { get; set; }
public string Name { get; set; }
public string Position { get; set; }
public string Office { get; set; }
public Nullable<int> Age { get; set; }
public Nullable<int> Salary { get; set; }
}
}
Your view contains a #Html.HiddenFor() for each property before the associated EditorFor() method. The DefaultModelBinder only binds the first matching name/value pair and ignores the others, so its the values of the hidden inputs (which are default values) that are being saved.
Remove all the #Html.HiddenFor() from your view and the edited values will be correctly bound.
As a side note, its unclear why your method is named AddOrEdit when all you are doing is adding new records.
[HttpPost]
public ActionResult AddOrEdit(Employee emp)
{
using (DBModel db = new DBModel())
{
db.Employees.Add(emp);
try
{
db.SaveChanges();
}
catch(DbEntityValidationException e)
{
Console.WriteLine(e);
}
return Json(new { success = true, message = "Saved Succesfully" }, JsonRequestBehavior.AllowGet);
}
}

MVC Dropdown list null on view on submit

I'm having issues with drop down lists on MVC. I've searched and searched but to no avail.
My ViewModel
public class IncidentFormViewModel
{
public Guid Guid { get; set; }
public Incident Incident { get; set; }
public Guid PersonInvolvedId { get; set; }
public IEnumerable<Person> People { get; set; }
}
My Controller
public ActionResult New()
{
var incidentFormVM = new IncidentFormViewModel
{
Incident = new Incident(),
People = unitofwork.Person.GetAll()
};
return View("IncidentForm", incidentFormVM);
}
and View(I've taken out useless information)
#using (Html.BeginForm("Save", "Incident"))
<div class="container">
<div class="row">
<div class="col-sm-6">
<div class="form-group">
#Html.LabelFor(m => m.Incident.PersonInvolved)
#Html.DropDownListFor(m => m.PersonInvolvedId, new SelectList(Model.People, "Id", "FirstName"), new { #class = "form-control" })
#Html.ValidationMessageFor(m => m.Incident.PersonInvolved)
</div>
</div>
<br />
<button type="submit" class="btn btn-primary">Submit</button>
</div>
</div>
The thing is if i put a stop on the line below and put a watch on Model.People i can see the list of people against it.
#Html.DropDownListFor(m => m.PersonInvolvedId, new SelectList(Model.People, "Id", "FirstName"), new { #class = "form-control" })
What am i doing wrong?

ViewModel Contents are Null after Posting Form to Controller

So the ViewModel has 2 sets of data.
The CurrentDetails and UpdatedDetails. Both are instances of the same class which carries strings and whatnot inside etc.
This method has worked with all other views and models I've attempted with, but for THIS one instance, when the form is posted to the controller, its contents (CurrentDetails and UpdatedDetails) are both found to be null.
I've tried changing the parameter name from model to test and to other arbitrary things, but to no avail.
The one thing that worked (but is not a solution to me) is NOT having instances of the class inside the ViewModel, and just having the data there (but I don't see why I should be forced to do things this way.
Here's the controller:
[HttpPost]
public ActionResult FloristProfile(MerchantFloristProfileViewModel test)
{
if (!ModelState.IsValid)
return View(test);
using (var db = new ApplicationDbContext())
{
Florist florist = db.Florists.Find(MerchantBase.FloristID);
if (Request.Form["editSubmit"] != null)
{
florist.Name = test.UpdatedDetails.Name;
florist.Website = test.UpdatedDetails.Website;
db.SaveChanges();
return RedirectToAction("FloristProfile");
}
else if (Request.Form["photoSubmit"] != null)
{
if (test.CurrentDetails.File.ContentLength > 0)
{
CloudBlobContainer container = FlowerStorage.GetCloudBlobContainer();
string blobName = String.Format("florist_{0}.jpg", Guid.NewGuid().ToString());
CloudBlockBlob photoBlob = container.GetBlockBlobReference(blobName);
photoBlob.UploadFromStream(test.CurrentDetails.File.InputStream);
florist.LogoPath = blobName;
florist.isRendering = true;
db.SaveChanges();
return RedirectToAction("FloristProfile");
}
}
}
return Content("Invalid Request");
}
View:
#using (Html.BeginForm("FloristProfile", "Merchant", FormMethod.Post, new { #class = "form-horizontal" }))
{
#Html.ValidationSummary(false, "", new { #class = "text-danger" })
#Html.HiddenFor(x => x.CurrentDetails.FloristID)
#Html.HiddenFor(x => x.CurrentDetails.Name)
#Html.HiddenFor(x => x.CurrentDetails.StaffCount)
#Html.HiddenFor(x => x.CurrentDetails.StoreCount)
#Html.HiddenFor(x => x.CurrentDetails.Website)
<div class="form-group">
#Html.LabelFor(x => x.UpdatedDetails.Name, new { #class = "col-sm-2 control-label" })
<div class="col-sm-10">
#Html.TextBoxFor(x => x.UpdatedDetails.Name, new { #class = "form-control" })
</div>
</div>
<div class="form-group">
#Html.LabelFor(x => x.UpdatedDetails.Website, new { #class = "col-sm-2 control-label" })
<div class="col-sm-10">
#Html.TextBoxFor(x => x.UpdatedDetails.Website, new { #class = "form-control" })
</div>
</div>
<div class="form-group">
<div class="col-sm-offset-2 col-sm-10">
<button type="submit" name="editSubmit" class="btn btn-success">Save</button>
</div>
</div>
}
ViewModel:
public class MerchantFloristProfileViewModel
{
public class FloristProfileDetails
{
public int FloristID { get; set; }
[Required(ErrorMessage = "Please Enter a Name")]
public string Name { get; set; }
[DataType(DataType.Url)]
[Required(ErrorMessage = "Please Enter a Website")]
public string Website { get; set; }
public int StoreCount { get; set; }
public int StaffCount { get; set; }
// For Picture Upload
public HttpPostedFileBase File { get; set; }
}
public FloristProfileDetails CurrentDetails;
public FloristProfileDetails UpdatedDetails;
}
Both CurrentDetails and UpdatedDetails in your MerchantFloristProfileViewModel model are fields, not properties (no getter/setter) so the DefaultModelBinder cannnot set the values. Change them to
public FloristProfileDetails CurrentDetails { get; set; }
public FloristProfileDetails UpdatedDetails { get; set; }
But you should not be sending all that extra data to the view, then sending it all back again unchanged. Apart from the extra overhead, any malicious user could alter the values in the hidden fields causing your app to fail. Just get the original from the repository again if you need it in the POST method

MVC 4 Running fine on Visual studio but showing run time erron on iis. Model is null

My asp MVC application runs fine on visual studio. but when hosted on server its showing run time error. The error is because the Model is Null. But model => model.Service is getting values.
Error
Line 86: </div>
Line 87: <div class="editor-field">
Line 88: #if (Model.ServiceIsLimitToList)
Line 89: {
Line 90:
On Visual studio ifs working fine but showing error on running on IIS. The error is because the Model is null while running on iis.
Following is the Code
Model
public class WorkOrderCreateViewModel : ViewModel
{
[Required]
[Display(Name = "Service")]
public string Service { get; set; }
[Required]
[Display(Name = "Property")]
public string Property { get; set; }
[Display(Name = "Asset Group")]
public string AssetGroup { get; set; }
public bool ServiceIsLimitToList { get; set; }
public List<PropertiesList> Properties { get; set; }
public List<AssetGroupList> AssetGroups { get; set; }
public List<ServiceList> ServiceLists { get; set; }
}
Controller
public class WorkOrderController : MobileWebControllerBase
{
public ActionResult Create()
{
try
{
this.EnsureSessionNotExpired();
var db = new DataAccess(this.GetConnectionString());
ViewModel.WorkOrderCreateViewModel viewModel = new ViewModel.WorkOrderCreateViewModel();
viewModel.ServiceIsLimitToList = int.Parse(this.GetSystemOption("WODefaults", "ServiceLimitToList", conn)) != 0;
viewModel.Properties = this.GetProperties();
viewModel.AssetGroups = this.GetAssetGroup();
viewModel.ServiceLists = this.GetServices();
return View(viewModel);
}
catch (Exception ex)
{
return HandleException(ex);
}
}
}
View
#model WorkorderMobileMvc.ViewModel.WorkOrderCreateViewModel
#using (Html.BeginForm()) {
#Html.AntiForgeryToken()
#Html.ValidationSummary(true)
<fieldset>
<p>
<strong>New WO</strong>
#Html.ActionLink("Home", "Index")
Help
</p>
<div class="editor-label-dll">
#Html.LabelFor(model => model.ServiceLists)
</div>
<div class="editor-field">
#if (Model.ServiceIsLimitToList)
{
#Html.TextAreaFor(model => model.Service, new { #class = "txt", id = "Service" })
}
else
{
#Html.DropDownListFor(x => x.Service, new SelectList(Model.ServiceLists, "Services", "Services", Model.Service), "---Select Service---", new { Class = "field size3", id = "ddlService" })
#Html.ValidationMessageFor(model => model.Service)
}
</div>
<div class="editor-label-dll">
#Html.LabelFor(model => model.Property)
</div>
<div class="editor-field">
#Html.DropDownListFor(x => x.Property, new SelectList(Model.Properties, "Propertie", "Propertie", Model.Property), "---Select Property---", new { Class = "field size3", id = "ddlProperty" })
#Html.ValidationMessageFor(model => model.Property)
</div>
<div class="editor-label-dll">
#Html.LabelFor(model => model.AssetGroup)
</div>
<div class="editor-field">
#Html.DropDownListFor(x => x.AssetGroup, new SelectList(Model.AssetGroups, "AssetGroup", "AssetGroup", Model.AssetGroups), "---Select Asset Group---", new { Class = "field size3", id = "ddlAssetGroup" })
</div>
<div style="clear:left"></div>
<p>
<input type="submit" value="Create" />
</p>
</fieldset>
}
<div>
#Html.ActionLink("Back to List", "Index")
</div>
You need to specify in your view which model to use, something like this at the very top:
#model WorkOrderCreateViewModel

Resources