RequiredAttribute doesn't appear on client-side validation, on derived class - asp.net-mvc-3

My viewmodel inherits from a class that inherits from an abstract class that has a property with a [Required] attribute, but the rule doesn't appear in the DOM and unobtrusive validation doesn't catch the error.
The display attribute goes through fine, but the validation DOM attributes are not added to the textarea
my view has this:
#model FormPersonView
....
#Html.TextAreaFor(m => m.Description)
#Html.ValidationMessageFor(m => m.Description)
my code has this:
public class FormPersonView : Person
{
//View related stuff
.....
.....
}
public class Person : BasePerson
{
//Person related stuff - validation for these work!
[Required]
public string FirstName { get; set; }
[Required]
public string LastName { get; set; }
}
public abstract class BasePerson
{
//Base person stuff - validation for this doesn't work!
public string Id { get; set; }
[Required]
[Display("Short description of the person")]
public string Description { get; set; }
}
Why does it work with one level of inheritance but not two? It does work on the server side.

Had exactly this problem. While defining the view, the model comes as a type you defined #model FormPersonView. Data annotations will only work on that specific type, even if you have derived properties from children, their data annotations won't be engaged.
The solution that I came up with in my project was to define editor templates for types I needed data annotations to work properly and then calling #EditorFor on those models. Then and only then were data annotations operating as expected.
Hope this help you.

Related

Giving error while creating partial class

I am developing MVC application in which , I am trying to create the partial class of class generated by MVC application lets say Location class.
Now I want to create the partial class of Location class in new class file.
The below class code is auto genrated by MVC of Location code.
namespace CRM
{
public partial class Location
{
public int Id { get; set; }
public string Name { get; set; }
public string Remark { get; set; }
}
}
I have added new class file which contain the partial class of above file
namespace CRMEntities.Partial_Class
{
public interface ILocation
{
[StringLength(50, ErrorMessage = "Region can accept maximum 50 characters.")]
string Region { get; set; }
[Key]
int Id { get; set; }
[Required]
string Name { get; set; }
string Remark { get; set; }
}
public partial class Location : ILocation
{
}
}
Its giving the below error...
CRMEntities.Partial_Class.Location' does not implement interface member 'CRMEntities.Partial_Class.ILocation.Name
First, you don't need to do this, what I understand is you are trying to do validation right? Think about, the object generated by EF is not ViewModel, they are domain model. Data annotation should be in View Model, not domain model.
Most of cases, often mis-use is to use domain model as view model, but it is not correct much. Because sometime, view models need more than one domain model to provide data for your UI.
So for separation of concerns, you need to define your View Model different with domain model.
Example: you have Location class, you need to add LocationViewModel class and put data annotation in here.
You can map manually or use AutoMapper for mapping bettween View Model and Domain Model.
Another solution is you can use Fluent Validation, with this way, needless to have more partial class just for validation.
You don't show the definition of ILocation in your question, but the error says that the Location.Name property is declared differently than the ILocation.Name member.
Edit: Your two partial classes appear to be in two different namespaces, hence they are actually two entirely different classes, not two parts of the same class. That would explain the compiler error.
Having said that, I do agree with the other answer (+1!) that you should do your UI validation on a view model instead.

Failing to get unobtrusive client validation

I figured out that property i want to be validated has to have [Required] attribute in C#
(am i right?)
If so -my model is linq generated class - how to add this attribute?
You can do it a couple of ways:
If it's possible, make the field non-nullable in the database. This will make the field required at the data layer.
Create a partial class that adds a property to your model class. Use this property instead of the database-generated property.
For example:
public partial class YourEntity
{
[Required]
public string YourNewProperty
{
get { return this.TheRealProperty; }
set { this.TheRealProperty = value; }
}
}
Hopefully this helps
well, you could always make a new class, as a part of a Data access layer, with the same attributes, just put [required] where you want.
I believe your LINQ classes are partials. With MVC, you can use the "MetatDataTypeAttribute"
Like so
[MetadataType(typeof(UserMetadataSource))]
public partial class User {
}
class UserMetadataSource {
[HiddenInput(DisplayValue = false)]
public int UserId { get; set; }
}

MVC 3 / Entity Framework: Binding Collections

