I am using Data Annotations in my MVC 4 project with Scaffolding Nuget to create CRUD views. I am using Layer level Database model not EF.
So my Class look like as below:
[MetadataType(typeof(CustomerMetaData))]
public partial class UserProfile: IBrObject
{
public UserProfile(string aspUserName): this()
{
this.AspUserName = aspUserName;
}
public string AspUserName { get; set; }
public DateTime MetaDateFirstSaved { get; set; }
}
public class CustomerMetaData
{
[ReadOnly(true)]
[ScaffoldColumn(false)]
[DisplayName("ASP UserName")]
public object AspUserName { get; set; }
[DisplayName("Date First Saved")]
[DataType(DataType.Date)]
public object MetaDateFirstSaved { get; set; }
}
when i am trying to create views with Scaffolding Nuget it still shows AspUserName column not hide or not read only.
How i can hide or readonly ?
You use object in metadata and string and DateTime respectively in actual view model so they don't match.
Update
Another possibility (I pretty sure this is what's happening in your case) is because your model type in the view defined as Interface type rather than class type.
In your view replace #model IBrObject with #model UserProfile.
Hope this helps
object AspUserName != string AspUserName
Related
I have a Person model and a student model. The student model has 2 FKs of PersonIDs; one for student and the other for parent.
My view looks like this:
#Html.EditorFor(m => m.student.Person.FirstName)
#Html.EditorFor(m => m.student.Person.DOB)
#Html.EditorFor(m => m.student.Father.FirstName)
The models would look like this:
public partial class Person
{
public int PersonID { get; set; }
[Required]
[PlaceHolder("First Name")]
public string FirstName { get; set; }
[PlaceHolder("Birth Date")]
public Nullable<System.DateTime> DOB { get; set; }
}
public partial class Student
{
public int Student_PersonID { get; set; }
public int Parent_PersonID { get; set; }
}
I want the DOB to be required field for the student but not for the parent. If I add [Required] attribute to the DOB element, then it requires it for both. Is there a way I can set a require a field on the view? or is there a way in the model or using validation attribute to do this?
fyi... i am using EF database first approach
thanks
I would suggest having the view model match the fields that are displayed in the view. If later a field is to be removed from the view, then it will also be removed from the domain model.
In this case, if your view is to display the following fields:
StudentFirstName
StudentDOB
ParentFirstName
ParentDOB
Then I would suggest having the following view:
public class PersonViewModel
{
public int StudentPersonID { get; set; }
[Required]
public string StudentFirstName { get; set; }
[Required]
public DateTime StudentDOB { get; set; }
public int ParentPersonID { get; set; }
[Required]
public string ParentFirstName { get; set; }
public DateTime ParentDOB { get; set; }
}
Or if instead you have 2 seperate views displaying:
StudentFirstName
StudentDOB
AND displaying:
ParentFirstName
ParentDOB
Then I would suggest having 2 seperate view models:
public class StudentViewModel
{
public int StudentPersonID { get; set; }
[Required]
public string StudentFirstName { get; set; }
[Required]
public DateTime StudentDOB { get; set; }
}
public class ParentViewModel
{
public int ParentPersonID { get; set; }
[Required]
public string ParentFirstName { get; set; }
public DateTime ParentDOB { get; set; }
}
Using the view models in this way will allow you to use the [Required] data annotations for the fields that require them rather than trying to create a workaround. Note that the view models are not to be confused with the domain models and therefore this data would then need to be mapped to the domain model.
Hope this helps.
If your application is a simple application you may not need to create a seperate business logic layer and most books only present MVC with simple models which may be fine. However, if you search around you will find other examples where developers recommend having a view model seperate from a business model such as this
I would also recommend reading Wrox Professional Enterprise .Net 2009 where chapters 7 & 8 give great examples of the business layer with discussions of the Transaction Script pattern, Active Record pattern and Domain Model pattern.
One way is to make a PersonRequired class that inherits from Person. Add a metadata class to PersonRequired so you have PersonRequiredMetaData and in that specific that the inherited DOB field is required. You would need to manually copy the values between the Person and PersonRequired classes or use AutoMapper. I hope there is a better answer than this!
Another option is to use FluentValidation that would let you do the validation separate from the model (doesn't use data annotations). I wonder if some people are using data annotations for database requirements and fluent validation for programmatic requirements.
I have the following ViewModel and i would like to create a custom binder to bind subclasses (LogOnModel, ChangePasswordModel).
public class LogOnViewModel
{
public string NextStep { get; set; }
public string PreviousStep { get; set; }
public string ReturnUrl { get; set; }
public bool MustChangePassword { get; set; }
public bool MustAgreeNewPrivacyStatement { get; set; }
public LogOnModel logOnModel { get; set; }
public ChangePasswordModel changePasswordModel { get; set; }
}
I was able to create my custom binder (inherit from DefaultModelBinder) but never was able to get a full VALIDATED model (ModelState populated) back into my controller. It's working fine for simple type (string, bool, ....) but a bit more complicated with complex type (subclass).
Is MVC 3 Futures the answer to my question or someone was able to override DefaultModelbinder to bind subclasses?
Thanks,
Michel
You will have to create custom model binders for LogOnModel and ChangePasswordModel as well; your custom model binder doesn't know automatically how to bind your complex types.
I've seen somewhere how to do this before on a blog but I forgot where or how. Lets say I have a domain in a class library. I'd like to data annotate the properties of this domain as my viewmodel in the web project.
How do I accomplish this?
For example. This domain is in my class library:
public class Person {
public int Id {get; set;}
public string FirstName {get; set;}
}
In my web project, there is this:
//Do i need to set some attribute here?
public class CreatePersonViewModel{
[Required()]
[DisplayName("First Name")]
public string FirstName {get; set;}
}
This code can be mapped to Person without a tool. Probably partial or something.
The whole idea of using a view model is to decouple it from your domain model and to have something which is adapted to the needs of the view. The view model should be declared in the web project and contain all the necessary properties and formatting attributes that this particular view might require. The domain model shouldn't be polluted with any view specific data annotations. So if your model looks like this:
public class Person {
public int Id { get; set; }
public string FirstName { get; set; }
}
You could have the following view model:
public class CreatePersonViewModel {
[Required]
[DisplayName("First Name")]
public string FirstName { get; set; }
}
and then have the controller fetch the model from some repository, map it to the view model (AutoMapper can help you here) and pass the view model to the view.
Do you mean annotate your Domain objects or your view model objects?
Using the System.ComponentModel.DataAnnotations validation attributes (and deriving any of your own from ValidationAttribute, you can validate values bound to the properties of your viewmodel at the point of model binding.
Scott Guthrie has a detailed blog post about Model validation with data annotation validation attributes.
EDIT: you say in a comment to another poster that your types already exist. You can add the MetadataTypeAttribute to the existing type to indicate another type that holds the validation logic to be applied to the properties of your existing type.
You can create a 'buddy' class for your data annotation attributes
[MetadataType(typeof(ResourceMetadata))]
public partial class Resource
{
public object Value { get; set; }
}
public class ResourceMetadata
{
// The metadata class can define hints
[UIHint("ResourceValue")]
public object Value { get; set; }
}
Are you talking about this type of thing?:
using System.ComponentModel.DataAnnotations;
public MyClass
{
[DisplayName("Street Address")]
public string StreetAddress { get; set; }
}
EDIT:
If you need to add Data Annotations to generated class like an Entity do this:
using System.ComponentModel.DataAnnotations;
using System.ComponentModel;
namespace Something
{
[MetadataType(typeof(MetaMyClass))]
public partial class MyClass
{
//You can just leave this empty if you have nothing additional to add to the class
}
public class MetaMyClass
{
[DisplayName("Street Address")]
public string StreetAddress { get; set; }
}
}
i'd like to know, I have a application in asp.net mvc and nhibernate. I've read about that in the Views on asp.net mvc, shouldn't know about the Domain, and it need use a DTO object. So, I'm trying to do this, I found the AutoMapper component and I don't know the correct way to do my DTOS, for some domain objects. I have a domain class like this:
public class Entity
{
public virtual int Id { get; set; }
public virtual bool Active { get; set; }
}
public class Category : Entity
{
public virtual string Name { get; set; }
public virtual IList<Product> Products { get; set; }
public Category() { }
}
public class Product : Entity
{
public virtual string Name { get; set; }
public virtual string Details { get; set; }
public virtual decimal Prince { get; set; }
public virtual int Stock { get; set; }
public virtual Category Category { get; set; }
public virtual Supplier Supplier { get; set; }
public Product() { }
}
public class Supplier : Entity
{
public virtual string Name { get; set; }
public virtual IList<Product> Products { get; set; }
public Supplier() { }
}
I'd like to get some example of how can I do my DTOs to View ? Need I use only strings in DTO ? And my controllers, it should get a domain object or a DTO and transform it on a domain to save in repository ?
Thanks a lot!
Cheers
There is no guidelines on this matter and it depends on your personal chice. I have few advices that have proven useful in practice:
1. Use flat DTOs - this means that the properties of the DTO must be as primitive as possible. This saves you the need for null reference checking.
For example if you have a domain object like this:
public class Employee
{
prop string FirstName{get; set;}
prop string LastName{get; set;}
prop Employee Boss{get; set;}
...
}
And you need to output in a grid a list of employees and display information for their 1st level boss I prefer to create a DTO
public class EmployeeDTO
{
prop string FirstName{get; set;}
prop string LastName{get; set;}
prop bool HaveABoss{get;set}
prop string BossFirstName{get; set;}
prop string BossLastName{get; set;}
...
}
or something like this (-:
2. Do not convert everything to sting - this will bind the DTO to a concrete view because you'll apply special formatting. It's not a problem to apply simple formatting directly in the view.
3. Use DTOs in your post actions and than convert them to domain objects. Usually controller's actions are the first line of deffence against incorrect data and you cannot expect to be able to allways construct a valid domain object out of the user's input. In most cases you have to do some post-processing like validation, setting default values and so on. After that you can create your DTOs.
I am using EFExtensions with a typed view in mvc and am getting
The model item passed into the dictionary is of type 'Microsoft.Data.Extensions.Materializer`1+d__0[MvcCms.Web.Models.User]' but this dictionary requires a model item of type 'MvcCms.Web.Models.ViewData.SiteAdminModel'.
'MvcCms.Web.Models.ViewData.SiteAdminModel' contains a definition of User, here is the code in SiteAdminModel
public class SiteAdminModel
{
public StateProvince SelectedState { get; set; }
public IEnumerable<StateProvince> States { get; set; }
public IEnumerable<Organization> Organizations { get; set; }
public IEnumerable<User> Users { get; set; }
}
What would be the best way to fix this. Possibly using a codebehind to cast the Materialized version or doing that in the controller?
The problem was occuring because I was passing the model through in the renderpartial and it didn't need to be passed there because the control had access without it.