I have a Details Model that is used in 2 different pages.
public class Details
{
public string FirstName { get; set; }
public string LastName { get; set; }
public string City { get; set; }
public string Country { get; set; }
public string Nationality { get; set; }
}
When saved in the 1st Page, I want every property of this model to be required, however when saved in the 2nd Page, I want every property to be optional.
Is there a way to make this validation conditional depending on the page I use it?
I'm assuming details model is a base class for these two separate views. You should make it abstract and derive from it (unless you do need to use it somewhere) or use automapper to map details model into details-1 and details-2 with the required validation attributes
Related
I have a model, that needs an ID that contains the date that its made, and if there are more than one made that day, they need to have a number attached to it like so:
15122019
16122019-1
16122019-2
17122019
something like this, and it would need to be made automatically, no input from the user..
is this possible?
this is how my model looks right now:
public class RaidRequest
{
public int Id { get; set; }
[Required]
public Permissions Access { get; set; }
[Required]
public Group UserOrAdmin { get; set; }
[Required]
public string Department { get; set; }
[Required]
public string NameSurname { get; set; }
[Required]
public string Reason { get; set; }
[Required]
public string UNCPath { get; set; }
}
How would this be possible?
Yes, It's possible. However to have such formatting 16122019-1 you need string column. Such logic should be implemented on the Bussiness layer
Also, you have to take into account concurrent inserts, if the system is highly loaded, to have correct increment value
Code improvements:
Your request model should not have fields which are not used (like Id). It's better to have several DTO for each level: API, Business Logic, Database.
I am creating some view models for my ASP MVC web app.
I created "code first" models for database. Is it a good way to derive view models from database models?
Example database model:
public class Project
{
[Key]
public int Id { get; set; }
public int? CustomerId { get; set; }
public int TypeId { get; set; }
public string Number { get; set; }
public string Name { get; set; }
}
View model:
public class ViewModelProject : Project
{
[NotMapped]
public DateTime? Start { get; set; }
[NotMapped]
public DateTime? End { get; set; }
[NotMapped]
public string Manager { get; set; }
}
Is this the right way or is it completely false?
EDIT (subquestion):
I have some very simple database models like ProjectType, which only contains i.e. two properties. Should I also fragment those models in model view or can I make it that way:
Simple database model:
public class ProjectType
{
[Key]
public int Id { get; set; }
public string Name { get; set; }
public int? Code { get; set; }
}
Can I use it like so:
public class ProjectVM
{
public string Name { get; set; }
public int Number { get; set; }
public ProjectType Type { get; set; }
}
Or does it have to be fragmented like so:
public class ProjectVM
{
public string Name { get; set; }
public int Number { get; set; }
public string Type { get; set; }
public int TypeCode { get; set; }
}
I would not recommend doing it this way. I (and many others) have tried it and it doesn't work well. You will inadvertedly run into troubles, since an MVC model has to be tailored to the view and what you get from the DB rarely fits. Sure, you can hammer it into place, but the code quickly gets messy and store-related and UI code starts to mangle together. This even shows in your example, since you have to put the NotMappedAttribute (which is related to data storage), to ViewModelProject (a class at UI level).
There are many other examples to show this problem, but an especially good one I find when you want to serialize a model object to JSON and send it to a JavaScript client. The JSON serializer takes the values of all public properties and adds them to the JSON. If you want to exclude a property, you have to mark it with a ScriptIgnoreAttribute, which you would also have to apply to the base class, which breaks separation between UI and store-related code.
The better way to go is to keep the staorage model and the MVC model separated and to map the data from one to the other (there are already pre-existing frameworks that help you with that, such as Automapper). This comes with additional advantages, for example better testability, since you are now not dependent on a specific data store to create model instances.
For example, I have a EF6 model like this:
class User
{
public int Id { get; set; }
public string Email { get; set; }
public string Name { get; set; }
public virtual ICollection<ProfileProperty> Properties { get; set; }
public virtual ICollection<Book> Books { get; set; }
}
class Book
{
public int Id { get; set }
public int Name { get; set }
public DateTime CreationDate { get; set }
public long Size { get; set }
public string ContentPath { get; set }
}
And now I want to create a WebAPI that allows to:
Create a new user
Update user's name
Modify the list of user's books
However, here are a few tricks to it which don't let me use tutorials right off:
Some fields are either irrelevant or confidential and must not be exposed via WebAPI, for example: User.Id, User.Properties, and nested User.Books[x].ContentPath.
Only a small subset of fields is editable (in the example, User.Name).
Only a small subset of operations (CRUD) is available, therefore it's not a REST service.
The first thing that comes to mind is create extra classes for each exposed model. However, maintaining them and writing code that converts data from database models to those WebAPI-friendly classes and back is too bothersome. Is there a more simple and automated way?
The ideal approach would be one which requires writing as little redundant code as possible. Maybe there is a set of attributes to mark fields with?
You're right in thinking you should create more classes. For each exposed action (change name, create user, etc...) you should create a ViewModel that exposes only the fields you need.
public class ChangeUserNameViewModel
{
public int UserId { get; set; }
public string NewName { get; set; }
}
It's easy to convert your view model to your domain model and back again using something like AutoMapper.
Let's say I have a following ViewModel :
public class PersonViewModel
{
[Required]
public String Email { get; set; }
[Required]
public String FirstName { get; set; }
[Required]
public String LastName { get; set; }
}
This is a ViewModel not a original Entity, I use this model in two places, in the first one I want to validate all fields, but in another one I want to exclude Email field from model validation. Is there anyway to specify to exclude field(s) from validation?
You can use
ModelState.Remove("Email");
to remove entries in model state, that are related to hidden fields.
The best solution is to divide view model into two:
public class PersonViewModel
{
[Required]
public String FirstName { get; set; }
[Required]
public String LastName { get; set; }
}
public class PersonWithEmailViewModel : PersonViewModel
{
[Required]
public String Email { get; set; }
}
An ugly solution:
ModelState.Remove("Email");
Recommended solution:
Create another ViewModel. A VM is supposed to represent your view, so if your view has no Email field, make a suitable VM for it.
I have a set of contact infos that I will be displaying in an ASP.NET MVC page
They will either have an email address or information to contact
should I have this setup
public class Contact
{
public int ID { get; set; }
public string Name { get; set; }
public string Email { get; set; }
public string Explanation { get; set; }
}
where email address is shown when explanation is null
or
public class Contact
{
public int ID { get; set; }
public string Name { get; set; }
public string DisplayInfo { get; set; }
public int DisplayInfoType { get; set; }
}
where the display info type determines how I will display the info.
First approach: it's more expressive!
The domain model is more expressive in the first example; it speaks for itself what the data means.
That you need to have one of the two filled is a business rule which you don't need to express in the properties of your entities.
DisplayInfo or for that matter any similar display logic should be incorporated in the Views. The business logic is not responsible for what part of the domain has to be shown to the user on the view. This should be taken care at the view-level.
The first setup is better. It expresses what the fields do more effectively. It delays the execution of UI logic until the appropriate layer.
Also note that your Email may be empty as well as null. Additionally, you may get more use out of a field name such as ContactInstructions instead of Explanation (explanation of what?).