Is it possible to use DataAnnotations with Interfaces inheritance? - c#

not performing the validation in PersonaFisica
..
Blockquote
[MetadataType(typeof(IValidationPersona))]
public class Persona : Entidad, IValidationPersona
{
public string Mail { get; set; }
public string Telefono { get; set; }
}
[MetadataType(typeof(IValidationPersonaFisica))]
public class PersonaFisica : Persona, IValidationPersonaFisica
{
public string Nombre { get; set; }
public string Apellido { get; set; }
}
public interface IValidationPersona
{
[DisplayName("Persona -- Email")]
string Mail { get; set; }
[RegularExpression(#"^\d+$", ErrorMessageResourceType = typeof(ValidationMessages), ErrorMessageResourceName = "SoloNumeros")]
string Telefono { get; set; }
}
public interface IValidationPersona
{
[DisplayName("Persona -- Email")]
string Mail { get; set; }
[RegularExpression(#"^\d+$", ErrorMessageResourceType = typeof(ValidationMessages), ErrorMessageResourceName = "SoloNumeros")]
string Telefono { get; set; }
}
validation does not work with inheritance in interfaces, thanks!

This feature is not implemented in the framework for couple of good reasons. Please refer to this MSDN forum DataAnnotations in Interfaces

Related

Automapper Mapping Exception

I am trying to build a simple application where I can store and retrieve some details about some devices and the users of them, like an inventory. But when I try to display the list of devices with their owners, Automapper throws this error:
AutoMapperMappingException: Missing type map configuration or unsupported mapping.
I don't understand what I am doing wrong here. How can I deal with this?
Startup.cs
builder.Services.AddAutoMapper(typeof(MapConfig));
builder.Services.AddControllersWithViews();
var app = builder.Build();
MapConfig.cs
public class MapConfig : Profile
{
public MapConfig()
{
CreateMap<Asset, AssetVM>().ReverseMap();
CreateMap<AppUser, AppUsersVM>().ReverseMap();
}
}
Asset.Cs
public class Asset
{
public int Id { get; set; }
public string Brand { get; set; }
public string Model { get; set; }
public string? ProductNumber { get; set; }
public string? SerialNumber { get; set; }
public DateTime DateCreated { get; set; }
public DateTime DateModified { get; set; }
public bool IsAssigned { get; set; }
public string? ISN { get; set; }
public string Status { get; set; }
public bool IsInsured { get; set; }
public string Condition { get; set; }
[ForeignKey("UserId")]
public AppUser AppUser { get; set; }
public string? UserId { get; set; }
}
AssetVM
public class AssetVM
{
public int Id { get; set; }
public string Brand { get; set; }
public string Model { get; set; }
[Display(Name ="Product Number")]
public string? ProductNumber { get; set; }
[Display(Name ="Serial Number")]
public string? SerialNumber { get; set; }
[Display(Name ="Date Created")]
[DataType(DataType.Date)]
public DateTime DateCreated { get; set; }
[Display(Name = "Date Modified")]
[DataType(DataType.Date)]
public DateTime DateModified { get; set; }
[Display(Name ="Assigned")]
public bool IsAssigned { get; set; }
public string? ISN { get; set; }
[Required]
public string Status { get; set; }
[Display(Name ="Has Insurance")]
public bool IsInsured { get; set; }
[Required]
public string Condition { get; set; }
public string? UserId { get; set; }
public SelectList? AppUsersList { get; set; }
public AppUsersVM AppUsers { get; set; }
}
This is how I get and map the data that is to be displayed on the page:
public async Task<AssetVM> GetAssets()
{
var asset = await context.Assets.Include(q => q.AppUser).ToListAsync();
var model = mapper.Map<AssetVM>(asset);
return model;
}
And finally I return the result of GetAssets method to the view in my controller:
var model = await assetRepository.GetAssets();
return View(model);
Well, I found what I'm doing wrong. This is what I've done:
Since I was getting a list after querying the database in my GetAssets method, I had to change my mapping to:
var model = mapper.Map<List<AssetVM>>(asset);
And to be able to return this model, I also had to change my method declaration to:
public async Task<List<AssetVM>> GetAssets()
This changes made it work, except I didn't get the details of the user that is using that asset. And this was due to a typo in my AssetVM viewmodel.
public AppUsersVM AppUser { get; set; }
Those were all the changed I had to do. Still have a looong way to be a competent programmer so I'd be glad if you let me know if I have any flaws in my logic or any recommendations at all.

C# Overriding inherited validation

I have the following class that all of my entities inherit from:
using System.ComponentModel.DataAnnotations;
#nullable enable
namespace AutomationNavigator.Model.Core
{
public abstract class NamedEntity : Entity, INamedEntity
{
public NamedEntity() : base()
{
}
[MaxLength(100,ErrorMessage ="Name must be 100 characters or less.")]
[Required]
[MinLength(3, ErrorMessage = "Name must be at least 3 characters.")]
[RegularExpression("^[A-Za-z0-9_. ]{3,100}$")] // Alphanumeric with Underscore and Dot only
[Display(Name= "Name")]
public string? Name { get; set; }
}
}
The validation on the Name field is ok to universally apply except in a specific scenario that I just created where I need to allow special characters is name field in my app. Can I somewhow override/remove the Regex validation? The class I am trying to accomplish this for is:
namespace AutomationNavigator.Model.ProcessAssessment
{
public class ProcessFile: NamedEntity
{
[Display(Name = "OrganizationId")]
public Guid? OrganizationId { get; set; }
[ForeignKey("OrganizationId")]
[Display(Name = "Organization")]
public Organization? Organization { get; set; }
[Display(Name = "BusinessProcessId")]
public Guid? BusinessProcessId { get; set; }
[ForeignKey("BusinessProcessId")]
[Display(Name = "BusinessProcess")]
public BusinessProcess? BusinessProcess { get; set; }
[Display(Name = "ProcessDocumentId")]
public Guid? ProcessDocumentId { get; set; }
[ForeignKey("ProcessDocumentId")]
[Display(Name = "ProcessDocument")]
public ProcessDocument? ProcessDocument { get; set; }
[Display(Name = "ProcessFileStatusLookupId")]
public Guid? ProcessFileStatusLookupId { get; set; }
[ForeignKey("ProcessFileStatusLookupId")]
[Display(Name = "LookupValue")]
public LookupValue? LookupValue { get; set; }
[Display(Name = "BlobId")]
public Guid? BlobId { get; set; }
[ForeignKey("BlobId")]
[Display(Name = "Blob")]
public Blob? Blob { get; set; }
[Display(Name = "SizeInBytes")]
public double? SizeInBytes { get; set; }
[Display(Name = "Version")]
public double? Version { get; set; }
[MaxLength(500, ErrorMessage = "Description must be 500 characters or less.")]
[Display(Name = "Description")]
public string? Description { get; set; }
}
}
Virtual properties are a good way of allowing descendents to customise behaviour.
I would make the Name property virtual in the abstract class and override it in the derived specific class where you need to change the validation.
In the abstract class:
[MaxLength(100,ErrorMessage ="Name must be 100 characters or less.")]
[Required]
[MinLength(3, ErrorMessage = "Name must be at least 3 characters.")]
[RegularExpression("^[A-Za-z0-9_. ]{3,100}$")]
[Display(Name= "Name")]
public virtual string? Name { get; set; }
In the derived class:
public class ProcessFile: NamedEntity
{
public override string? Name { get; set;}
}
You can also make the base class' name directly available for the derived class and validate it. Something like:
public abstract class NamedEntity
{
protected string name;
public virtual string Name
{
get { return name; }
set
{
//validation, if any
}
}
public NamedEntity()
{
name = "";
}
}
public class ProcessFile: NamedEntity
{
public override string Name
{
get { return base.Name; }
set { base.Name = // new validation; }
}
public ProcessFile()
: base()
{
base.Name = "";
}
}
I hope it helps.
Cheers.

how to determine that my model pass all data annotations rule check or not?

I have scenario where I want to know is my model is valid or not.
here is my model
public class CallPartyModel
{
public System.Guid PartyId { get; set; }
public System.Guid FwCallMasterId { get; set; }
[Required(ErrorMessage = "Principal Party is required.")]
[Display(Name = "Principal Party")]
public System.Guid PrincipalPartyId { get; set; }
[Required(ErrorMessage = "Responsible Party is required.")]
[Display(Name = "Responsible Party")]
public System.Guid ResponsiblePartyId { get; set; }
[Display(Name = "File Type")]
public System.Guid FileTypeId { get; set; }
[Display(Name = "Agent Type")]
public Nullable<System.Guid> AgentTypeId { get; set; }
public string AgentTypeCode { get; set; }
public bool AdvancedRequired { get; set; }
public bool SeperateDARequired { get; set; }
public string PrincipalPartyName { get; set; }
public string ResponsiblePartyName { get; set; }
public string PrincipalReferenceCode { get; set; }
public string ResponsibleReferenceCode { get; set; }
public string FileTypeName { get; set; }
public string FileTypeCode { get; set; }
public string AgentTypeName { get; set; }
public bool? DAIssuedFlag { get; set; }
[Range(0, 999999999.999, ErrorMessage = "Value lies outside the 0 to 999999999.999 range")]
public decimal? AdvanceReceivedAmount { get; set; }
public System.Guid CreatedBy { get; set; }
public System.DateTime CreatedDateTime { get; set; }
public Nullable<System.Guid> ModifiedBy { get; set; }
public Nullable<System.DateTime> ModifiedDateTime { get; set; }
public bool IsDeleted { get; set; }
public Nullable<System.Guid> DeletedBy { get; set; }
public Nullable<System.DateTime> DeletedDateTime { get; set; }
//public virtual UserModel FwCore_Users { get; set; } //Created By User
//public virtual UserModel FwCore_Users1 { get; set; }//Modified By User
//public virtual UserModel FwCore_Users2 { get; set; }// Deleted by User
public bool IsDirtyCheck { get; set; }
public bool LockPrinFlag { get; set; }
public string LockPrinMsg { get; set; }
}
I have defined some rules for this ex. public decimal? AdvanceReceivedAmount { get; set; }
the range rule.
I know how to check model state when our model is bonded to view as ModelState.Isvalid()
but in my code I am working with tow diffident models, its in some wcf service, where I am getting the input as string for all properties and I can't define the data annotation rule on second model. So I have to transfer the data manually from model one to model two and in model two (CallPartyModel) I have define the data annotation rules. Now before performing any transaction in database, I have to check if the model properties's value are valid or not, I know I can do it manually but is there any method as modelState.IsValid() for this kind of scenario?
as:
CallPartyModel obj=new CallPartyModel();
obj.AdvanceReceivedAmount=88.88;
if(obj.IsValid())
{
//go
}
else
{
//Show the error according to property
}
Any suggestion or help will be appreciated
How about you check your model1 against model2 by loading the model2 with the values of Model1 and then using
Model2 m2 = new Model2();
//... load up the values into m2 from Model1
if(TryUpdateModel(m2)) //if it is ok (checks validation)
{
... your code...
}
I hope this helps.

Error with mapping entities in EF

I am trying to implement Asp.net Identity 2.0 with DB first.
I have imported my model.edmx into the project. It contains all the tables I need with the correct information and structure.
In the database there is a table called 'FSKUsers' I have edited this to contain the needed fields of the AspNetUsers which is the default table for Identity 2.0
So in my Identity DB Context I have mapped my FskUser class (which is a high level user for Identity sake)
public class IdentityDbContext : IdentityDbContext<FskUser, FskRole, int, FskUserLogin, FskUserRole, FskUserClaim>
{
public IdentityDbContext()
: base("FSK_FskNetworksEntities")
{
}
protected override void OnModelCreating(System.Data.Entity.DbModelBuilder modelBuilder)
{
base.OnModelCreating(modelBuilder);
var userEntity = modelBuilder.Entity<FskUser>();
userEntity.ToTable("FSKUsers", "dbo");
userEntity.Property(p => p.Id).HasColumnName("FSKUserId");
userEntity.Property(p => p.PasswordHash).HasColumnName("Password");
}
public static IdentityDbContext Create()
{
return new IdentityDbContext();
}
}
So basically I want to map the class FskUser to the Data Base table called FSKUser which is also contained in my .edmx model.
When I run the website I get the following error.
The entity type FskUser is not part of the model for the current context
My two POCO classes:
The one from my edmx model:
public partial class FSKUser
{
public FSKUser()
{
this.AspNetUserClaims = new HashSet<AspNetUserClaim>();
this.AspNetUserLogins = new HashSet<AspNetUserLogin>();
this.FSKDevices = new HashSet<FSKDevice>();
this.FSKEventLogs = new HashSet<FSKEventLog>();
this.FSKReports = new HashSet<FSKReport>();
this.FSKTransactions = new HashSet<FSKTransaction>();
this.FSKTriggers = new HashSet<FSKTrigger>();
this.UdlDownloads = new HashSet<UdlDownload>();
this.AspNetRoles = new HashSet<AspNetRole>();
this.FSKCompanies = new HashSet<FSKCompany>();
}
public int FSKUserId { get; set; }
public string UserName { get; set; }
public string Email { get; set; }
public bool EmailConfirmed { get; set; }
public string PhoneNumber { get; set; }
public bool PhoneNumberConfirmed { get; set; }
public string Password { get; set; }
public string SecurityStamp { get; set; }
public bool TwoFactorEnabled { get; set; }
public Nullable<System.DateTime> LockoutEndDateUtc { get; set; }
public bool LockoutEnabled { get; set; }
public int AccessFailedCount { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public byte FSKAccessLevelId { get; set; }
public string AddressStreet1 { get; set; }
public string AddressStreet2 { get; set; }
public string AddressStreet3 { get; set; }
public string AddressPostCode { get; set; }
public Nullable<int> CreatorId { get; set; }
public Nullable<System.DateTime> CreateDate { get; set; }
public string ConfirmationToken { get; set; }
public Nullable<bool> IsConfirmed { get; set; }
public Nullable<System.DateTime> LastPasswordFailureDate { get; set; }
public Nullable<int> PasswordFailuresSinceLastSuccess { get; set; }
public Nullable<System.DateTime> PasswordChangedDate { get; set; }
public string PasswordVerificationToken { get; set; }
public string PasswordVerificationTokenExpirationDate { get; set; }
public bool IsDeleted { get; set; }
public Nullable<int> CostCentreId { get; set; }
public Nullable<int> AdminPasswordResetUserId { get; set; }
public Nullable<System.DateTime> PreviousLogInDate { get; set; }
public System.Guid msrepl_tran_version { get; set; }
public virtual ICollection<AspNetUserClaim> AspNetUserClaims { get; set; }
public virtual ICollection<AspNetUserLogin> AspNetUserLogins { get; set; }
public virtual ICollection<FSKDevice> FSKDevices { get; set; }
public virtual ICollection<FSKEventLog> FSKEventLogs { get; set; }
public virtual ICollection<FSKReport> FSKReports { get; set; }
public virtual ICollection<FSKTransaction> FSKTransactions { get; set; }
public virtual ICollection<FSKTrigger> FSKTriggers { get; set; }
public virtual ICollection<UdlDownload> UdlDownloads { get; set; }
public virtual ICollection<AspNetRole> AspNetRoles { get; set; }
public virtual ICollection<FSKCompany> FSKCompanies { get; set; }
}
The one I use in my Identity Config
public class FskUser : IdentityUser<int, FskUserLogin, FskUserRole, FskUserClaim>
{
[Display(Name = "First Name")]
[Required(ErrorMessage = "First Name is Required.")]
public string FirstName { get; set; }
[Display(Name = "Last Name")]
[Required(ErrorMessage = "Last Name is Required.")]
public string LastName { get; set; }
[MaxLength(20)]
[Display(Name = "Cell Number")]
[RegularExpression(#"^\(?([0-9]{3})\)?[-. ]?([0-9]{3})[-. ]?([0-9]{4})$", ErrorMessage = "Entered phone format is not valid.")]
[StringLength(10, ErrorMessage = "The {0} must be 10 numbers long.", MinimumLength = 10)]
public override string PhoneNumber { get; set; }
[Display(Name = "Access Level")]
public byte? FSKAccessLevelId { get; set; }
[Display(Name = "Street Address 1")]
public string AddressStreet1 { get; set; }
[Display(Name = "Street Address 2")]
public string AddressStreet2 { get; set; }
[Display(Name = "Street Address 3")]
public string AddressStreet3 { get; set; }
[Display(Name = "Postal Code")]
public string AddressPostCode { get; set; }
[Display(Name = "Previous Login")]
public Nullable<DateTime> PreviousLogInDate { get; set; }
[Display(Name = "Account Confirmed")]
public Nullable<bool> IsConfirmed { get; set; }
[Display(Name = "Last Password Failier")]
public Nullable<DateTime> LastPasswordFailureDate { get; set; }
[Display(Name = "Password Last Changed")]
public Nullable<DateTime> PasswordChangedDate { get; set; }
public async Task<ClaimsIdentity> GenerateUserIdentityAsync(UserManager<FskUser, int> manager)
{
//TODO: add option for web and api (to create different auth types
// Note the authenticationType must match the one defined in CookieAuthenticationOptions.AuthenticationType
var userIdentity = await manager.CreateIdentityAsync(this, DefaultAuthenticationTypes.ApplicationCookie);
// Add custom user claims here
return userIdentity;
}
}
When you use Database first approach with edmx file OnModelCreating method is never called. You may check that with debugger.

Is it possible to inherit data annotations in C#?

Can I inherit the "password" data annotation in another class?
public class AccountCredentials : AccountEmail
{
[Required(ErrorMessage = "xxx.")]
[StringLength(30, MinimumLength = 6, ErrorMessage = "xxx")]
public string password { get; set; }
}
The other class:
public class PasswordReset : AccountCredentials
{
[Required]
public string resetToken { get; set; }
**["use the same password annotations here"]**
public string newPassword { get; set; }
}
I have to use different models due to API call's, but like to avoid having to maintain two definitions for the same field.
Thanks!
Addition: something like
[UseAnnotation[AccountCredentials.password]]
public string newPassword { get; set; }
Consider favoring composition over inheritance and using the Money Pattern.
public class AccountEmail { }
public class AccountCredentials : AccountEmail
{
public Password Password { get; set; }
}
public class PasswordReset : AccountCredentials
{
[Required]
public string ResetToken { get; set; }
public Password NewPassword { get; set; }
}
public class Password
{
[Required(ErrorMessage = "xxx.")]
[StringLength(30, MinimumLength = 6, ErrorMessage = "xxx")]
public string Value { get; set; }
public override string ToString()
{
return Value;
}
}
Perhaps it has become a golden hammer for me, but recently I have had a lot of success with this, especially when given the choice between creating a base class or instead taking that shared behavior and encapsulating it in an object. Inheritance can get out of control rather quickly.
In the base class, you can make it virtual property, and change it override in the derived class. However, it would not inherit attribute, we do a tricky here :
public class AccountCredentials : AccountEmail
{
[Required(ErrorMessage = "xxx.")]
[StringLength(30, MinimumLength = 6, ErrorMessage = "xxx")]
public virtual string password { get; set; }
}
public class PasswordReset : AccountCredentials
{
[Required]
public string resetToken { get; set; }
public override string password { get; set; }
}

Categories