Html.DropDownListFor() set default selected value MVC3 - asp.net-mvc-3

I want to set the default selected value in DropDownListFor when the element is created
Data model:
public class CascadingDropDownModel
{
public int? PreviousFirstListId { get; set; }
public int? SelectedFirstListId { get; set; }
public int? SelectedSecondListId { get; set; }
public string FirstTextHint { get; set; }
public string SecondTextHint { get; set; }
public IList<DropDownElement> FirstDropDownData { get; set; }
public IList<DropDownElement> SecondDropDownData { get; set; }
public CascadingDropDownModel()
{
FirstDropDownData = new List<DropDownElement>();
SecondDropDownData = new List<DropDownElement>();
}
}
Partial view (doesn't work):
#Html.DropDownListFor(
m => m.SelectedFirstListId,
new SelectList(Model.FirstDropDownData, "Id", "Name", Model.SelectedFirstListId),
Model.FirstTextHint)
Partial view (work):
#Html.DropDownListFor(
m => m.SelectedFirstListId,
new SelectList(Model.FirstDropDownData, "Id", "Name", 5),
Model.FirstTextHint)
Please, tell me what the problem is?

Related

Why is Entity Framework navigation property null?

I am use code first model with a relationship below
public class ApplicationUser : IdentityUser
{
public string UserFirstName { get; set; }
public string UserLastName { get; set; }
public string UserSchool { get; set; }
public UserProfileData UserProfileData { get; set; }
public int? MedicalSpecialtyId { get; set; }
public virtual MedicalSpecialty MedicalSpecialty { get; set; }
// public int? AnalyticsDataId { get; set; }
// public ICollection<AnalyticsData> AnalyticsDatas { get; set; }
}
public class MedicalSpecialty
{
public int Id { get; set; }
public string Description { get; set; }
// public int ApplicationUserId { get; set; }
public virtual ApplicationUser ApplicationUser { get; set; }
public ICollection<ProgramDetailData> ProgramDetailDatas { get; set; }
}
And when I try to get a User's associated MedicalSpecialty object it is NULL
userSpecialtyName = currentUser.MedicalSpecialty.Description;
BUT when I run this code above it the currentUser.MedicalSpecialty is no longer NULL. What happened?? Somehow that LINQ query woke up the object and filled it with data
var userSpecialtyId = currentUser.MedicalSpecialtyId;
userSpecialtyName = _medicalSpecialtyRepository.Find
(x => x.Id == userSpecialtyId).FirstOrDefault().Description;
userSpecialtyName = currentUser.MedicalSpecialty.Description;

MVC Query expressions over source type 'dynamic' or with a join sequence of type 'dynamic' are not allowed

