ASP.NET MVC DropDownList Validation - asp.net

I have
[DisplayName("Country")]
public List<SelectListItem> Countries { get; set; }
property in strong-type Model View class for DropDownList.
When I try to check if the ModelState.IsValid on form postback it's always false & error for Countries tells "Can't convert [value] to SelectListItem" or some of a kind.
I figured out there is no straight-forward mapping for drop down selected value (looks like I'll have to read value from Form value collection), but how can I ignore binding and validation for List property? I just want to make ModelState.IsValid attribute to be true if all the other fields are populated properly.
Thank you in advance

Finally I used workaround.
My model now:
class Model
{
...
[DisplayName("Country")]
List<Country> Countries;
Guid CountrySelected <-- new field!
...
}
I use Html.DropDownList("CountrySelected", Model.Countries.Select(x => new SelectItemList.. )
instead of HtmlDropDownListFor. HtmlDropDownListFor maps [id selected] to List not to CountrySelected property. Now [id selected] is mapped to CountrySelected

Is it because the value submitted is of type String or Country rather than a list of SelectListItem or List<SelectListItem>.
What are you binding to the control in the UI?
try
[DisplayName("Country")]
public List<Country> Countries { get; set; }
Where Country is the type name from your DAL.
EDIT:
Based on the error you are recieving, it sounds like the model is expecting the value to be a String so try swapping List<Country> for List<String>.
[DisplayName("Country")]
public List<string> Countries { get; set; }

Related

Bind city column values in db to view as Dropdownlist using mvc4 and stored procedure

In my project City table is there. in my applcation I want city to place as dropdown list. I am using ADO net. can u please give me some idea how can i use it in controller and bind it to view #Html.DropDownListFor
Simplest method to bind dropdownlist in mvc(i m taking hypothetical example here) :-
Controller :
[HttpGet]
public ActionResult Index()
{
Maplocations obj=new Maplocations();
obj.mapLocationItemTypes = binddropdown();
return View(obj);
}
Public List<SelectListItem> binddropdown()
{
// call stored procedure here and get value for dropdown
}
Model(Maplocations) :
public List<SelectListItem> mapLocationItemTypes { get; set; }
public int mapLocationItemVal { get; set; }
View:
#Html.DropDownListFor(m => m.mapLocationItemVal , new SelectList(Model.mapLocationItemTypes , "Value", "Text"), " -----Select List----- ")
here in above example the 3rd overload of DropDownListFor() i.e. " -----Select List----- " will be the initial selected item of your dropdown with value equal to ' '.
At Controller during POST mapLocationItemVal will have selected dropdown value.
The above shown code is best and simplest way to bind Dropdownlist in MVC.

Get EF 4 database first object property annotation

We are using EF4 database first approach to create all the entities as found in the context class. I'm now trying to add a display name attribute to one of the objects' properties as follows:
[MetadataType(typeof(OpportunityMetaData))]
public partial class Opportunity : EntityObject
{
}
public class OpportunityMetaData
{
[Display(Name = "Worked By")]
public int WorkedById { get; set; }
}
Then on a test page, using reflection, I'm trying to get an output that says "Worked By", as follows:
var attrType = typeof(DisplayNameAttribute);
var property = typeof(Opportunity).GetProperty("WorkedById");
Response.Write(((DisplayNameAttribute)property.GetCustomAttributes(attrType, false).FirstOrDefault()).DisplayName);
But this just gives Object Reference not set to an instance of an object. Alternatively, if I just Response.Write the property, it writes out "WorkedById" and not "Worked By".
Any help would be appreciated.
Its DisplayAttribute, not DisplayNameAttribute. Name is just a property on it.

Pass empty string as nullable int property

My model:
[DisplayName("Height")]
public int? Height { get; set; }
[DisplayName("Width")]
public int? Width { get; set; }
View:
<%= Html.TextBoxFor(x => x.Width) %>
<%= Html.TextBoxFor(x => x.Height) %>
Action:
if (ModelState.IsValid)
SaveSettings(model);
When empty strings are passed from view, the ModelState is false, but I need empty strings to be valid input, so that nulls are passed and ModelState.IsValid will be true. What can I add to the view to add this logic ? Or perhaps any other solution ? Thanks a lot for help.
There are work arounds, such as using a string property on your ViewModel and using a RegEx validator to make sure it is a number. The Regex shouldn't fire on an empty input. Then when you go from ViewModel to Model you'll have to do a conditional on the string value like
var m = new Model();
m.Property = !String.IsNullOrEmpty(this.Property)? int.parse(this.Property) as int?:null;
int? (Nullable<int>) will never be able to accept an empty string. And empty string is neither null or an int value (which are the demands of Nullable<int>).
If you want to intercept this behavior you can design your own custom model binder by either implementing IModelBinder or subclass DefaultModelBinder. Doing this, you can set an empty string value equal to null (or some magic number, but I'd prefer null).

Why is IValidatableObject.Validate only called if property validation passes?

In my model, it seems that Validate() is only called AFTER both properties pass validation.
public class MyModel : IValidatableObject
{
[Required]
public string Name { get; set;}
[Required]
public string Nicknames {get; set;}
public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
{
if(Nicknames != null && Nicknames.Split(Environment.NewLine.ToCharArray()).Count() < 2)
return yield result new ValidationResult("Enter at least two nicknames, new [] { "Nicknames" });
}
}
When a user enters a single line of text in the Nicknames text area but leaves the Name text box empty, only the Required error message for the Name property is displayed. The error message that should be displayed from the Validate() function never shows up.
Only after entering a name in the Name text box and some text in the Nicknames text is the Validate() function called.
Is this how it's supposed to work? It seems odd that a user is shown an error message on a subsequent page when the error is being caused on the current page.
This is by design. Object-level validation does not fire until all the properties pass validation because otherwise it is possible that the object is incomplete. The Validate method is meant for thing like comparing one property to another. In your case you should write a custom property validator.

ViewModel: how to display values from datatable in List View

I have created a viewmodel class for my custom page. I have a stored procedure which returns the DataTable(ORM tool). I cannot change this procedure. But I would like display the records from the stored procedure on View List. How can I display the values from the datatable in the List View? I appreciate any help.
Thanks,
public class CreateViewModel
{
[Required]
public DateTime StartDate {get; set;}
[Required]
[StringLength(250, ErrorMessage = "Details must be less than 250 characters")]
public string Details { get; set; }
}
The main way of doing it would be reading out the column values from each row of the datatable into the view model instance. This is regular DataTable access way. This should be done in your service layer called from your controller action.
If you can't change the stored proc, but are not tied to a DataTable then if you execute the SqlCommand to return a SqlReader. Then you can access the data with the following code (something like):
var list = new List<MyViewData>();
while(reader.Read())
{
var model = new MyViewData();
model.Property = reader.GetString(reader.GetOrdinal("ColumnName"));
// .. etc..
list.Add(model);
}
return list;
This accesses the recordset returned from the stored proc.
You can then set your view's model property as an IEnumerable then you can access each of the instances with a foreach over the model in the view.
Hope this helps.

Resources