How is Modelstate.IsValid triggered?

Hello! I am reading this tutorial on how DTO's can be implemented with API's: https://dev.to/moe23/net-6-automapper-data-transfer-objects-dtos-49e The process in this tutorial seems normal and you can easily follow along. There are only 2 things I have my questions about: 1. The Driver class in this tutorial has no DataAnnotations (see first codeblock). How come the Modelstate.IsValid can be triggered in codeblock 2?
namespace SampleMapper.Models;

public class Driver
{
public Guid Id { get; set; }
public string FirstName { get; set; } = "";
public string LastName { get; set; } = "";
public int DriverNumber { get; set; }
public DateTime DateAdded { get; set; }
public DateTime DateUpdated { get; set; }
public int Status { get; set; }
public int WorldChampionships { get; set; }
}
namespace SampleMapper.Models;

public class Driver
{
public Guid Id { get; set; }
public string FirstName { get; set; } = "";
public string LastName { get; set; } = "";
public int DriverNumber { get; set; }
public DateTime DateAdded { get; set; }
public DateTime DateUpdated { get; set; }
public int Status { get; set; }
public int WorldChampionships { get; set; }
}
2. How does Modelstate.IsValid get triggered when a Dto is passed but it gets mapped to an entity?
[HttpPost]
public IActionResult CreateDriver(DriverCreationDto data)
{
var _driver = _mapper.Map<Driver>(data);

if(ModelState.IsValid)
{
drivers.Add(_driver);

return CreatedAtAction("GetDriver", new {_driver.Id}, data);
}

return new JsonResult("Something went wrong") {StatusCode = 500};
}
[HttpPost]
public IActionResult CreateDriver(DriverCreationDto data)
{
var _driver = _mapper.Map<Driver>(data);

if(ModelState.IsValid)
{
drivers.Add(_driver);

return CreatedAtAction("GetDriver", new {_driver.Id}, data);
}

return new JsonResult("Something went wrong") {StatusCode = 500};
}
DEV Community
.NET 6 - AutoMapper & Data Transfer Objects (DTOs) 🗺
Intro In this article we will be exploring AutoMapper and Data Transfer Objects (DTOs) in...
39 Replies
Anton
Anton•5mo ago
If it can't bind json to that object. Like if it can't parse a string as a datetime. Or if the json is invalid in some way too, I think. Like if you pass tru instead of true.
electronic heartbreak.
electronic heartbreak.OP•5mo ago
Would not the _mapper function then crash?
Anton
Anton•5mo ago
No the parameter will have the defaults for those properties then But that cab only happen if you turn off the filter that shortcircuits this in MVC generally, it would return a response automatically at that point Or maybe it will just be null? not sure the mapper has nothing to do with ModelState
electronic heartbreak.
electronic heartbreak.OP•5mo ago
I have a little hard time to understand this. thats correct
Anton
Anton•5mo ago
well just try passing some garbage json with the default mvc settings and see what error you get it won't even get to your code
electronic heartbreak.
electronic heartbreak.OP•5mo ago
oh like that.
Anton
Anton•5mo ago
But it will ignore extra fields, I'm pretty sure and if you don't provide a value for a property, it will initialize it to null
electronic heartbreak.
electronic heartbreak.OP•5mo ago
if we check the Driver model for example in the code above. Lets say the driver number should be between 1 and 5 and the DTO contains 0? then it should fail
Anton
Anton•5mo ago
no it won't handle that automatically unless you do data annotations and enable them, I think they aren't on by default
electronic heartbreak.
electronic heartbreak.OP•5mo ago
yes data annotations should be added. But you should not add data annotations on DTO's
Anton
Anton•5mo ago
Well then you won't be using MVC's system for validation which isn't good in the first place, to be fair data annotations are pretty primitive
electronic heartbreak.
electronic heartbreak.OP•5mo ago
Since the DTO comes in at the controller. you would 'normally' validate the object that comes in.
Anton
Anton•5mo ago
well one thing for certain
electronic heartbreak.
electronic heartbreak.OP•5mo ago
i do say that adding basic validation, like required or min/max length would be OK.
Anton
Anton•5mo ago
mapping typically never does any validation
electronic heartbreak.
electronic heartbreak.OP•5mo ago
A DTO can be invalid. it just maps
Anton
Anton•5mo ago
One thing I learned when doing backbends for more than a year is that there's no great solution for anything in these frameworks. There's always a flaw in any tech you're going to use Using controllers means a lot of code duolication
electronic heartbreak.
electronic heartbreak.OP•5mo ago
oh yeah thats for sure. I am currently at my first ever job and making choices is the hardest part of it 😉
Anton
Anton•5mo ago
Using mediator is code duplication + boilerplate + indirectness Using validation in MVC means no async validation
electronic heartbreak.
electronic heartbreak.OP•5mo ago
Cant i do the following? 1. Add basic validation like required,min/max length to the DTO 2. map the DTO to the entity 3. Perform more advanced validation to the Entity 4. By errors, return an error and if correct perform a save to the database
Anton
Anton•5mo ago
FluentValidation doesn't have a good foundation and is really hard to extend I think you should only check for nulls and for that enum members match for dtos Otherwise you're going to duplicate logic
electronic heartbreak.
electronic heartbreak.OP•5mo ago
that enum one was just an example, but i get that it might belong to the DTO
Anton
Anton•5mo ago
Yes, it doesn't validate enum members automatically, yiu heard that right If you pass it a 5 and theres no 5 in the enum, it won't comlain You don't have to map it to an entity necessarily either It's easier that way, sure for crud but for stuff that isn't crud, generating sql is often just easier One great thing about EF Core is that it keeps around the db model With table names and mappings from properties to columns That thing's great for query generation
electronic heartbreak.
electronic heartbreak.OP•5mo ago
Well, I need to use DTO/Entitities since my Entity contains properties i dont want to expose to a client. A DTO is excellent in this case.
Anton
Anton•5mo ago
No you should use dtos always for sure That's not even an argument worth having
electronic heartbreak.
electronic heartbreak.OP•5mo ago
Okay good haha 😄
Anton
Anton•5mo ago
My advice is that db entities must correspond to the db tables as close as possible Don't be tempted to add ignored fields that some service finds useful If you have to do that, it means you need another domain model
electronic heartbreak.
electronic heartbreak.OP•5mo ago
When Mr. chatgpt generates an example I see it do the following: 1. The DTO has basic validation 2. The entity constructor has complex validation 3. An exception gets thrown when the complex validation fails. Yes i have that, definitely dont worry about that part :). I am just struggling with the validation part between the DTO and Entity.
Anton
Anton•5mo ago
Nah that's dumb imo It makes sense conceptually to make sure your objects are always valid and stuff
electronic heartbreak.
electronic heartbreak.OP•5mo ago
the domain objects should be valid when theyre created or when theyre ready to be stored in a database.
Anton
Anton•5mo ago
But you don't want that to actually happen, or have to happen, automatically Then also you're forced to do excaptions And can't collect errors easily just don't validate separately when required
electronic heartbreak.
electronic heartbreak.OP•5mo ago
When storing stuff in the DB, you want the data to be correct (i mean thats a fact) during the process from receiving the data to storing it, the data should be validated.
Anton
Anton•5mo ago
It's not possible to validate objects individually in the context of a database Especially in the constructor You're going to have to make other queries to properly validate stuff likely And you can't "just" forget that. It's like forgetting to open a transaction. Or create a query string and forget to run it. imo you need to be able to control that manually Also, basic entity validation can already be achieved from your database model I have never seen anyone do this for some reason, but that's how you should ultimately do it
electronic heartbreak.
electronic heartbreak.OP•5mo ago
I use mongo so there is no validation :kekw:
Anton
Anton•5mo ago
No there is You do specify max length and stuff for fields when you configure the db with ef core You can validate according to that info Which is ultimately the only correct way You don't have to duplicate any configuration if EF Core is the source of truth, the validation should reference tgat
electronic heartbreak.
electronic heartbreak.OP•5mo ago
Mongo has no integration with EF.
Anton
Anton•5mo ago
I've heard it does now not sure how good it is
electronic heartbreak.
electronic heartbreak.OP•5mo ago
yeah that package is still in its baby phase. cant use that in production
Anton
Anton•5mo ago
I'd use it even if it doesn't support queries just for the sake of the model
Want results from more Discord servers?
Add your server