Heads up! To view this whole video, sign in with your Courses account or enroll in your free 7-day trial. Sign In Enroll
Preview
Start a free Courses trial
to watch this video
In the previous video, we saw how under-posting was breaking our validation. Let's explore how we can resolve this issue.
Follow Along
To follow along committing your changes to this course, you'll need to fork the aspnet-fitness-frog-spa repo. Then you can clone, commit, and push your changes to your fork like this:
git clone <your-fork>
cd aspnet-fitness-frog-spa
git checkout tags/v3.7 -b using-dtos-to-prevent-under-posting
In the previous video we saw how
under-posting was breaking our validation,
0:00
let's explore how we
can resolve this issue.
0:04
Let's take a look at
out Entry model class.
0:10
Adding required attributes to the Date,
ActivityId, Duration,
0:13
and Intensity properties,
unfortunately won't make a difference.
0:17
The Required attribute ensures
that a property has a value, but
0:30
the default values for these property
data types are in fact valid values.
0:34
In order for the required attribute
to have the desired effect,
0:40
we need to change these properties to
their corresponding nullable types.
0:43
But this classes' primary concern is
to define the entry type in our EF
0:48
unity data model.
0:53
In this particular situation it doesn't
feel right to change this class
0:56
in order to solve a problem with our API.
1:00
Also, if this class is being
used across multiple projects,
1:03
changing a property's data type could
break code throughout our solution.
1:06
The workaround that I'm going to employ,
is to create a DTO,
1:14
a Data Transfer Object.
1:18
And update our entries controller post and
1:20
put methods to bind to the DTO
instead of the entry model.
1:23
Having an entry DTO class will give us
a way to define the properties using
1:27
nullable types, all without
changing the entry model class.
1:32
Let's start by editing a folder for
our DTO class to live in.
1:36
Right click on
the Treehouse.FitnessFrog.Spa project and
1:44
select Add > NewFolder,
let's name the folder Dto.
1:50
Now let's add a class to our new folder.
1:56
I'll name the class EntryDto.
2:03
Now we need to add our properties,
which for
2:09
the most part will be one to one of
the properties on the entry model class.
2:11
Public int Id { get; set;}.
2:21
Public DateTime?
2:28
Date { get; set; }.
2:32
public int?
2:35
ActivityId { get; set; }.
2:38
Public decimal?
2:44
Duration { get; set; }.
2:48
Public Entry, and let's add a using
directive to the TreehouseFitnessFrog
2:52
shared model's namespace, and
this will be of type IntensityLevel,
2:57
which is the enumeration
defined in the entry model.
3:02
Add a question mark so
it's nullable as well, and
3:06
the name of the property is Intensity.
3:09
Then public bool, Exclude { get; set; }.
3:14
And lastly,
public string Notes { get; set; }..
3:21
Okay, now that we have our properties,
we can add our data annotation attributes.
3:27
The Date, ActivityId, Duration and
3:32
Intensity properties all
need required attributes.
3:35
And adding using directive for the system
component model data annotation namespace.
3:42
Okay, so that was for the Date property,
3:50
now we need to add a required attribute
for ActivityId, Duration, and Intensity.
3:53
I'm gonna add some extra white space,
just to make this easier to read.
3:59
There, that looks better.
4:07
Let's review the Entry Model class to see
if there's anything we might have missed.
4:11
That's just a display attribute,
we can ignore that.
4:18
The Notes property is decorated with
a max length data annotation attribute.
4:26
This limits the length of the string for
4:31
the Notes property to no
more than 200 characters.
4:34
It'd be good for
4:37
this constraint to be enforced as
a validation rule within our IAPI.
4:38
So, let's copy and paste this attribute to
our DTO class property with the same name.
4:41
All right,
now let's update the Entry's controller.
4:53
Scroll down to the Post action method.
5:02
And let's the method's parameter
to be our DTO's type, so EntryDto.
5:07
Looks like we need to add
a using directive for
5:13
our name space
Teehouse.FitnessFrog.Spa.Dto.
5:17
There we go.
5:21
Now web API will bind to our
EntryDto instead of the entry model.
5:23
That was easy enough to do, but
5:28
that broke the call to
the entriesRepository Add method.
5:30
Which expects an instance
of the Entry model class.
5:34
To resolve this issue, we need a method
to convert our EntryDto class instance
5:37
to an Entry model class instance.
5:42
To do this, let's add a to
model method to our DTO class.
5:47
Public, and for the return type
we want this to be of type Entry,
5:53
our model class, and
let's name the method ToModel().
5:58
We want to return a new instance
of the Entry model class.
6:05
Then let's map each of our DTO
properties to a model property.
6:12
So Id = Id, Date = Date, but
6:16
since this is a nullable
date time property,
6:20
we need to actually set it
to the Date.Value property.
6:25
Then ActivityId = ActivityId,
and again the same thing,
6:35
it's a nullable integer so
we want the Value property.
6:39
Duration = Duration.Value,
6:45
Intensity, Intensity.Value.
6:52
And then exclude this time, just Exclude,
6:59
because it's not a nullable type,
and Notes = Notes.
7:03
Then back in our Entry controller,
let's make a call to our new method
7:07
right before to
the _entriesRepository.Add method.
7:12
Var, and let's use the variable
name entryModel = entry.ToModel.
7:18
Now we can pass the entryModel
variable into the Add method.
7:26
After the entry has been
added to the database,
7:31
EF will set the model's ID property with
a value that assigned by the database.
7:34
We'll want to update our DTO's ID
property with that value.
7:39
So our call to the created method
will have the new resource's id.
7:43
So entry.id = entryModel.id.
7:50
Before we test our changes let's
also update the Put method.
7:58
To start, let's change our return
type from void to IHttpActionResult.
8:02
And instead of binding to
the Entry model class,
8:08
we wanna bind to our EntryDto class.
8:11
Then let's add an if
statement to check to see if
8:15
the ModelState.IsValid property is false.
8:19
And if it is false we want to
return a call to BadRequest,
8:23
parsing in our ModelState.
8:27
And just like with
the repositories add method,
8:30
the update method expects an instance
of the Entry model class.
8:33
So we need to call the ToModel
method on our DTO object And
8:37
then lastly since we changed our void
return type to IHttpActionResult,
8:43
we now need to explicitly return
the no content status code.
8:48
We can do that by returning
a call to the StatusCode method.
8:52
Passing in the System.Net.HttpStatusCode
in numeration value of NoContent.
8:57
Next step let's test our changes.
9:04
You need to sign up for Treehouse in order to download course files.
Sign up