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?).
Related
I am facing an issue when validating a form on ASP.
I have 2 models Person and Address. Each of them have their specific forms to add entries using EF Core.
In Person form I need hidden inputs to keep track of potential Address related data (It is perfectly fine there is no Address). To that matter I use hidden input fields but because the Address model have validation annotations, the generated markup reflects it which puts ModelState.IsValid to false upon validation unless, of course, I am editing a person with valid Address data.
I also tried to set Person.Address to null in the specific situation where it should be just before actually checking its value and it does not work. Probably it is already too late for ModelState to update by then.
if (Person.Address is not null && Person.Address.Id == 0)
Person.Address = null;
if (ModelState.IsValid)
// Further code to save data in DB
else
// Code to redisplay the page
I would like to know if there is a way to tell ASP not to validate/ignore specific input fields but still allow me to keep a piece of data?
Thank you very much.
Edit:
As per demand in the comments I add the classes with annotation
The Person
public class Person
{
[Key]
public int Id { get; set; }
[Required]
public string FirstName { get; set; }
[Required]
public string LastName { get; set; }
[Range(0, 150)]
public int Age { get; set; }
public Address Address { get; set; }
}
The address class
public class Address
{
[Key]
public int Id { get; set; }
[Required, MaxLength(50)]
public string Street { get; set; }
[Required, MaxLength(50)]
public string City { get; set; }
[Required, MaxLength(50)]
public string Country { get; set; }
}
OK Problem solved. I found some interesting doc.
Thanks for the propositions.
You can skip data annotations on those fields which you don't want to validate.
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
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 new to full stack software development, and I have an assignment to create a simple full stack web app in .NET Core, Entity Framework Core (when it comes to the back-end part), which would store some employee data. Now, let's say I have an Employee entity. We also need to implement the Employee's position in some way (an employee can have the position of a back-end developer, front-end developer, project manager etc.). That's why I have also created this EmployeePosition class, so that there is an EmployeePosition property in Employee. I also have other similar status enitities like the EmployeePosition in the app.
EmployeePosition would then be seeded to a separate table in the database, and thus it can be applicable to any company that "would use" this app (just use different seed data). I will use a legacy database for seeding.
Now it seems that this would work, but it also seems a bit too crude for me, because whenever I would need to do an operation with the status in the repository, I would have the use the magic Id number of the status, or hardcode the status Name property somewhere in a method (if I don't have a smarter workaround for the given operation), for instance "Switch(Position.Name) case "front-end": do stuff" etc.
Could I maybe get a suggestion or direction on how to implement this better, am I on a good track here?
Would it be better to actually use enums as data types inside of EmployeePosition, any suggestions on how to implement that? Considering that I have to use the legacy database for seeding, I would have to somehow create my enums out of the legacy file.
public class Employee
{
[Key]
public int Id { get; set; }
[Required]
public string FirstName { get; set; }
[Required]
public string LastName { get; set; }
[Required]
public string Image { get; set; }
[Required]
public string Email { get; set; }
[Required]
public string Phone { get; set; }
[Required]
public EmployeePosition Position { get; set; }
public class EmployeePosition
{
[Key]
public int Id { get; set; }
[Required]
public string Name { get; set; }
}
What you can do is create an Enum for employee positions.
public enum EmployeePosition
{
Backend = 0,
Frontend = 1,
DBA = 2,
}
And your employee entity
public class Employee
{
[Key]
public int Id { get; set; }
[Required]
public string FirstName { get; set; }
[Required]
public string LastName { get; set; }
[Required]
public string Image { get; set; }
[Required]
public string Email { get; set; }
[Required]
public string Phone { get; set; }
[Required]
public EmployeePosition Position { get; set; }
}
Then you can use
If (Employee.Position == EmployeePosition.Backend)
{
// your logic.
}
You have conflicting requirements unfortunately. You say that your program is "status-agnostic":
EmployeePosition would then be seeded to a separate table in the database, and thus it can be applicable to any company that "would use" this app (just use different seed data).
And yet, it's really not:
Because whenever I would need to do an operation with the status in the repository, I would have the use the magic Id number of the status, or hardcode the status Name property somewhere in a method (if I don't have a smarter workaround for the given operation), for instance "Switch(Position.Name) case "front-end": do stuff" etc.
So one of those requirements has to "win". Either your code knows what the different statuses are (and so different seed data wouldn't work) or it doesn't.
If the first requirement is more important:
Keep your code as it is, you have a perfectly reasonable model for N number of statuses where they aren't known ahead of time, nor is any logic specific to a given entry
If the second requirement is more important:
Switch to an enum. You don't want magic numbers or strings floating around in your code. As you mention, you'll need to map each existing data row into one of the predefined enum members.
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.