I am trying to get this expression working in my Razor file:
<span>#($" ({string.Join(", ", from o in comment.CommentStaff.StaffOffices select o.Office.OfficeOrganizationCd)})")</span>
But it says "Query expressions over source type 'dynamic' or with a join sequence of type 'dynamic' are not allowed" in the red squiggly in the Razor and the Developer exception page.
Here is my model (#model CommentVM) coming down to the Razor from the controller action:
public class CommentVM
{
public int AuditId { get; set; }
public string Comment { get; set; }
public IEnumerable<Comment> Comments { get; set; }
}
Here is the Controller Action (actually this is coming from the Invoke method in a component. But this shouldn't really make a difference).
public IViewComponentResult Invoke(int auditId)
{
IQueryable<Comment> comments = _commentRepo.Comments.Include(c => c.CommentStaff).ThenInclude(c => c.StaffOffices)
.Where(c => c.CommentAuditId == auditId)
.OrderByDescending(c => c.CommentDate).Take(3);
CommentVM commentVM = new CommentVM
{
AuditId = auditId,
Comments = comments
};
return View(commentVM);
}
The Comments Repo returns an IQueryable of Comment objects.
The Comment POCO looks like this:
[Table("comment")]
public class Comment
{
[Key]
[Column("comment_id")]
public int CommentId { get; set; }
[Column("comment_type_cd")]
public string CommentTypeCd { get; set; }
[Column("comment_audit_id")]
public int? CommentAuditId { get; set; }
[Column("comment_finding_id")]
public int? CommentFindingId { get; set; }
[Column("comment_recommend_id")]
public int? CommentRecommendId { get; set; }
[Column("comment_action_item_id")]
public int? CommentActionItemId { get; set; }
[Column("comment_acd_id")]
public int? CommentAcdId { get; set; }
[Column("comment_pdl_id")]
public int? CommentPdlId { get; set; }
[Column("comment_cost_nm")]
public string CommentCostNm { get; set; }
[Required]
[Column("comment_tx")]
public string CommentText { get; set; }
[Column("comment_dt")]
public DateTime CommentDate { get; set; }
#region Navigation Properties
[Column("comment_staff_id")]
public short CommentStaffId { get; set; }
[ForeignKey("CommentStaffId")]
public Staff CommentStaff { get; set; }
#endregion
}
So CommentStaff is a navigation property to a Staff object which has a bridge table POCO called StaffOffices for a many to many relationship between Staff and Office.
Here is the bridge table POCO:
[Table("staff_office")]
public class StaffOffice
{
[Column("staff_office_staff_id")]
public short ID { get; set; }
public Staff Staff { get; set; }
[Column("staff_office_office_id")]
public short OfficeID { get; set; }
public Office Office { get; set; }
}
I am trying to get this:
<span>#($" ({string.Join(", ", from o in comment.CommentStaff.StaffOffices select o.Office.OfficeOrganizationCd)})")</span>
or this:
#{
StringBuilder sb = new StringBuilder();
foreach(var o in comment.CommentStaff.StaffOffices)
{
sb.Append(o.Office.OfficeOrganizationCd);
}
}
<span>#sb.ToString()</span>
It's a partial view. I needed to include the model definition of the parent Razor file:
#model CommentVM

How to debug AutoMapper "Missing type map configuration or unsupported mapping" error

I have seen plenty of examples of this error occuring, for a wide variety of causes and I have gone through all the causes I can see, but still i get the error, so I am wondering if some one can give some information about what this error actually means, so i can try finding the cause. Here is some code:
Controller:
[HttpPost]
public ActionResult Edit(ProfileViewModel model)
{
if (ModelState.IsValid)
{
var person = new UserAttribute();
person = Mapper.Map<ProfileViewModel, UserAttribute>(model);
db.UserAttribute.Add(person);
db.SaveChanges();
}
View Model
public class ProfileViewModel
{
[Display(Name = "First Name")]
[StringLength(20)]
[Required]
public string FirstName { get; set; }
[Display(Name = "Last Name")]
[StringLength(30)]
[Required]
public string LastName { get; set; }
[Display(Name = "Gender")]
[Required]
public string Gender { get; set; }
[Display(Name = "Date of Birth")]
[DisplayFormat(DataFormatString = "{0:MM/dd/yyyy}", ApplyFormatInEditMode = true)]
public DateTime DOB { get; set; }
[Display(Name = "Hair Color")]
public string HairColor { get; set; }
[Display(Name = "Eye Color")]
public string EyeColor { get; set; }
[Display(Name = "Body Type")]
public string Weight { get; set; }
[Display(Name = "Height")]
public string HeightFeet { get; set; }
public string HeightInches { get; set; }
public int UserId { get; set; }
public IEnumerable<SelectListItem> WeightList { get; set; }
public IEnumerable<SelectListItem> EyeColorList { get; set; }
public IEnumerable<SelectListItem> HairColorList { get; set; }
public IEnumerable<SelectListItem> HeightFeetList { get; set; }
public IEnumerable<SelectListItem> HeightInchesList { get; set; }
public IEnumerable<SelectListItem> GenderList { get; set; }
}
UserAttribute model:
public int ProfileId { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public string Gender { get; set; }
public System.DateTime DOB { get; set; }
public string HairColor { get; set; }
public string EyeColor { get; set; }
public string HeightFeet { get; set; }
public string Weight { get; set; }
public int UserId { get; set; }
public string HeightInches { get; set; }
Mapping config:
public class AutoMapperConfiguration
{
public static void Configure()
{
Mapper.Initialize(x => x.AddProfile<ViewToDomainMapProfile>());
Mapper.Initialize(x => x.AddProfile<DomainToViewMapProfile>());
}
}
public class ViewToDomainMapProfile : Profile
{
public override string ProfileName
{
get { return "ViewToDomainMapProfile"; }
}
protected override void Configure()
{
Mapper.CreateMap<ProfileViewModel, UserAttribute>()
.ForSourceMember(x => x.GenderList, y => y.Ignore())
.ForSourceMember(x => x.HairColorList, y => y.Ignore())
.ForSourceMember(x => x.EyeColorList, y => y.Ignore())
.ForSourceMember(x => x.WeightList, y => y.Ignore())
.ForSourceMember(x => x.HeightFeetList, y => y.Ignore())
.ForSourceMember(x => x.HeightInchesList, y => y.Ignore());
}
}
and the config is called in the global asax:
AutoMapperConfiguration.Configure();
Using Mapper.AssertConfigurationIsValid(); produces the following exception:
AutoMapper.AutoMapperConfigurationException :
Unmapped members were found. Review the types and members below.
Add a custom mapping expression, ignore, add a custom resolver, or modify the source/destination type
==============================================================================================
ProfileViewModel -> UserAttribute (Destination member list)
----------------------------------------------------------------------------------------------
ProfileId
So, you need to add mapping for ProfileId.
Overall, it's a good practice to use Mapper.AssertConfigurationIsValid(); either in your unit tests (you have them, right?), or after your mapper configuration. It'll display detailed information for such a misconfigurations.
For the viewmodel => userattribute
I noticed that ProfileId is a destination property, but not a source property.
public int ProfileId { get; set; }
Do you need to add code to ingore this destination member?
Other:
I might also suggest using or customizing the automapper to map properties that present that match by name exclusively.
Also, when possible, please avoid model names ending in the word Attritribute as by convention this is used almost exclusively for actual attributes. (my apologies for nitpicking)

Trouble with Model.IsValid on a property thats not required

I am having trouble with Model.IsValid on a property that's not required.
Here's the code.
BeginForm in the Edit.cshtml file
#using (Html.BeginForm("Edit", "Member", FormMethod.Post, new { enctype = "multipart/formdata" }))
{
#Html.Partial("_MemberForm", Model.Member)
}
MemberEditViewModel: (used for the Edit.cshtml file)
public class MemberEditViewModel
{
public MemberFormModel Member { get; set; }
}
MemberFormModel:
public class MemberFormModel : ICreateMemberCommand, IValidatableObject
{
public int Id { get; set; }
[Required]
public string FirstName { get; set; }
[Required]
public string LastName { get; set; }
[Required]
public string SocialSecurityNumber { get; set; }
[Required]
public int PinCode { get; set; }
[Required]
public char Gender { get; set; }
public string Email { get; set; }
[Required]
public string Address { get; set; }
[Required]
public string ZipCode { get; set; }
[Required]
public string ZipAddress { get; set; }
public string Phone { get; set; }
public string Phone2 { get; set; }
[Required]
public string City { get; set; }
[Required]
public int CountryId { get; set; }
//not required (but still displaying error it's required)
public Membership Membership { get; set; }
// not required (displaying error it's required)
public PunchCard PunchCard { get; set; }
public bool IsActive { get; set; }
block of _MemberForm.cshtml (partial)
<fieldset>
<dl>
<dt>#Html.LabelFor(m => m.Id)</dt>
<dd>#Html.TextBoxFor(m => m.Id, new { disabled = "disabled", #readonly = "readonly" })</dd>
<dt>#Html.LabelFor(m => m.PinCode)</dt>
<dd>#Html.EditorFor(m => m.PinCode)</dd>
<!-- problem with membership, maybe with the .FromData/ToDate ? -->
<dt>#Html.LabelFor(m => m.Membership)</dt>
<dd>#Html.EditorFor(m => m.Membership.FromDate, new { #name = "Membership" }) -
#Html.EditorFor(m => m.Membership.ToDate, new { #name="Membership"})</dd>
<!-- problem with punch card, maybe with the .Times ? -->
<dt>#Html.LabelFor(m => m.PunchCard)</dt>
<dd>#Html.EditorFor(m => m.PunchCard.Times, new { #name = "PunchCard" })</dd>
</dl>
</fieldset>
The MemberController Edit Action
// POST: /Members/10002/Edit
[HttpPost]
public ActionResult Edit(FormCollection formValues, MemberFormModel memberForm)
{
var errors = ModelState.Values.SelectMany(v => v.Errors);
if(IsSaveOperation(formValues)){
if(TryUpdateMember(memberForm)){
return RedirectToAction("Details", "Member", new {id = memberForm.Id});
}
}
var mm = new MemberEditViewModel{ Member = memberForm };
return View(mm);
}
Membership.cs
public class Membership
{
public Membership(){ /* empty constructor */}
public Membership(int id, int memberId, DateTime fromDate, DateTime toDate)
{
Id = id;
MemberId = memberId;
FromDate = fromDate;
ToDate = toDate;
}
public int Id { get; set; }
public int MemberId { get; set; }
[DataType(DataType.Date)]
public DateTime FromDate { get; set; }
[DataType(DataType.Date)]
public DateTime ToDate { get; set; }
}
PunchCard.cs
public class PunchCard
{
public PunchCard() { /* empty constructor */ }
public PunchCard(int memberId, int times, DateTime createdDate, DateTime modifiedDate)
{
this.MemberId = memberId;
this.Times = times;
this.CreatedDate = createdDate;
this.ModifiedDate = modifiedDate;
}
public int Id { get; set; }
public int MemberId { get; set; }
public int Times { get; set; }
public DateTime CreatedDate { get; set; }
public DateTime ModifiedDate { get; set; }
}
You see I dont have any [Required] attribute, neither in the MemberFormModel. So how come those two are Required ? Its a mystery.
You should not be using both the disabled and readonly attribute on your textbox:
#Html.TextBoxFor(m => m.Id, new { disabled = "disabled", #readonly = "readonly" })
I guess the disabled attribute takes precedence and the value of the Id is never sent to the server when you submit the form. That's why you get a modelstate error. Because your id property is required. Now you will be probably tell me that it is not decorated with the [Required] attribute but this doesn't matter. Since you have declared it as a non-nullable integer it is implicitly required and the framework automatically makes it required. If you don't want this to happen you should declare it as a nullable integer.
So back to your view, if you want to only display id, without allowing the user to modify it, use readonly:
#Html.TextBoxFor(m => m.Id, new { #readonly = "readonly" })
Obviously don't think that if you made a textbox readonly, the user cannot modify it. The normal user will not. But a hacker could always put whatever value he wants in this textbox and forge a request. So absolutely do not rely on this as some sort of security or something.

Asp.Net MVC3 - How create Dynamic DropDownList

I found many articles on this but still I don´t know how exactly to do this. I am trying to create my own blog engine, I have View for create article (I am using EF and Code first) and now I must fill number of category in which article should be add but I want to change it to dropdownlist with names of categories. My model looks this:
public class Article
{
public int ArticleID { get; set; }
[Required]
public string Title { get; set; }
[Required]
public int CategoryID { get; set; }
public DateTime Date { get; set; }
[Required()]
[DataType(DataType.MultilineText)]
[AllowHtml]
public string Text { get; set; }
public virtual Category Category { get; set; }
public IEnumerable<SelectListItem> Categories { get; set; }
public virtual ICollection<Comment> Comments { get; set; }
}
public class Category
{
public int CategoryID { get; set; }
[Required]
public string Name { get; set; }
public virtual ICollection<Article> Articles { get; set; }
}
I know I must use Enum (or I think) but I am not exactly sure how. I don´t know which tutorial from that I found is best for me.
Edit:
Thanks for your answers but I found something else. I am trying this:
This is my model:
public class Article
{
[Key]
public int ArticleID { get; set; }
[Display(Name = "Title")]
[StringLength(30, MinimumLength = 5)]
[Required]
public string Title { get; set; }
public DateTime Date { get; set; }
public int CategoryID { get; set; }
[Required()]
[DataType(DataType.MultilineText)]
[AllowHtml]
public string Text { get; set; }
public Category Category { get; set; }
public virtual ICollection<Comment> Comments { get; set; }
public IEnumerable<Category> Categories { get; set; }
}
public class Category
{
[Key]
public int CategoryId { get; set; }
[Required]
public string CategoryName { get; set; }
public virtual ICollection<Article> Articles { get; set; }
}
This is my controller to create article:
public ActionResult Vytvorit()
{
IEnumerable<Category> categories = GetCaregories();
var view = View(new Article() { Categories = categories });
view.TempData.Add("Action", "Create");
return view;
}
private static IEnumerable<Category> GetCaregories()
{
IEnumerable<Category> categories;
using (BlogDBContext context = new BlogDBContext())
{
categories = (from one in context.Categories
orderby one.CategoryName
select one).ToList();
}
return categories;
}
private Category GetCategory(int categoryID)
{
return db.Categories.Find(categoryID);
}
//
// POST: /Clanky/Vytvorit
[HttpPost]
public ActionResult Vytvorit(Article newArticle)
{
try
{
if (newArticle.CategoryID > 0)
{
newArticle.Category = GetCategory(newArticle.CategoryID);
}
if (TryValidateModel(newArticle))
{
db.Articles.Add(newArticle);
db.SaveChanges();
return RedirectToAction("Index");
}
else
{
newArticle.Categories = GetCaregories();
var view = View(newArticle);
view.TempData.Add("Action", "Create");
return view;
}
}
catch
{
return View();
}
}
And this is part of my view:
#Html.DropDownListFor(model => model.CategoryID, new SelectList(Model.Categories,"CategoryID","CategoryName"))
#Html.ValidationMessageFor(model => model.CategoryID)
I have problem with NullReferenceExeption but I don´t know why. Can I do it this way? It looks very easy for me.
Your model seems quite strange. It contains properties such as CategoryID and Category which seem redundant. It also contains a SelectListItem collection property called Categories. So, is this a model or a view model? It looks quite messed up. Let's assume it's a model. In this case it would more likely look something like this:
public class Article
{
public int ArticleID { get; set; }
[Required]
public string Title { get; set; }
public DateTime Date { get; set; }
[Required()]
[DataType(DataType.MultilineText)]
[AllowHtml]
public string Text { get; set; }
public virtual Category Category { get; set; }
public IEnumerable<Category> Categories { get; set; }
public virtual ICollection<Comment> Comments { get; set; }
}
public class Category
{
public int CategoryID { get; set; }
[Required]
public string Name { get; set; }
public virtual ICollection<Article> Articles { get; set; }
}
Now that the model is clear we could define a view model which will be passed to the view. A view model is a class which is specifically designed for the view. So depending on what you intend to put in this view you define it in this view model. So far you have talked only about a drop down, so let's do it:
public class ArticleViewModel
{
public int SelectedCategoryId { get; set; }
public IEnumerable<SelectListItem> Categories { get; set; }
}
and then we have a controller:
public class ArticlesController: Controller
{
private readonly IArticlesRepository _repository;
public ArticlesController(IArticlesRepository repository)
{
_repository = repository;
}
public ActionResult Index()
{
Article article = _repository.GetArticle();
ArticleViewModel viewModel = Mapper.Map<Article, ArticleViewModel>(article);
return View(viewModel);
}
}
So the controller uses a repository to fetch the model, maps it to a view model (in this example I use AutoMapper) and passes the view model to the view which will take care of showing it:
#model AppName.Models.ArticleViewModel
#using (Html.BeginForm())
{
#Html.DropDownListFor(
x => x.SelectedCategoryId,
new SelectList(Model.Categories, "Value", "Text"),
"-- Select category --"
)
<input type="submit" value="OK" />
}
I have gone through this as well and I have to agree that at first it seems odd (In my explanation I'm assuming you want to select one category only, but the process is very similar for a multi select).
Basically you need to perform 3 steps:
1:
You need two properties on your viewmodel
One will hold the selected category id (required for postback) and the other will a SelectList with all possible categories:
public class Article
{
public int ArticleID { get; set; }
public int CategoryID { get; set; }
public SelectList Categories { get; set; }
}
2:
Also before passing the viewmodel on to the view you need to initialize the SelectList (Best practivce is to prepare as much as possible before passing a model into the view):
new SelectList(allCategories, "CategoryID", "Name", selectedCategoryID)
3:
In the view you need to add a ListBox for the CategoryID property, but using the Categories property too fill the ListBox with values:
#Html.ListBoxFor(model => model.CategoryID , Model.Categories)
Thats it! In the post back action of the controller you will have the CategoryID set. You can do whatever you need to from there to persist things in your db.

Resources