1 00:00:00,310 --> 00:00:04,689 In the previous video we saw how under-posting was breaking our validation, 2 00:00:04,689 --> 00:00:07,290 let's explore how we can resolve this issue. 3 00:00:10,581 --> 00:00:13,231 Let's take a look at out Entry model class. 4 00:00:13,231 --> 00:00:17,278 Adding required attributes to the Date, ActivityId, Duration, 5 00:00:17,278 --> 00:00:21,549 and Intensity properties, unfortunately won't make a difference. 6 00:00:30,770 --> 00:00:34,874 The Required attribute ensures that a property has a value, but 7 00:00:34,874 --> 00:00:40,290 the default values for these property data types are in fact valid values. 8 00:00:40,290 --> 00:00:43,626 In order for the required attribute to have the desired effect, 9 00:00:43,626 --> 00:00:47,594 we need to change these properties to their corresponding nullable types. 10 00:00:48,921 --> 00:00:53,803 But this classes' primary concern is to define the entry type in our EF 11 00:00:53,803 --> 00:00:56,060 unity data model. 12 00:00:56,060 --> 00:01:00,070 In this particular situation it doesn't feel right to change this class 13 00:01:00,070 --> 00:01:03,410 in order to solve a problem with our API. 14 00:01:03,410 --> 00:01:06,842 Also, if this class is being used across multiple projects, 15 00:01:06,842 --> 00:01:11,134 changing a property's data type could break code throughout our solution. 16 00:01:14,575 --> 00:01:18,747 The workaround that I'm going to employ, is to create a DTO, 17 00:01:18,747 --> 00:01:20,880 a Data Transfer Object. 18 00:01:20,880 --> 00:01:23,070 And update our entries controller post and 19 00:01:23,070 --> 00:01:27,950 put methods to bind to the DTO instead of the entry model. 20 00:01:27,950 --> 00:01:32,075 Having an entry DTO class will give us a way to define the properties using 21 00:01:32,075 --> 00:01:36,730 nullable types, all without changing the entry model class. 22 00:01:36,730 --> 00:01:39,896 Let's start by editing a folder for our DTO class to live in. 23 00:01:44,741 --> 00:01:50,159 Right click on the Treehouse.FitnessFrog.Spa project and 24 00:01:50,159 --> 00:01:54,960 select Add > NewFolder, let's name the folder Dto. 25 00:01:56,120 --> 00:01:58,033 Now let's add a class to our new folder. 26 00:02:03,692 --> 00:02:07,724 I'll name the class EntryDto. 27 00:02:09,220 --> 00:02:11,663 Now we need to add our properties, which for 28 00:02:11,663 --> 00:02:15,770 the most part will be one to one of the properties on the entry model class. 29 00:02:21,152 --> 00:02:26,690 Public int Id { get; set;}. 30 00:02:28,218 --> 00:02:32,148 Public DateTime? 31 00:02:32,148 --> 00:02:35,812 Date { get; set; }. 32 00:02:35,812 --> 00:02:38,657 public int? 33 00:02:38,657 --> 00:02:41,386 ActivityId { get; set; }. 34 00:02:44,043 --> 00:02:48,429 Public decimal? 35 00:02:48,429 --> 00:02:50,348 Duration { get; set; }. 36 00:02:52,559 --> 00:02:57,528 Public Entry, and let's add a using directive to the TreehouseFitnessFrog 37 00:02:57,528 --> 00:03:02,117 shared model's namespace, and this will be of type IntensityLevel, 38 00:03:02,117 --> 00:03:05,570 which is the enumeration defined in the entry model. 39 00:03:06,720 --> 00:03:09,385 Add a question mark so it's nullable as well, and 40 00:03:09,385 --> 00:03:11,486 the name of the property is Intensity. 41 00:03:14,008 --> 00:03:20,038 Then public bool, Exclude { get; set; }. 42 00:03:21,877 --> 00:03:25,858 And lastly, public string Notes { get; set; }.. 43 00:03:27,711 --> 00:03:32,633 Okay, now that we have our properties, we can add our data annotation attributes. 44 00:03:32,633 --> 00:03:35,080 The Date, ActivityId, Duration and 45 00:03:35,080 --> 00:03:38,602 Intensity properties all need required attributes. 46 00:03:42,523 --> 00:03:47,250 And adding using directive for the system component model data annotation namespace. 47 00:03:50,830 --> 00:03:53,560 Okay, so that was for the Date property, 48 00:03:53,560 --> 00:03:59,103 now we need to add a required attribute for ActivityId, Duration, and Intensity. 49 00:03:59,103 --> 00:04:02,315 I'm gonna add some extra white space, just to make this easier to read. 50 00:04:07,802 --> 00:04:09,563 There, that looks better. 51 00:04:11,501 --> 00:04:15,216 Let's review the Entry Model class to see if there's anything we might have missed. 52 00:04:18,330 --> 00:04:20,929 That's just a display attribute, we can ignore that. 53 00:04:26,781 --> 00:04:31,830 The Notes property is decorated with a max length data annotation attribute. 54 00:04:31,830 --> 00:04:34,051 This limits the length of the string for 55 00:04:34,051 --> 00:04:37,153 the Notes property to no more than 200 characters. 56 00:04:37,153 --> 00:04:38,049 It'd be good for 57 00:04:38,049 --> 00:04:41,770 this constraint to be enforced as a validation rule within our IAPI. 58 00:04:41,770 --> 00:04:46,510 So, let's copy and paste this attribute to our DTO class property with the same name. 59 00:04:53,022 --> 00:04:55,895 All right, now let's update the Entry's controller. 60 00:05:02,210 --> 00:05:04,567 Scroll down to the Post action method. 61 00:05:07,114 --> 00:05:13,867 And let's the method's parameter to be our DTO's type, so EntryDto. 62 00:05:13,867 --> 00:05:17,349 Looks like we need to add a using directive for 63 00:05:17,349 --> 00:05:21,484 our name space Teehouse.FitnessFrog.Spa.Dto. 64 00:05:21,484 --> 00:05:22,459 There we go. 65 00:05:23,838 --> 00:05:28,560 Now web API will bind to our EntryDto instead of the entry model. 66 00:05:28,560 --> 00:05:30,200 That was easy enough to do, but 67 00:05:30,200 --> 00:05:34,330 that broke the call to the entriesRepository Add method. 68 00:05:34,330 --> 00:05:37,710 Which expects an instance of the Entry model class. 69 00:05:37,710 --> 00:05:42,662 To resolve this issue, we need a method to convert our EntryDto class instance 70 00:05:42,662 --> 00:05:44,847 to an Entry model class instance. 71 00:05:47,870 --> 00:05:53,000 To do this, let's add a to model method to our DTO class. 72 00:05:53,000 --> 00:05:58,076 Public, and for the return type we want this to be of type Entry, 73 00:05:58,076 --> 00:06:02,789 our model class, and let's name the method ToModel(). 74 00:06:05,970 --> 00:06:09,628 We want to return a new instance of the Entry model class. 75 00:06:12,302 --> 00:06:16,800 Then let's map each of our DTO properties to a model property. 76 00:06:16,800 --> 00:06:20,412 So Id = Id, Date = Date, but 77 00:06:20,412 --> 00:06:25,905 since this is a nullable date time property, 78 00:06:25,905 --> 00:06:32,713 we need to actually set it to the Date.Value property. 79 00:06:35,187 --> 00:06:39,393 Then ActivityId = ActivityId, and again the same thing, 80 00:06:39,393 --> 00:06:43,355 it's a nullable integer so we want the Value property. 81 00:06:45,822 --> 00:06:49,759 Duration = Duration.Value, 82 00:06:52,271 --> 00:06:57,796 Intensity, Intensity.Value. 83 00:06:59,240 --> 00:07:03,079 And then exclude this time, just Exclude, 84 00:07:03,079 --> 00:07:07,972 because it's not a nullable type, and Notes = Notes. 85 00:07:07,972 --> 00:07:12,896 Then back in our Entry controller, let's make a call to our new method 86 00:07:12,896 --> 00:07:16,917 right before to the _entriesRepository.Add method. 87 00:07:18,261 --> 00:07:24,044 Var, and let's use the variable name entryModel = entry.ToModel. 88 00:07:26,286 --> 00:07:28,726 Now we can pass the entryModel variable into the Add method. 89 00:07:31,760 --> 00:07:34,620 After the entry has been added to the database, 90 00:07:34,620 --> 00:07:39,423 EF will set the model's ID property with a value that assigned by the database. 91 00:07:39,423 --> 00:07:43,252 We'll want to update our DTO's ID property with that value. 92 00:07:43,252 --> 00:07:47,336 So our call to the created method will have the new resource's id. 93 00:07:50,773 --> 00:07:58,880 So entry.id = entryModel.id. 94 00:07:58,880 --> 00:08:02,741 Before we test our changes let's also update the Put method. 95 00:08:02,741 --> 00:08:08,380 To start, let's change our return type from void to IHttpActionResult. 96 00:08:08,380 --> 00:08:11,387 And instead of binding to the Entry model class, 97 00:08:11,387 --> 00:08:13,670 we wanna bind to our EntryDto class. 98 00:08:15,654 --> 00:08:19,774 Then let's add an if statement to check to see if 99 00:08:19,774 --> 00:08:23,792 the ModelState.IsValid property is false. 100 00:08:23,792 --> 00:08:27,482 And if it is false we want to return a call to BadRequest, 101 00:08:27,482 --> 00:08:29,375 parsing in our ModelState. 102 00:08:30,640 --> 00:08:33,080 And just like with the repositories add method, 103 00:08:33,080 --> 00:08:37,410 the update method expects an instance of the Entry model class. 104 00:08:37,410 --> 00:08:43,050 So we need to call the ToModel method on our DTO object And 105 00:08:43,050 --> 00:08:48,183 then lastly since we changed our void return type to IHttpActionResult, 106 00:08:48,183 --> 00:08:52,421 we now need to explicitly return the no content status code. 107 00:08:52,421 --> 00:08:57,175 We can do that by returning a call to the StatusCode method. 108 00:08:57,175 --> 00:09:04,777 Passing in the System.Net.HttpStatusCode in numeration value of NoContent. 109 00:09:04,777 --> 00:09:06,735 Next step let's test our changes.