MVC DropDownList item issue - c#

I am quiet new with MVC. I am creating the user management module for authenticating and authorizing users withing that application. Hence, I created 2 models one for user roles and the other for user details.
I created two models like this:
public class RolesModels
{
public RolesModels()
{
this.Users = new HashSet<UserModels>();
}
[Key]
[DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)]
public int RoleId { get; set; }
[Required]
[DataType(DataType.Text)]
[StringLength(20, ErrorMessage = "The {0} must be at least 6 characters long.", MinimumLength = 6)]
[Display(Name = "Caption")]
public string Caption { get; set; }
[Display(Name = "Can Create")]
public bool createRole { get; set; }
[Display(Name = "Can View")]
public bool viewRole { get; set; }
[Display(Name = "Can Modify")]
public bool modifyRole { get; set; }
[Display(Name = "Can Delete")]
public bool deleteRole { get; set; }
public virtual ICollection<UserModels> Users { get; set; }
}
public class UserModels
{
[Key]
[DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)]
public int user_id { get; set; }
[Required]
[DataType(DataType.Text)]
[Display(Name = "User Name")]
[StringLength(20, ErrorMessage = "The {0} must be at least 3 characters long.", MinimumLength = 3)]
public string user_name { get; set; }
[Required]
[DataType(DataType.Password)]
[Display(Name = "Password")]
[StringLength(10, ErrorMessage = "The {0} must be at least 4 characters long.", MinimumLength = 4)]
public string user_pass { get; set; }
[DataType(DataType.EmailAddress)]
[Display(Name = "Email")]
[StringLength(50, ErrorMessage = "The {0} must be at least 6 characters long.", MinimumLength = 6)]
public string UserEmail { get; set; }
[Display(Name = "Registeration Date")]
[DataType(DataType.Date)]
[DisplayFormat(DataFormatString = "{0:dd-MM-yyyy}", ApplyFormatInEditMode = true)]
public DateTime RegDate { get; set; }
[Display(Name = "Enable")]
public bool status { get; set; }
[Required]
public int RoleId { get; set; }
[Display(Name = "Roles")]
public virtual RolesModels Roles { get; set; }
}
and I have the registration controller action like this:
[HttpGet]
public ActionResult registration()
{
// var md = from m in db.RolesModels
// orderby m.Caption descending
// select m;
// Html.DropDownList("Roles", new SelectList(ViewBag.Roles), new { #id = "dropdown" });
ViewBag.Roles = db.RolesModels.Select(r => r.Caption);
ViewBag.RolesId = db.RolesModels.Select(r => r.RoleId);
return View();
}
I created a view for the registration with a dropdownlist like this:
#Html.DropDownList("RoleId", new SelectList(ViewBag.Roles), new { #id = "dropdown" })
My HTTPPost is here
[HttpPost]
public ActionResult registration(Solnet_HotelSuite.Models.UserModels user)
{
if (ModelState.IsValid)
{
using (var db = new DBEntity())
{
var sysUser = db.UserModels.Create();
sysUser.user_name = user.user_name;
sysUser.user_pass = user.user_pass;
sysUser.UserEmail = user.UserEmail;
sysUser.RegDate = user.RegDate;
sysUser.RoleId = user.RoleId;
//sysUser.Roles = user.Roles;
sysUser.status = user.status;
db.UserModels.Add(sysUser);
db.SaveChanges();
}
}
return View(user);
}
But whenever I clicked on Register user, I get the error :
Value cannot be null. Parameter name: items
What am I doing wrong?

The items you put in the viewbag are missing after the postback. Try changing the end of your HttpPost code to:
ViewBag.Roles = db.RolesModels.Select(r => r.Caption);
ViewBag.RolesId = db.RolesModels.Select(r => r.RoleId);
return View(user);
You may need to adjust this code as the db object may be out of scope at this point.

Related

Editing and saving from a ViewModel.