I have 2 models, employee and person:
public class Employee
{
[Key]
public int Id { get; set; }
public int? PersonId { get; set; }
[ForeignKey("PersonId")]
public virtual Person Person { get; set; }
}
public class Person
{
public IList<PhoneNumber> PhoneNumbers { get; set; }
public int Id { get; set; }
public string FName { get; set; }
public string LName { get; set; }
public Person()
{
PhoneNumbers = new List<PhoneNumber>
{
new PhoneNumber()
};
}
}
Editor Template for Phone:
#Html.TextBoxFor(x => x.Number)
#Html.DropDownListFor(m => m, new SelectList(Enum.GetNames(typeof (WebMVC.Core.Common.PhoneType))))
To reduce clutter, I removed the other (non-pertinent) properties.
The difficulty I am having is while in the Employee Create(), I can bind the person FName & LName, I cannot bind the PhoneNumbers collection.
I know about the 2008 Haack blog but I do not think it mirrors this situation.
Does anyone know a solution to bind the person phone numbers collection in the employee's Create()?
I'm not exactly sure if PhoneNumber is a custom class that you created, or one that is built into the framework. But if you're having problems with MVC3 mapping posted data to the Employee class like you specified, you might want to look at creating a custom binding. Keep in mind that if your editor template code is incorrect this wont really matter, so I would take a look at that using fiddler first.
Here are a few good sites to get you started, I found them all on SO at one point.
http://odetocode.com/blogs/scott/archive/2009/04/27/6-tips-for-asp-net-mvc-model-binding.aspx
http://odetocode.com/blogs/scott/archive/2009/05/05/iterating-on-an-asp-net-mvc-model-binder.aspx
http://www.singingeels.com/Articles/Model_Binders_in_ASPNET_MVC.aspx
Creating a custom binder gives you complete control over the way that MVC parses your posted model data and populates the object. There are 2 main functions that most people override, CreateModel and BindModel. BindModel is the function you will most likely want to override if this is the way you would like to go.
I don't know what the html from the editor template looks like, but to bind to a collection of custom types it should look something like this:
<input name="[0].Number">
<input name="[0].PhoneType">
<input name="[1].Number">
<input name="[1].PhoneType">
<input name="[2].Number">
<input name="[2].PhoneType">

Ignoring properties when serializing

I'm pulling my hair out on this one.
I am trying to implement a multi-step wizard, and i'm using the Html.Serialize html helper in MVC3 Futures. This works well, except one of the properties in my model is a SelectList. I don't want this property serialized (and it blows up when it tries anyways).
I can't use [NonSerialized] because that only works on fields, not properties. I've even tried some of the other normal ways such as [XmlIgnore] (which I didn't think would work anyways).
Can anyone suggest an attribute that will ignore a property in a model when using Html.Serialize?
EDIT:
The error I get when I try to serialize is a InvalidDataContractException. There is this message:
Type 'System.Web.Mvc.SelectList' cannot be serialized. Consider marking it with the DataContractAttribute attribute, and marking all of its members you want serialized with the DataMemberAttribute attribute. If the type is a collection, consider marking it with the CollectionDataContractAttribute. See the Microsoft .NET Framework documentation for other supported types.
However, if I do this then I have to mark all the members with [DataMember] just to exclude 1 property, which seems kind of stupid.
UPDATE:
A quick example of this is this bit of code (make sure to add reference to System.Runtime.Serialization.dll):
Test.cs
[Serializable]
public class Test
{
public int ID { get; set; }
[IgnoreDataMember]
public SelectList TestList { get; set; }
}
HomeController.cs
public ActionResult About()
{
return View(new Test() { ID = 0, TestList = new SelectList(new [] {""})});
}
Home/About.cshtml
#using Microsoft.Web.Mvc
#model MvcApplication3.Models.Test
#Html.Serialize("Test", Model)
This generates the InvalidDataContractException
public class MyViewModel
{
[IgnoreDataMember]
public SelectList Items { get; set; }
...
}
or simply:
public class MyViewModel
{
public IEnumerable<SelectListItem> Items { get; set; }
...
}

Can AutoMapper map object to model property of the same type

I am attempting to improve my data flow between my MVC 3 Model and Views (mainly CRUD). I have taken the approach of using ViewModels and FormModels. My ViewModel contains everything it need to represent the view FormData, DropDownLists etc. The FormModel simply contains the FormData fields that are submitted by the form and are needed to update a record.
My question is can I use AutoMapper to map UserDto information onto my FormData field in my ViewModel?
Obviously my mapping below is only mapping between the two object and not an object to property but I have tried using the ‘.ForMember’ mapping options but they are again for object members not an object to an object member. I have also looked at Custom Type Convertors but not sure if this is the right way to go.
Mapper.CreateMap<UserDto, UserViewModel>();
Mapper.CreateMap<UserViewModel, UserDto>();
public class UserViewModel
{
public User FormData { get; set; }
// DropDownLists
// Other view specific data
}
public class UserFormModel
{
public int UserId { get; set; }
[Required]
public string Name { get; set; }
[Required]
public string Age { get; set; }
[Required]
public string Email { get; set; }
}
Any help would be much appreciated.
You need to create the map to the FormData property type and then tell AutoMapper to use this map.
(The following will likely not compile; I'm in the process of recreating my work machine and am working from memory).
Mapper.CreateMap<UserDto, User>(); // set up property mapping
Mapper.CreateMap<UserDto, UserViewModel>()
.ForMember(vm => vm.FormData, map => map.MapFrom(dto => Mapper.Map<UserDto, User>(dto)));

Resources