In class I have this :
public class CustomerMvc
{
public int Id { get; set; }
[Required(ErrorMessage = "LastName mandatory.")]
public string LastName { get; set; }
[EmailValidation(ErrorMessage = "Email not valid.")]
public string Email { get; set; }
}
In another class, I have this :
public class CartMvc
{
public CustomerMvc Customer { get; set; }
[Required(ErrorMessage = "VAT mandatory.")]
public int VatId { get; set; }
}
A Save method int the controller, receive a model type CartMvc. The problem is, in this case, I don't want validate the property type CustomerMvc but only VatId.
Is there a way to bypass, in this case, the validation on CustomerMvc ? Other way ?
Thanks,
You could use a view model:
public class SaveCustomerMvcViewModel
{
public int Id { get; set; }
public string LastName { get; set; }
public string Email { get; set; }
}
and then:
public class SaveCartMvcViewModel
{
public SaveCustomerMvcViewModel Customer { get; set; }
[Required(ErrorMessage = "VAT mandatory.")]
public int VatId { get; set; }
}
Now of course your Save controller action will take the appropriate view model as parameter:
[HttpPost]
public ActionResult Save(SaveCartMvcViewModel model)
{
...
}
And as a side remark, putting the [Required] attribute on a non-nullable integer property (your VatId property) hardly makes any sense because a non-nullable integer will always have a value. If you want to validate that the user actually entered some value you'd better use a nullable integer on your view model:
public class SaveCartMvcViewModel
{
public SaveCustomerMvcViewModel Customer { get; set; }
[Required(ErrorMessage = "VAT mandatory.")]
public int? VatId { get; set; }
}
Related
The Problem with this class:
public class ApplicationVM
{
public int Id { get; set; }
public string ApplicantFullName { get; set; }
public DateTime DateOfCreation { get; set; }
public DateTime? DateOfSent { get; set; }
public int NumberOfDays { get; set; }
public ApplicationTypeVM Type { get; set; }
public ApplicationStatusVM Status { get; set; }
[Required(ErrorMessage = "StatedDates required")]
[RegularExpression(#"^((?:^|\s*)\d{2}\.\d{2}\.\d{4})*$", ErrorMessage = "StatedDates invalid")]
public string StatedDates { get; set; }
[UIHint("CoordinatorEditor")]
[Required(ErrorMessage = "Coordinator required")]
public string CoordinatorFullName { get; set; }
public string Comment { get; set; }
}
Data annotations error messages don't localize. I inherit this class for other view models which are used on UI. For example, this one:
public class RemoteWorkingApplicationVM : ApplicationVM
{
[Required(ErrorMessage = "WorkingPlan required")]
public List<ActivityVM> WorkingPlan { get; } = new List<ActivityVM>();
}
Other localization is working. I think the problem is with inheritance. What do you think?
My thoughts were correct, the problem was with the inheritance. In my case, I needed to add entries for data annotation messages in resources for all supertype view models.
I'm having a client, and it sending the following Signature to the Library
Client UI Signature :
namespace Library.Model
{
public class Person
{
public int PersonId { get; set; }
public string Name { get; set; }
public string streetName { get; set; }
public string City { get; set; }
public string State { get; set; }
}
}
Library DB Structure:
namespace Library.Data
{
public class Person
{
public int PersonId { get; set; }
public string Name { get; set; }
public int AddressId { get; set; }
public Address AddressInfo { get; set; }
}
public class Address
{
public int AddressId { get; set; }
public string streetName { get; set; }
public string City { get; set; }
public string State { get; set; }
}
}
Here I'm doing the mapping process from Client UI model to DB Structured model. How could I use the DB structured model as like Client model instead of the Client model.
Kindly assist me how efficiently we can share the DB Structured model in Client?
Note: But the Client the Signature should be
public class Person
{
public int PersonId { get; set; }
public string Name { get; set; }
public string streetName { get; set; }
public string City { get; set; }
public string State { get; set; }
}
Kindly refer Update a class property based on another Property of a calss properties value in the Setter - I need the solution similar to this.
i think you can use PersonViewModel to make this and it will be like you mention
public class PersonViewModel
{
public int PersonId { get; set; }
public string Name { get; set; }
public string streetName { get; set; }
public string City { get; set; }
public string State { get; set; }
}
Make join and file this object
PersonViewModel persons = new PersonViewModel ();
I wish it will help you :)
In my model I have a one to many relationship between Users and Topics class. Code for the two classes is
public class Topic
{
public int TopicID { get; set; }
public int UserID { get; set; }
public virtual User User { get; set; }
[Display(Name="Topic Subject")]
public string TopicSubject { get; set; }
[Display(Name="Date")]
[DataType(DataType.Date)]
public DateTime TopicDate { get; set; }
[DisplayName("Name")]
public int CatagoryID { get; set; }
[DisplayName("FullName")]
public virtual Catagory Catagories { get; set; }
public virtual ICollection<Reply> Replies { get; set; }
}
and
public class User
{
public int UserID { get; set; }
[Display(Name = "First Name")]
[StringLength(50)]
public string FirstName { get; set; }
[Display(Name = "Last Name")]
[StringLength(50)]
public string LastName { get; set; }
[Display(Name="Password")]
[DataType(DataType.Password)]
public string UserPass { get; set; }
[DataType(DataType.EmailAddress)]
public string Email { get; set; }
[DataType(DataType.Date)]
public DateTime Date { get; set; }
[Display(Name = "Full Name")]
public string FullName
{
get { return FirstName + ", " + LastName; }
}
public virtual ICollection<Topic> Topics { get; set; }
public virtual ICollection<Reply> Replies { get; set; }
}
In my controller the action method I used an int id parameter to pass the id internally from the view
public ActionResult Create(int id)
{
ViewBag.CatagoryID = id;
ViewBag.UserID = id;
return View();
}
But when I try to access Topics/Create in my browser an error like this appears and it's bugging me:
Your Create method is the HttpGet version - meaning, why are you passing the id for an object that hasn't been created in order to "create" an object? This should be empty for a create, and the HttpPost should pass back the model so it can only then be created.
Try looking at the create mvc example: http://www.asp.net/mvc/overview/older-versions-1/getting-started-with-mvc/getting-started-with-mvc-part6
For the controller to work you need to pass the id in the query parameters. So you need to use the below url.
http://localhost:63952/Topics/Create?id=1
If you want the id to be optional you need to change your action method like below.
public ActionResult Create(int? id)
{
ViewBag.CatagoryID = id;
ViewBag.UserID = id;
return View();
}
The above will tell C# id param is optional and MVC will not expect it to be present on the query parameters
Hope this helps!!
Try localhost:63952/Create/5
5 refers to the id that you passed in the function Create
you can try any number it will works
I'm using the MetaDataType Attribute on my domain model class. It it supposed to move the attribute information from the referenced class into the class that the MetadataType attribute has been set.
But it doesn't do as advertised. What is causing the issue here?
[MetadataType(typeof(ComponentModelMetaData))]
public partial class Component
{
public int Id { get; set; }
public string Name { get; set; }
public ICollection<Repo> Repos { get; set; }
public string Description { get; set; }
}
public class ComponentModelMetaData
{
[Required(ErrorMessage = "Name is required.")]
[StringLength(30, MinimumLength = 3, ErrorMessage = "Name length should be more than 3 symbols.")]
public string Name { get; set; }
public ICollection<Repo> Repos { get; set; }
[Required(ErrorMessage = "Description is required.")]
public string Description { get; set; }
}
ASP.NET Core uses
Microsoft.AspNetCore.Mvc **ModelMetadataType**
instead of
System.ComponentModel.DataAnnotations.**MetadataType**
source
Try changing your attribute to [ModelMetadataType(typeof(ComponentModelMetaData))]
Entity class:
namespace CoreProject.Persistence.EFCore
{
public partial class User
{
public User()
{
Reader = new HashSet<Reader>();
Writer = new HashSet<Writer>();
}
public int UserId { get; set; }
public string Email { get; set; }
public string Password { get; set; }
public string PasswordHashKey { get; set; }
public byte Role { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public DateTime CreatedUtc { get; set; }
public DateTime LastUpdateUtc { get; set; }
public byte Status { get; set; }
public bool Deleted { get; set; }
public DateTime? ActivatedUtc { get; set; }
public bool Test { get; set; }
public virtual ICollection<Reader> Reader { get; set; }
public virtual ICollection<Writer> Writer { get; set; }
}
}
Metadata (Both have to use the same namespace):
namespace CoreProject.Persistence.EFCore
{
[ModelMetadataType(typeof(IUserMetadata))]
public partial class User : IUserMetadata
{
public string FullName => FirstName + " " + LastName;
}
public interface IUserMetadata
{
[JsonProperty(PropertyName = "Id")]
int UserId { get; set; }
[JsonIgnore]
string Password { get; set; }
[JsonIgnore]
string PasswordHashKey { get; set; }
[JsonIgnore]
byte Role { get; set; }
}
}
Another way... use same namespace
public class ApirolesMetaData
{
[Required]
public string Name { get; set; }
}
[ModelMetadataType(typeof(ApirolesMetaData))]
public partial class Apiroles
{
}
I'm in a similar situation, where the database existed before the coding began. So DB first seemed the natural choice. Generated classes, none of which have annotations. So added MetadataType, and found this stackOverflow page - and so tried ModelMetadataType. I tried it against a class, as well as an interface.
I tried using var validationContext = new ValidationContext(model);
instead of var editContext = new EditContext(model);
and got further when I used var result = Validator.TryValidateObject(model, validationContext, xxxxx, validateAllProperties: true);
I thought I figured it out when I tried editContext.AddDataAnnotationsValidation();
Although this works for a class with annotations, it doesn't work (for me) for partial classes using either [MetadataType] or [ModelMetadataType] attributes.
The only work-around I've found to work (for me) is to create a new class that wraps the model you're wanting to annotate. That means same properties but getters and setters pointing at original model. But at least the annotations will work!
public class Model
{
public int ID { get; set; }
public string Name { get; set; }
}
public class AnnotatedModel
{
private readonly Model model;
public AnnotatedModel(Model model)
{
this.model = model;
}
[Range(1, int.MaxValue)]
public int ID { get => model.ID; set => model.ID = value; }
[Required]
[StringLength(maximumLength: 10, ErrorMessage = "Name can't be longer than 10 characters.")]
public string Name { get => model.Name; set => model.Name = value; }
}
So to use the above, I needed to write this:
var model = new Model();
var annotatedModel = new AnnotatedModel(model);
var editContext = new EditContext(annotatedModel);
editContext.AddDataAnnotationsValidation();
var result = editContext.Validate();
If anyone can tell me what I'm missing, great! Otherwise I hope this work-around will be useful for somebody.
I'm coming from webforms, and I'm trying to replicate a simple data model in MVC. I'm a .NET and C# novice, so excuse me if this is a really simple question. I have "Letters" that each have one category and multiple recipients. EF seems to create my data model correctly on the SQL backend, but I cant access the category in the view. Here is my model:
namespace FFLettersMVC.Models
{
public class Letter
{
public int id {get; set;}
public DateTime dateCreated { get; set; }
public string letterTitle { get; set; }
public DateTime dateMailed { get; set; }
public string createdBy { get; set; }
public string Type { get; set; }
public int CategoryID { get; set; }
public Category Category { get; set; }
public virtual ICollection<Recipient> Recipient { get; set; }
}
public class Category
{
public int id { get; set; }
public string name { get; set; }
}
public class Recipient
{
public int id { get; set; }
public int letterID { get; set; }
public string fname { get; set; }
public string lname { get; set; }
public string ssnTin { get; set; }
public string email { get; set; }
public Letter Letter { get; set; }
}
}
Controller Code for Details Page:
//
// GET: /Letter/Details/5
public ViewResult Details(int id)
{
Letter letter = db.Letters.Find(id);
return View(letter);
}
View Code Attempting to access comments property:
<div class="display-label">Category</div>
<div class="display-field">
#Html.DisplayFor(model => model.Category.name)
</div>
You need to make it virtual, as you did the Recipient.
public virtual Category Category { get; set; }
Marking the property as 'virtual' notifies EF to override the property when creating its proxies.