This seems to be a common question. I have looked at many examples however I must be missing something somewhere. Below is my code for the 'ViewModel', and 'Controller'.
ViewModel:
public class EditAddressViewModel
{
public Guid AddressUI { get; set; }
[Display(Name = "Billing Address?")]
[UIHint("_IsStatus")]
public bool IsBilling { get; set; }
[Display(Name = "Shipping Address?")]
[UIHint("_IsStatus")]
public bool IsShipping { get; set; }
[Display(Name = "Location Name")]
public string LocationName { get; set; }
[Display(Name = "Contact Name")]
public string ContactName { get; set; }
[Display(Name = "Address")]
public string Line1 { get; set; }
[Display(Name = "Address 2")]
public string Line2 { get; set; }
[Display(Name = "Country")]
public int Country { get; set; }
[Display(Name = "State")]
public int State { get; set; }
[Display(Name = "City")]
public int City { get; set; }
[Display(Name = "ZipCode")]
public string ZipCode { get; set; }
[Display(Name = "Contact Email")]
[DataType(DataType.EmailAddress)]
[StringLength(320)]
[RegularExpression(#"[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*#(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?", ErrorMessage = "Enter a valid email address")]
public string EmailAddress { get; set; }
[Display(Name = "Phone Number")]
[DataType(DataType.PhoneNumber)]
[StringLength(12)]
[RegularExpression(#"((\(\d{3}\) ?)|(\d{3}-))?\d{3}-\d{4}", ErrorMessage = "Enter a valid phone number")]
public string PhoneNumber { get; set; }
[Display(Name = "Fax Number")]
[DataType(DataType.PhoneNumber)]
[StringLength(12)]
[RegularExpression(#"((\(\d{3}\) ?)|(\d{3}-))?\d{3}-\d{4}", ErrorMessage = "Enter a valid phone number")]
public string FaxNumber { get; set; }
public int CompanyId { get; set; }
[Display(Name = "Select Country")]
public int CountryId { get; set; }
public IEnumerable<SelectListItem> Countries { get; set; }
[Display(Name = "Select State")]
public int StateId { get; set; }
public IEnumerable<SelectListItem> States { get; set; }
[Display(Name = "Select Cit;y")]
public int CityId { get; set; }
public IEnumerable<SelectListItem> Cities { get; set; }
}
The Controller:
// Customer Input
// GET: Addresses/Edit/5
[Authorize(Roles = "CompanyAdmin")]
public ActionResult UserEdit(Guid guid)
{
if (guid == null)
{
return new HttpStatusCodeResult(HttpStatusCode.BadRequest);
}
Addresses addresses = db.Addresses.Find(guid);
if (addresses == null)
{
return HttpNotFound();
}
EditAddressViewModel editAddress = new EditAddressViewModel()
{
AddressUI = addresses.AddressUI,
LocationName = addresses.LocationName,
Line1 = addresses.Line1,
Line2 = addresses.Line2,
Country = addresses.Country,
State = addresses.State,
City = addresses.City,
ZipCode = addresses.ZipCode,
PhoneNumber = addresses.PhoneNumber,
FaxNumber = addresses.FaxNumber,
CompanyId = addresses.CompanyId
};
ConfigureViewModel(editAddress);
return View(editAddress);
}
public void ConfigureViewModel(EditAddressViewModel editAddressViewModel)
{
editAddressViewModel.Countries = db.Countries.Select(o => new SelectListItem()
{
Value = o.CountryId.ToString(),
Text = o.CountryName
});
editAddressViewModel.States = db.States.Select(o => new SelectListItem()
{
Value = o.StateId.ToString(),
Text = o.StateName
});
editAddressViewModel.Cities = db.Cities.Select(o => new SelectListItem()
{
Value = o.CityId.ToString(),
Text = o.CityName
});
}
// POST: Addresses/Edit/5
// To protect from overposting attacks, please enable the specific properties you want to bind to, for
// more details see https://go.microsoft.com/fwlink/?LinkId=317598.
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult UserEdit(EditAddressViewModel model)
{
var userId = User.Identity.GetUserId();
if (!ModelState.IsValid)
{
return View(model);
}
Addresses addresses = db.Addresses.Find(model.AddressUI);
addresses.IsBilling = EditAddressViewModel.IsBilling;
addresses.IsShipping = EditAddressViewModel.IsShipping;
addresses.LocationName = EditAddressViewModel.LocationName;
addresses.Line1 = EditAddressViewModel.Line1;
addresses.Line2 = EditAddressViewModel.Line2;
addresses.Country = EditAddressViewModel.Country;
addresses.State = EditAddressViewModel.State;
addresses.City = EditAddressViewModel.City;
addresses.ZipCode = EditAddressViewModel.ZipCode;
addresses.PhoneNumber = EditAddressViewModel.PhoneNumber;
addresses.FaxNumber = EditAddressViewModel.FaxNumber;
addresses.CompanyId = EditAddressViewModel.CompanyId;
db.Entry(addresses).State = EntityState.Modified;
db.SaveChanges();
return RedirectToAction("Index", "Customer", new { UserId = userId });
}
The issue I am running into is in the controller. All of the entries for Example
addresses.IsBilling = EditAddressViewModel.IsBilling;
Show that "An object reference is required for the non-static field, method, or property". If I go to my 'ViewModel' and change the "public int or string" to be "public static int" then it goes away but then I get an error on the get Action that is cannot be tied to a static object. I am a little confused because this same scenario seems to work for another question on this site. In mine it does not. I have to be missing something somewhere. thanks for your help.
When you say addresses.IsBilling = EditAddressViewModel.IsBilling; you are asking for a property of the class EditAddressViewModel
You want to access a property of the object model. So I think you want addresses.IsBilling = model.IsBilling; etc.

How to loop through viewBag with strongly typed data model

I have ViewBag with strongly typed model data, I need to loop through model data in razor, how can i do that.
Razor (need help here)
#foreach (var item in ViewBag.PropertyRentingPrise)
{
//#Html.DisplayFor(item.PropertyRentingPrise)
???????????????????????????????????????
}
Controller
ViewBag.PropertyRentingPrise = _propertyManagementServices.GetAllPropertyRentingPrice();
Function returning List of records
public List<PropertyRentingPrice> GetAllPropertyRentingPrice()
{
try
{
using (var _uow = new PropertiesManagement_UnitOfWork())
{
var _records = (from _propertyTypeList in _uow.PropertyRentingPrice_Repository.GetAll()
select _propertyTypeList).ToList();
return _records;
}
}
catch { return null; }
}
model class
public class PropertyRentingPrice
{
public PropertyRentingPrice() { }
[Key]
[Column(Order = 0)]
[Display(Name = "Property Renting ID")]
public int RentingID { get; set; }
[Key][Column(Order=1)]
[Display(Name = "Housing Organization ID")]
[Required(ErrorMessage = "Require Housing Organization ID")]
public int HousingOrganizationID { get; set; }
[Key]
[Column(Order = 2)]
[Display(Name = "Property Type ID")]
[Required(ErrorMessage = "Require Property Type ID")]
public int PropertyTypeID { get; set; }
[Display(Name = "Cost Per Week")]
[Required(ErrorMessage = "Require Cost Per Week Based on Property Type")]
public decimal CostPerWeek { get; set; }
[Display(Name = "Cost Per Month")]
[Required(ErrorMessage = "Require Cost Per Month Based on Property Type")]
public decimal CostPerMonth { get; set; }
[Display(Name = "Currency")]
[Required(ErrorMessage = "Require Currency In Which Property Been Advertised, Type £ for British Pound")]
public string Currency { get; set; }
[Display(Name = "Maximum Occupancy")]
[Required(ErrorMessage = "Require Maximum Number Occupancy Based on Property Type")]
public int MaximumOccupancy { get; set; }
[Display(Name = "Bill Includes")]
[Required(ErrorMessage = "Require Yes/No if Property Rent Includes Bills")]
public bool Bill_Includes { get; set; }
public HousingOrganization HousingOrganization { get; set; }
public PropertyType PropertyType { get; set; }
}
You need to parse ViewBag object to a List of PropertyRentingPrice.
Try this:
#{
var m = ViewBag.PropertyRentingPrice as List<PropertyRentingPrice>;
}
#foreach(var item in m)
{
}

Data Annotation Validation for a Group of Fields in Model

I am new to MVC 3 Data Annotations and I just want to ask that if its possible to add Validation on a Group of Fields in Model and Display the validation if none of it has Value?
this is the set of fields in my Data model
public class ContactModel
{
public Nullable<int> Id { get; set; }
[Display(Name = "Contact Firstname")]
[Required(ErrorMessage = "Required!")]
public string ContactFirstname { get; set; }
[Display(Name = "Contact Lastname")]
[Required(ErrorMessage = "Required!")]
public string ContactLastname { get; set; }
[Display(Name = "Contact Middlename")]
public string ContactMiddlename { get; set; }
[Display(Name = "Phone")]
[Required(ErrorMessage = "Required!")]
public string ContactPhone { get; set; }
[Display(Name = "Mobile ")]
[Required(ErrorMessage = "Required!")]
public string ContactMobile { get; set; }
[Display(Name = "Email")]
[Required(ErrorMessage = "Required!")]
public string ContactEmail { get; set; }
[Display(Name = "Job Title")]
[StringLength(50, ErrorMessage = "Max character reached!")]
public string ContactJobTitle { get; set; }
}
And I want to add validation if one from Phone,Mobile or Email doesn't have value
Thanks
You can implement IValidatableObject interface and add validation for all necessary properties:
public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
{
if(string.IsNullOrEmpty(Phone) || string.IsNullOrEmpty(Mobile) || string.IsNullOrEmpty(Email))
{
yield return new ValidationResult("Some error message");
}
}
Of course you should remove [Required] attributes then from those properties.

MVC DataReader connection related issue

I have two models with a navigation property in one to the other. Model looks like this:
I am calling the two models in the same view. SuiteCategoryModels as the default and SuitesModels as a partial view.
public class SuiteCategoryModels
{
[Key]
[DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)]
public int SuiteCatID { get; set; }
[Required]
[DataType(DataType.Text)]
[Display(Name = "Category")]
[StringLength(50, ErrorMessage = "The {0} must be at least 6 characters long.", MinimumLength = 6)]
public string CatName { get; set; }
[Required]
[DataType(DataType.Text)]
[Display(Name = "Category Description")]
[StringLength(500, ErrorMessage = "The {0} must be at least 6 characters long.", MinimumLength = 6)]
public string CatDesc { get; set; }
public virtual ICollection<SuitesModels> SuitesModels { get; set; }
}
and the second model like this:
public class SuitesModels
{
[Key]
[DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)]
public int SuiteID { get; set; }
[Required]
[DataType(DataType.Text)]
[Display(Name = "Suite Name")]
[StringLength(50, ErrorMessage = "The {0} must be at least 6 characters long.", MinimumLength = 6)]
public string SuiteName { get; set; }
[Required]
[DataType(DataType.Text)]
[Display(Name = "Description")]
[StringLength(50, ErrorMessage = "The {0} must be at least 6 characters long.", MinimumLength = 6)]
public string SuiteDesc { get; set; }
[DataType(DataType.ImageUrl)]
[Display(Name = "Picture")]
public string SuitePix { get; set; }
[Required]
[Display(Name = "Rate")]
public int SuiteRate { get; set; }
[Required]
[Display(Name = "Persons Per Suite")]
public int PersonPerSuite { get; set; }
[Required]
[Display(Name = "Status")]
public bool SuiteStatus { get; set; }
public int SuiteCatID { get; set; }
public virtual SuiteCategoryModels SuiteCategory { get; set; }
}
I created a controller action to view like this:
public ActionResult Index()
{
var m = db.SuiteCategoryModels.ToList();
//ViewBag.BB =
//Dispose(false);
return View(m);
}
and the other like this:
public ActionResult SuitesIndex(int id = 0)
{
var mm = db.Suites.Select(r => r.SuiteCategory)
.Where(r => r.SuiteCatID == id);
//SuitesModels suitesmodels = db.Suites.Find(id);
if (mm == null)
{
return HttpNotFound();
}
return PartialView("SuitesIndex", mm.ToList());
}
But I have an error page stating: There is already an open DataReader associated with this Command which must be closed first..
What are the reasons of this error?
What do I do to correct this?
You need to add MultipleActiveResultSets=true; to your connection string.

Database Calculations - MVC 3 and CodeFirst

I'm trying to write a method that generates multiple commission slips. This is for a college, where clients are enrolled with tutors in a class called Enrollments. With this method, I am trying to accumulate the monthly fee of the tutors' clients multiplied by their commission percentages, as tutors earn a certain commission on the lessons they give. Here is my code for this:
public ActionResult CreateBulkCommissions()
{
var month = DateTime.Now.ToString("MMMM");
var enrolments = db.Enrollments.ToList();
var newCommissions = from enrolment in enrolments
select new TutorCommission()
{
CommissionAmount = enrolment.MonthlyFee,
CommissionMonth = month, // string constant
CommissionStatus = "Unpaid",
Tutor = enrolment.Tutor
};
foreach (var newCommission in newCommissions)
{
List<TutorCommission> TutorComs = newCommissions.GroupBy(g => g.Tutor).Select(s => new TutorCommission
{
CommissionAmount = s.Sum(u => u.CommissionAmount) * s.Key.TutorCommissionPercentage,
TutorNoID = s.Key.TutorNoID
}).ToList();
db.TutorCommission.Add(newCommission);
db.SaveChanges();
}
return RedirectToAction("Index");
}
The problem is that TutorCommission entries are created for each individual enrollment, instead of one entry per tutor (for the month) with the total commission amount. I.e. Ashley has 3 clients and therefore 3 enrollments and currently 3 TutorCommission entries are being created for him. I want to add up the enrollments amounts for one entry. In addition, the amount is not being multiplied by the commission percentage, so it is just saving as the full enrollment monthly fee. Relevant classes are:
public class Enrollment
{
[Key]
[Display(Name = "Enrollment ID Number")]
public long EnrollmentIDNumber { get; set; }
[Display(Name = "Client ID Number")]
public long ClientNumberID { get; set; }
[Display(Name = "Tutor ID Number")]
public long TutorNoID { get; set; }
[Display(Name = "Course Name")]
public string CourseName { get; set; }
[Display(Name = "Lesson Time")]
public string LessonTime { get; set; }
[Display(Name = "Lesson Day")]
public string LessonDay { get; set; }
[Display(Name = "Lesson Location")]
public string LessonLocation { get; set; }
[Display(Name = "Lesson Type")]
public string LessonType { get; set; }
[Display(Name = "Lesson Level")]
public string LessonLevel { get; set; }
[Display(Name = "Monthly Fee")]
public long MonthlyFee { get; set; }
public virtual Client Client { get; set; }
public virtual Tutor Tutor { get; set; }
}
public class TutorCommission
{
[Key]
[Display(Name = "Commission ID")]
public long CommissionID { get; set; }
[Display(Name = "Commission Month")]
public string CommissionMonth {get; set;}
[Display(Name = "Commission Amount")]
public double CommissionAmount { get; set; }
[Display(Name = "Commission Status")]
public string CommissionStatus { get; set; }
[Display(Name = "Tutor ID Number")]
public long TutorNoID { get; set; }
public virtual Tutor Tutor { get; set; }
public virtual ICollection<CommissionPayments> CommissionPayments { get; set; }
}
public class Tutor
{
[Key]
[Display(Name = "Tutor ID Number")]
public long TutorNoID { get; set; }
[Required]
[StringLength(50, ErrorMessage="First name must be less than 50 characters")]
[Display(Name = "First Name")]
public string TutorFirstName { get; set; }
[StringLength(50, ErrorMessage = "Last name must be less than 50 characters")]
[Display(Name = "Last Name")]
public string TutorLastName { get; set; }
[DisplayFormat(DataFormatString = "{0:d}", ApplyFormatInEditMode = true)]
[Display(Name = "Birth Date")]
public DateTime? TutorBirthDate { get; set; }
[Display(Name = "Cellphone Number")]
public string TutorCellphoneNumber { get; set; }
[Display(Name = "Home Number")]
public string TutorHomeNumber { get; set; }
[RegularExpression("^[a-z0-9_\\+-]+(\\.[a-z0-9_\\+-]+)*#[a-z0-9-]+(\\.[a-z0-9-]+)*\\.([a-z]{2,4})$", ErrorMessage = "Not a valid email address")]
[Display(Name = "Email Address")]
public string TutorEmailAddress { get; set; }
[Display(Name = "Street Address")]
public string TutorStreetAddress { get; set; }
[Display(Name = "Suburb")]
public string TutorSuburb { get; set; }
[Display(Name = "City")]
public string TutorCity { get; set; }
[Display(Name = "Postal Code")]
public string TutorPostalCode { get; set; }
[Display(Name="Full Name")]
public string FullName
{
get
{
return TutorFirstName + " " + TutorLastName;
}
}
[Display(Name="Commission Percentage")]
[Required]
public double TutorCommissionPercentage { get; set; }
public virtual ICollection<Enrollment> Enrollments { get; set; }
public virtual ICollection<TutorCommission> TutorCommissions { get; set; }
}
Thanks,
Amy
You can try moving the grouping logic outside the foreach loop, then iterating on the grouped list. So instead of
foreach (var newCommission in newCommissions)
{
List<TutorCommission> TutorComs = newCommissions.GroupBy(g => g.Tutor).Select(s => new TutorCommission
{
CommissionAmount = s.Sum(u => u.CommissionAmount) * s.Key.TutorCommissionPercentage,
TutorNoID = s.Key.TutorNoID
}).ToList();
db.TutorCommission.Add(newCommission);
db.SaveChanges();
}
try
List<TutorCommission> TutorComs = newCommissions.GroupBy(g => g.Tutor).Select(s => new TutorCommission
{
CommissionAmount = s.Sum(u => u.CommissionAmount) * s.Key.TutorCommissionPercentage,
TutorNoID = s.Key.TutorNoID
}).ToList();
foreach (var tutorCom in TutorComs)
{
db.TutorCommission.Add(tutorCom);
db.SaveChanges();
}
See if that is closer to the desired result.

Categories