Is there any data annotation for the allowed values in ASP.NET MVC Core? Since there is no enum in SQL server I am not able to migrate my class with enum field in it to the database. I want to give possible/allowed values to the field in the class. Is there any way to do this?
public class Employee
{
[Key]
public int ID { get; set; }
[Required]
public string Name { get; set; }
[Required]
public string Status { get; set; }
}
I want to provide Active and Inactive as the only possible values to the Status field.
you can also do this using a regular expression as below:
[Required]
[RegularExpression("Active|Inactive", ErrorMessage = "Invalid Status")]
public string Status { get; set; }
More details can by found here
As #ps2goat mentioned, you could use a check constraint on your database. However, for the model coming into the API you probably still want to provide validation there. Ideally you will do what you can, within reason, to prevent bad data from ever getting to the data layer. You don't mention whether you're using an n-tier architecture, or if your controller is directly referencing the data model. Either way, I believe this custom attribute can be used either at the API layer or on the entity model.
This is a good answer that explains how to create a custom validation attribute. It's an old answer, but it still applies to .Net Core. And here is an answer for a custom validation attribute in .Net Core. It basically looks like this:
public class EmployeeStatusAttribute : ValidationAttribute
{
private string[] _allowedValues;
public EmployeeStatusAttribute(string[] allowedValues)
{
_allowedValues = allowedValues;
}
protected override ValidationResult IsValid(object value, ValidationContext validationContext)
{
var employee = value as Employee;
if (_allowedValues.Contains(employee.Status))
{
return ValidationResult.Success;
}
return new ValidationResult(`{employee.Status} is not a valid status`);
}
}
Then in your model:
public class Employee
{
...
[EmployeeStatus("Active", "Inactive")]
public string Status { get; set; }
...
}
Related
I am working on a basic group chat system, for which I created these classes:
public class Role
{
public Guid Id { get; set; };
public string Username { get; set; }
}
public class Message
{
public Guid Id { get; set; };
public Role Author { get; set; }
public Conversation Conversation { get; set; }
public DateTime Date { get; set; }
public string Text { get; set; }
}
public class Conversation
{
public Guid Id { get; set; };
public IList<ConversationParticipant> ConversationParticipants { get; set; };
public IList<Message> Messages { get; set; };
}
public class ConversationParticipant
{
public Conversation Conversation { get; set; }
public Role Role { get; set; }
}
We are using EF Core 3.1 Code-First with migrations.
I am looking for a way to make Message.Author a required property, which should lead to a column in table Message that is created as AuthorId NOT NULL.
I tried:
public static void Map(this EntityTypeBuilder<Message> builder)
{
builder.HasOne(m => m.Author);
}
As this is applied using Add-Migration and Update-Database, the database column AuthorId is created, but with NULLs allowed.
There does not seem to be a method IsRequired() that I can add after HasOne().
I also tried:
public static void Map(this EntityTypeBuilder<Message> builder)
{
builder.Property(m => m.Author).IsRequired();
}
but that fails saying
The property 'Message.Author' is of type 'Role' which is not supported by current database provider. Either change the property CLR type or ignore the property using the '[NotMapped]' attribute or by using 'EntityTypeBuilder.Ignore' in 'OnModelCreating'.
Doing .HasOne(...) followed by .Property(...).IsRequired() also does not work:
'Author' cannot be used as a property on entity type 'Message' because it is configured as a navigation.
I managed to make Message.Conversation required through this:
public static void Map(this EntityTypeBuilder<Conversation> builder)
{
builder.HasMany(c => c.Messages) // A conversation can have many messages
.WithOne(e => e.Conversation) // Each message belongs to at most 1 conversation
.IsRequired(); // A message always has a conversation
}
However I'd rather not make Role aware of Messages, as I will never want to retrieve Messages directly from a Role (this will happen through Conversations and Participants).
My ultimate question is: Is there a way to make Message.Author required (NOT NULL), without linking Message and Role together in a full 1-to-many relationship with a Messages property in Role?
What about adding Role's foreign key to Message and then requiring that property to not be null? Something like:
// MessageConfiguration.cs
builder.Property(b => b.RoleId).IsRequired()
While the answer by #Ben Sampica was helpful and got me where I needed to be, the comments by #Ivan Stoev provided details and clarity that made me think that a more comprehensive answer would be useful.
There are multiple ways to make a foreign key column required (NOT NULL) in the generated table.
The simplest is to put [Required] on the navigation property:
public class Message
{
// ...
[Required] public Role Author { get; set; }
// ...
}
This will cause EF to create a shadow property AuthorId of type Guid because Message.Author is a Role and Role.Id is of type Guid. This leads to UNIQUEIDENTIFIER NOT NULL in case of SQL Server.
If you omit [Required] then EF will use Guid?, which leads to UNIQUEIDENTIFIER NULL, unless you apply one of the other options.
You can use an explicit Id property with a type that can't be null:
public class Message
{
// ...
public Guid AuthorId { get; set; }
public Role Author { get; set; }
// ...
}
Note (i) - This only works if you follow EF Core shadow property naming rules, which in this case means you must name the Id property nameof(Author) + nameof(Role.Id) == AuthorId.
Note (ii) - This will break if one day you decide to rename Author or Role.Id but forget to rename AuthorId accordingly.
If you can't or don't want to change the Model class, then you can tell EF Core that it needs to treat the shadow property as required:
builder.Property("AuthorId").IsRequired();
The same Notes apply as listed at 2, with the addition that you could now use nameof() to reduce the effort and the risks.
In the end I decided to use the [Required] approach, because
It is simple and descriptive,
No effort needed to think of which shadow property name to use,
No risk of breaking the shadow property name later on.
This may apply sometimes, not always:
Input forms may use the Model class attribute to check if a property is required. However it may be a better approach to build your forms around DTO classes, and then an attribute on an EF Model class may provide no worth for your forms.
In a webapi project we have a model like:
public class Person
{
public string Name { get; set; }
public Guid? Id { get; set; }
}
We have configured validation of parameters and we do some checks using ActionFilterAttribute:
public class ModelActionFilter : ActionFilterAttribute
{
public override void OnActionExecuting(HttpActionContext actionContext)
{
(...)
var modelState = actionContext.ModelState;
if (modelState.IsValid == false)
{
actionContext.Response = actionContext.Request.CreateErrorResponse(HttpStatusCode.BadRequest, modelState);
}
base.OnActionExecuting(actionContext);
}
}
The problem is that, doing a call like: https://localhost/person?Id=null&name='John', creates an error like:
The value 'null' is not valid for Id.
We have made the Id field nullable in the first place because we want to allow calls like the one above. Still, the validator complains. Is there any clean way to exclude this error?
I could go and iterate through the list of errors and exclude this one, but it feels really wrong.
You could define a model specific to the purpose. For example:
public class PersonSearchParameters
{
public string Name { get; set; }
public string Id { get; set; }
}
Then allow your method to handle parsing Id in the way you'd prefer to handle it.
I really think it'll be easier, though, if you just say that id should be omitted from your results if you want it to be null.
As a follow on from my previous question (MVC abstract ViewModel, retain Validation Attributes (dynamically)) I thought I'd ask the question in an alternate version.
So, let's consider the same situation, where I have a core ViewModel:
public class SampleViewModel {
[Required]
public string Property1 { get; set; }
[Required]
[EmailAddress]
public string Property2 { get; set; }
public IList<AnotherModel> Items { get; set; }
}
And another model:
public AnotherModel {
public string Value { get; set; }
}
And then within a controller, I perform the following:
var model = new SampleViewModel();
var fields = new List<AnotherModel>() {
new AnotherModel() { Value = model.Property1 },
new AnotherModel() { Value = model.Property2 },
};
So, my question is, how can I get the AnotherModel models to respond to the properties that are passed to their respective Value property.
In the sample above, the first AnotherModel will be Required, and the second will be Required, and an EmailAddress.
How is this possible?
Thank you
Update
For the purpose of this, lets say that each of those AnotherModel objects is represented by a form field. When the form is posted back, I use a custom model binder to obtain the Value from the AnotherModel and place it back into the source property (so Property1). My model is reconstructed correctly, and ModelState.IsValid is working. So, I have server-side validation of my SampleViewModel on post-back. Can this be somehow passed to the client to validate for me, based on the model's validation attributes?
Thanks
I do not want do bind the Id property on my CustomerViewModel so I added a [BindNever] attribute but it is not working. What could be the solution?
I have the following:
CustomerController.cs
// PUT api/customers/5
[HttpPut("{id}")]
public async Task<IActionResult> Put([FromUri] int id, [FromBody]CustomerViewModel customer)
{
//Implementation
}
CustomerViewModel
public class CustomerViewModel
{
[BindNever]
public int Id { get; set; }
public string LastName { get; set; }
public string FirstName { get; set; }
public string Email { get; set; }
}
If I input the following json . The id property still gets binded
{
"id": 100,
"lastName": "Bruce",
"firstName": "Wayne",
"email": "bruce#gothamcity.com"
}
This Blog post is an interesting read and concludes that the [FromBody] annotation "overrides" the BindBehaviourAttribute (BindNever is a simple specialization). The model is populated by all data available from the body (your JSON data in this case).
I do not consider this as intuitive, and the issue has a nice statement about this:
[BindRequired] customizes the MVC model binding system . That's its
purpose and it's working as designed.
[FromBody] switches the affected property or parameter into the
different world of input formatting. Each input formatter (e.g.
Json.NET and a small MVC-specific wrapper) can be considered a
separate system with its own customization. The model binding system
has no knowledge the details of JSON (or any other) deserialization.
Lesson learned: BindNever does not work in this scenario.
What are alternatives ?
Solution 1: Writing some custom model binding code. I have not done it myself, but What is the correct way to create custom model binders in MVC6? may help.
Solution 2: Rather pragmatic one
Perhaps this simple (but not very nice) workaround helps you out:
[HttpPut("{id}")]
public async Task<IActionResult> Put([FromUri] int id, [FromBody]CustomerViewModel customer)
{
customer.Id = 0;
//Implementation
}
also you could do this
public class CustomerViewModel
{
public int Id { get; private set; }
public string LastName { get; set; }
public string FirstName { get; set; }
public string Email { get; set; }
}
I add a note.
Now it's officially explained by Microsoft.
https://learn.microsoft.com/ja-jp/aspnet/core/mvc/models/model-binding?view=aspnetcore-6.0#attributes-for-complex-type-targets
https://learn.microsoft.com/ja-jp/aspnet/core/mvc/models/model-binding?view=aspnetcore-6.0#input-formatters
https://learn.microsoft.com/ja-jp/aspnet/core/mvc/models/model-binding?view=aspnetcore-6.0#frombody-attribute
In summary,
If we use the “FromBody attribute (including defaults such as HttpPost attribute)”, it depends on the input formatter and the BindNever attribute etc. will not work.
Instead, we can do so by specifying the attribute that corresponds to the input formatter.
For example, for the default json
It can be ignored using "System.Text.Json.Serialization.JsonIgnoreAttribute".
Try NotMapped attribute.
Body must be at least 30 characters; you entered 24.
I'm using ASP.NET MVC 3 and Entity Framework 4.1 Code First.
Let's say I have a User entity :
public class User
{
public int Id { get; set; }
public string Name { get; set; }
public string Email { get; set; }
public string Password { get; set; }
}
When editing it in my UserController I want to add a PasswordConfirmation field and verify that PasswordConfirmation == Password
1. By composition
My first try was :
public class EditUserModel
{
[Required]
public User User { get; set; }
[Compare("User.Password", ErrorMessage = "Passwords don't match.")]
public string PasswordConfirmation { get; set; }
}
In this case the client side validation works but (Edit: client side validation working was a coincidence.) doesn't work and the server side validation fails with the following message : Could not find a property named User.Password
Edit: I think the best solution, in this case, would be to create a custom CompareAttribute
Implementing IValidatableObject
public class EditUserModel : IValidatableObject
{
[Required]
public User User { get; set; }
public string PasswordConfirmation { get; set; }
public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
{
if(this.PasswordConfirmation != this.User.Password)
return new[] { new ValidationResult("Passwords don't match", new[] { "PasswordConfirmation " }) };
return new ValidationResult[0];
}
}
In this case the server side validation works but the client side validation doesn't work anymore. Implementing IClientValidatable seems a bit too complicated and I prefer not having client side validation in this case.
2. By inheritance
public class EditUserModel : User
{
[Compare("Password", ErrorMessage = "Passwords don't match.")]
public string PasswordConfirmation { get; set; }
}
When trying to directly save EditUserModel using EF it doesn't work, I get some some error message about the EditUserModel metadata so I'm using AutoMapper to convert from User to EditUserModel and backwards.
This solution works but it more complex because I have to convert from the model to the view model and backwards.
3. By duplication
(Suggested by Malte Clasen)
The view model would have all the properties of the model plus additional ones. AutoMapper can be used to convert from one to another.
public class EditUserModel {
public string Name { get; set; }
public string Email { get; set; }
public string Password { get; set; }
[Compare("Password", ErrorMessage = "Passwords don't match.")]
public string ConfirmPassword { get; set; }
}
This is the solution I like the least because of code duplication (DRY)
Questions
What are the pros and cons of inheritance, composition and duplication in this case ?
Is there a simple way to have both client side and server side validation without having to convert the model to the view model and backwards ?
Having struggled with this question before, I have in various instances gone with all three. In general, most of the opinions I've seen favor duplication in an MVC project, with a ViewModel constructed specifically for each view. In this manner the convention you'd use is something like UserDetailsViewModel and UserCreateViewModel. As you said, at that point AutoMapper or some other auto mapping tool would be used to convert from your domain objects to these flat ViewModels.
While I, too, don't like repeating code, I also don't like polluting my domain objects with validation or other view-specific attributes. Another advantage, though admittedly one almost nobody would ever have to contend with (regardless of what all the pros say), is that you can manipulate your domain objects in some ways without necessarily manipulating your ViewModels. I mention that because it's commonly cited, not because it carries much weight for me.
Lastly, using a truly flat ViewModel makes for cleaner markup. When I've used composition, I've often made errors creating HTML elements with names that are something like User.Address.Street. A flat ViewModel reduces at least my likelihood of doing that (I know, I could always use HtmlHelper routines to create elements, but that's not always feasible).
My recent projects have also pretty much required separate ViewModels these days anyway. They've all been NHibernate-based, and the use of proxies on NHibernate objects makes it not possible to use them directly for views.
Update - here's a good article I've referred to in the past: http://geekswithblogs.net/michelotti/archive/2009/10/25/asp.net-mvc-view-model-patterns.aspx
You could also consider independent classes for domain and view models, in this case for example
public class EditUserModel {
public string Name { get; set; }
public string Email { get; set; }
public string Password { get; set; }
public string ConfirmPassword { get; set; }
}
if the Id is stored in the url. If you want to avoid the manual copy between the instances of User and EditorUserModel, AutoMapper can help you. This way you can easily decouple the password string in your view model from the password hash in your domain model.
I have trying to work this out and I found a solution that does not involve duplicating code. It's kind of workaround but, in my opinion, it's better than the other proposed solutions.
You have the User Model with all the validation:
public class UserModel
{
[Required]
public int Id { get; set; }
[Required]
public string Name { get; set; }
public string Email { get; set; }
public string Password { get; set; }
}
You compose the previous model with a new model
public class EditUserModel
{
public UserModel User { get; set; }
[Required]
public string PasswordConfirmation { get; set; }
}
The trick is in the action, you could receive more than one model:
[HtttPost]
public ActionResult UpdateInformation(UserModel user, EditUserModel editUserModel) {
if (ModelState.IsValid) {
// copy the inner model to the outer model, workaround here:
editUserModel.User = user
// do whatever you want with editUserModel, it has all the needed information
}
}
In this way the validation works as expected.
Hope this helps.
I don't use Entity Models too much, I prefer LINQ - SQL models so this may be incorrect:
Why not use a meta-data class which is applied to the Entity?
With LINQ - SQL the metadata assigned is taken into consideration for both client-side as well as server-side validation.
From what I understand application of a [MetaDataType] attribute is similar to inheritance only it works without implementing a new class (model) for alterations to the basic entity.
Also, another option you might want to try is creating a custom attribute - I did this once for a similar purpose. Essentially a flag which indicated the persistence of a member.
So i would have an entity defined as follows:
public class User
{
public int Id { get; set; }
public string Name { get; set; }
public string Email { get; set; }
public string Password { get; set; }
[DoNotPersist]
public string ConfirmPassword {get; set;}
}
Also, I don't know what you are doing to store data but I had hooked an override into the OnInserting , OnEditing, OnDeleting functions for my DataContext which basically removed any members having my custom attribute.
I like this method simple because we use a lot of temporary, rather algorithmic data for each model (building good UI's for Business Intelligence) which is not saved in the database but is used everywhere inside model functions, controllers, etc - so we use dependency injection in all model repositories and controllers and so we have all these extra data points for each table to play with.
Hope that helps!
PS:- Composition vs Inheritance - it really depends on the target user of the application. If it is for an intranet app where security is less of an issue and the user / browser environment is controlled then just use client side validation, ie: composition.
I would favour composition over inheritance.
In case of your user password it looks like you're actually storing the password in Users table in clear text, which is VERY, VERY BAD.
You should store only a salted hash, and your EditUserModel should have two string properties for password and password confirmation, which are NOT the fields in your table.