-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathBuilding Your First API with ASP.NET Core
765 lines (633 loc) · 26.9 KB
/
Building Your First API with ASP.NET Core
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
Subject: Building Your First API with ASP.NET Core
{Module 1: Course Overview}
Course Overview
Build API for getting & manipulating info for cities and their points of interest
Intro to ASP.NET Core
Implement functionalities
Essential features & concepts
Entity Framework Core (ORM for .NET Core)
{Module 2: Getting Acquainted with ASP.NET Core}
Introduction
ASP.NET Core 1 & 2
VS 2015 & 2017
Gradual improvement
Introduce ASP.NET Core
Build API
Update / Delete resources (in-memory)
EF Core
Tooling
VS2015 ASP.NET Core 1 (update 3): project.json
VS2017 ASP.NET Core 1: .csproj / MSBuild
VS2017 ASP.NET Core 2 (v15.3+): .csproj / MSBuild
VS Code ASP.NET Core 1 & 2: .csproj / MSBuild
VS for Mac ASP.NET Core 1 & 2: .csproj / MSBuild
Exercise Files
95% code overlap b/t ASP.NET Core 1 & 2
VS2015 Core 1
VS2017 Core 1
VS2017 Core 2
Postman: send request / receive response
ASP.NET Core: The Big Picture
ASP.NET Core:
open-source & cross platform framework for building modern cloud-based internet connected applications
re-design from ground up
granular set of NuGet packages
smaller application service area
tighter security
reduced servicing
improved performance
ASP.NET Core runs on:
Full .NET Framework: target all dependencies
.NET Core:
small footprint
performance improvement
cross-platform
Demo: Downloading and Installing .NET Core
Demo: Starting a New ASP.NET Core Project
Under solution "Cityinfo.API":
Program.cs:
Starting point of application
w/ "public static void Main(string[] args)"
-> ASP.NET Core is a console application (that calls into ASP.NET specific libraries)
public static void Main(string[] args)
{
var host = new WebHostBuilder()
.UseKestrel()
.UseContentRoot(Directory.GetCurrentDirectory())
.UseIISIntegration()
.UseStartup<Startup>()
.UseApplicationInsights()
.Build();
host.Run();
}
WebHostBuilder(): Host application
UseKestrel(): Provides default Web Server
ASP.Net Core is completely decoupled from web server environment
ASP.Net Core is shipped with two different Http servers:
WebListener: windows-only seb server
Kestrel (default): cross-platform web server
UseIISIntegration():
Since IIS Express is default host for Visual Studio
IIS Express functions as reverse proxy server for Kestrel
Self hosting with IIS Express is possible, but IIS is much nicer
UseContentRoot(Directory.GetCurrentDirectory()):
UseContentRoot() specifies content root directory used by web host
content root:
base path to any content used by any application (like views and web content)
default: same as app base path for the executable hosting the app
content root is NOT webroot (wwwroot)
UseStartup<Startup>():
specifies startup type used by web host
Build():
build IWebHost instance to host our web app
Run():
runs web app; blocks the calling thread until host shuts down
Startup.cs: entry point of application
public void ConfigureServices(IServiceCollection services):
an optional method
for registering that are NOT registered automatically
* Add services to the container & configure services *
container: for dependency Injection
service: component intended for common consumption in an application
example:
(framework Services) identity, MVC, EF Core services
(application services - application specific) like one for sending email
(built-in services)
like ApplicationBuilder or Logger - there are NO coding in ConfigureServices
built-in services are available for injection
Injection via Configure method:
example: public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
with Instance of
IApplicationBuilder
IHostingEnvironment
ILoggerFactory
provided by the container
Called after ConfigureServices()
Uses services configured and registered in ConfigureServices()
Specify how app will respond to individual HTTP requests, such as MVC
The ASP.NET Core Request Pipeline and Middleware
Request pipeline:
code logic that handles requests and returns response
configure pipeline by adding middleware(s)
example:
diagnostics middleware
authentication middleware
MVC
Each middleware determines to pass request on to the next component in pipeline or NOT
Order to add middleware matters
example:
authentication middleware finds unauthorized request and returns unauthorized response without passing to the next middleware
Therefore, authentication middleware needs to be added
Demo: Configuring the ASP.NET Request Pipeline
Add developer exception page middleware to request pipeline
[Within Configure method]
app.UseDeveloperExceptionPage()
This is part of microsoft.aspnet.core.diagnostics assembly
Most middlewares are in separate assemblies
Add following code to trigger exception
app.Run( (context) =>
{
throw new Exception("Example exception");
});
Add ExceptionHandler to HTTP request pipeline when environment is not development
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else {
app.UseExceptionHandler();
}
Change environment from "Development" to "Production"
Project Properties | Debug |
For Environment variable:
Change value of ASPNETCORE_ENVIRONMENT to "Production" from "Development"
Summary
{Module 3: Creating the API and Returning Resources}
Coming Up
Add middleware to Web API, such as ASP.NET Core Middleware
Return resources (data) from Web API
Interact with Web API by sending HTTP request
Configure response
Middleware for Building an API
Need to:
Add middleware to HTTP request pipeline in Configure method
Add framework services to container in ConfigureServices method
Previously (Before Core)
ASP.NET Web API: Http services
ASP.NET MVC: Client-facing web application
Now (only):
ASP.NET Core MVC
Clarifying the MVC Pattern
MVC = Model-View-Controllers
Architecture software pattern for implementing UI
Encourage loose coupling, separation of concerns, testability, reuse
Not the FULL application architecture
A typical N-tier architecture: presentation layer, business layer, data access layer
also likely a service layer in-between
MVC is used as presentation layer
Model:
handles the logic of application data like retrive or store data
If MVC pattern is only used at the top level of architecture, the model does not contain any logic
- another component handles this, such as business layer
Alternatively, a View Model contains code to retrive or store data, used as model
View:
handles the display of data, like HTML
depends on Model
Controller:
handles interaction between Model and View
handles user input
depends on Model & View
chooses View to display to user
provide the View with any Model data the View required
In terms of API:
View represents data or resources (JSON)
Consumer of API is typically another application
Request send by consumer of API will trigger Controller
Controller takes user inputs (like query string parameters) to component responsible of business or data logic
Controller returns a model to data or resources like JSON (View)
Demo: Adding the ASP.NET Core MVC Middleware
Under Startup.cs / ConfigureServices()
Add services.AddMvc();
AddMvc() is not recognized
Add reference: Microsoft.AspNetCore.Mvc
Under Startup.cs / Configure()
Add app.UseMvc();
below exception handling code
Run project with IIS Express
return error 404
Next: Add controller to return resources (data)
ASP.NET Core 2 Metapackage and Runtime Store
New concept for ASP.NET Core 2:
Metapackage: Microsoft.AspNetCore.All
Runtime Store
Potential issues with Modularity
difficult to
locate functionalities
track version numbers
For ASP.NET Core 2.0
Metapackage adds a list of packages
Microsoft.AspNetCore.All includes
- all supported ASP.NET Core packages
- all supported Entity Framework Core packages
- internal and 3rd party dependencies used by ASP.NET Core & Entity Framework Core
But where do those packages come from?
For ASP.NET Core 2.0
Runtime Store locates on disk containing packages required for running ASP.NET Core 2 application
Similar to Global Assembly Cache
Benefits of Runtime Store
Faster deployment
Lower disk space used - b/c multiple applicae can use same Store
Improved startup performance - b/c packages are pre-compiled
Trade-off:
Comparing with ASP.NET Core 1.X
The (OPTIONAL) new approach require installation of Runtime and Runtime Store on each machine that been publish to
Demo: Returning Resources (Part 1)
Create Controllers Folder under project
Create CitiesController class under Controllers Folder
Objective: return JSON as the representation format of data
CitiesController Extends from Controller (using Microsoft.AspNetCore.Mvc)
Add Method:
public JsonResult GetCities()
{
return new JsonResult(
new List<object>()
{
new { id=1, Name = "New York City" },
new { id=2, Name = "Antwerp"}
});
}
When consuming HTTP services (like Web API)
Client sned HTTP GET request
Learning About Routing
Routing matches request to a method on Controller
Client Sneds Request
MVC framework passes URI to a controller and a corresponding method on that controller
By Convention:
Under Startup.cs | Configure | (Add parameters) app.UseMvc()
Passing routing conventions as UseMvc parameters
example:
app.UseMvc( config => {
config.MapRoute(
name: "Default",
template: "{controller}/{action}/{id?}",
defaults: new {controller="Home", action="Index"}
); });
Typically for returning HTML-return views
Conventions need to be configured
NOT ADVISED for API's
By Attribute:
Attributes at controller & action level including an optional template
Attributes are based on HTTP method
Typical resource use case: creating, reading, updating and deleteing
Reading:
HTTP Method: GET
Attribute: HttpGet
Level: Action
Sample URI: "/api/cities" & "/api/cities/1"
Creating:
HTTP Method: POST
Attribute: HttpPost
Level: Action
Sample URI: "/api/cities"
Updating:
Full Update:
HTTP Method: PUT (all fields overwritten or set to default)
Attribute: HttpPut
Level: Action
Sample URI: "/api/cities/1"
Partial Update:
HTTP Method: PATCH
Attribute: HttpPatch
Level: Action
Sample URI: "/api/cities/1"
Deleting:
HTTP Method: DELETE
Attribute: HttpDelete
Level: Action
Sample URI: "/api/cities/1"
Special Attribute: Route
Attribute: HttpDelete
Level: Controller
Provide a template to prefix all templates of action level attributes
Sample: Set template value "/api/cities" at controller level, so templates at action level do not have to
Demo: Returning Resources (Part 2)
Objective: Execute specific controller action when receiving request to "api/cities"
Pass in routing template
[HttpGet("api/cities")]
public JsonResult GetCities()
{ //See Demo 1 above }
Response:
[
{
"id": 1,
"name": "New York City"
},
{
"id": 2,
"name": "Antwerp"
}
]
Define route attribute at controller level
[Route("api/cities")]
public class CitiesController : Controller
{ //... }
OR [Route("api/[controller]")]
However, with this approach, refactoring can cause controller name change, which will change URI as well
Demo: Improving the Architecture with Model Classes
Objective: Add Model
Add "Models" folder under project
Add DTO class, "CityDto.cs"
What is return from and accept by API is NOT the same as the entities used by underlying datastore
At this point, in-memory datastore is been used
Entity Framework Core will be added later
Entity classes will be different from these Dto classes
Dto can contain methods with calculation that will NOT be part of entity class
Entity class will not contain field like Id - but defer it to underlying datastore
Add a new action to return a single city
Add new action GetCity
Under CitiesController.cs
[HttpGet("{id}")]
public JsonResult GetCity(int id)
{
return new JsonResult(
CititesDataStore.Current.Cities.FirstOrDefault(c => c.Id == id)
);
}
Noted that Route attribute in previous Demo eliminate the need to add "api/cities" like "api/cities/{id}"
Get attribute is marked with "{id}" and pass into GetCity(int id) as integer
Request with un-matched URI (like "api/people") will produce 404 error - resource not found - return by framework
Request with matched URI (to an Action, like "api/cities/0") but parameter does not exist will produce 200 OK status with null result
However, 404 error is the expected response status code
The Importance of Status Codes
HTTP response contains status code
Client (App) can get information if:
request processed as expected
(If fail) cause of failure
Five levels of status code:
Level 100: Informational, not part of HTTP 1.0 standard, NOT used by API
Level 200: request success
200 - OK: GET
201 - Created new resource
204 - No content: DELETE
Level 300: Re-Direction
Such as inform search engine a page has been permanently moved, mostly NOT used by API
Level 400: Client Error
400 - Bad request: such as JSON provided by client cannot be parsed
401 - Unauthorized: No or invalid authentication details were provided
403 - Forbidden: Authentication success, but client does not have access to resource requested
404 - Not found: Request resource does not exist
409 - Conflict: like two updates at the same time
Level 500: Server Error
500 - Internal Server Error
Demo: Returning Correct Status Codes
Objective: return response with a specific status code
At this point, we are returning JsonResult
JsonResult is an ActionResult formats given object as JSON
ActionResult is the default implementation of IActionResult
IActionResult defines a contract of an Action method
What if we want to return othe than Json object or along with a response status code?
- API should return what consumer request in Accept header if supported
- In addition to data, status code is also an important part of the response
To set status code literally
Under CitiesController | GetCities()
[HttpGet()]
public JsonResult GetCities()
{
var temp = new JsonResult(CitiesController.Current.Cities);
temp.StatusCode = 200;
return temp;
}
ASP.NET Core built-in helper methods - all create IActionResult
NotFound(): resource is not found
BadRequest(): request is malformed ... and more
Change result signature of Get methods in CitiesController to IActionResult
The return result can be of different format, like XML
[Http("{id}")]
public IActionResult GetCity(int id)
{
var cityToReturn = CityDataStore.Current.Cities.FirstOrDefault(c => c.Id == id);
if (cityToReturn == null)
{ return NotFound(); }
return Ok(cityToReturn);
}
Advantage of using methods like NotFound() or Ok() & IActionResult
Results are not necessarily returned in JSON format
If other formatters in API are supported, consumer can decide how to view the results
Modify Startup.cs to add status code pages (middleware):
Under Configure() method:
app.UseStatusCodePages();
Now display "Status Code: 404; Not Found" for resource not found instead of empty page
Demo: Returning Child Resources
Objective: return points of interests in a city with correct status code
Add class PointOfInterestDto
Extend CityDto class to include a collection of points of interest
- Initalize the list with empty collection to avoid null point exception
Under CityDto.cs (auto-property initializer):
public ICollection<PointOfInterestDto> PointOfInterest { get; set; } = new List<PointOfInterestDto>();
Add Controller: PointsOfInterestController extends Controller, with [Route("")] attribute
PointsOfInterest is a child resource of another resource - the URI needs to reflect that
Start the Route attribute with [Route("api/cities")]
If a City (parent resource) cannot be found, then request for pointsofinterest(child resource) should return 404
Add Action to PointsOfInterestController to get one point of interest
[HttpGet("{cityId}/pointsofinterest/{id}")]
public IActionResult GetPointOfInterest(int cityId, int id) {}
Demo: Working with Serializer Settings
Objective: chnage property casing to match casing in DTO class with Serializer Settings
ASP.NET Core by default deserializes from and serializes to Json
To apply the convetion directly from DTO class by overwritting default NamingStrategy:
Startup.cs | ConfigureServices |
services.AddMvc()
.AddJsonOptions(o => {
if (o.SerializerSettings.ContractResolver != null)
{
var castedResolver = o.SerializerSettings.ContractResolver
as DefaultContractResolver;
castedResolver.NamingStrategy = null;
}
});
Formatters and Content Negotiation
Content Negotiation:
Selecting the best representation for a given response when multiple response are available
This may be necessary when API has multiple clients / unknown clients that may prefer XML or other format
Media type is passed via the Accept header of the request
ex. "application/json" or "application/xml"
Output formatter of ASP.NET Core deals with Output
Consumer of API can request a specific type of output by
Setting the Accept header to the requested media typle, such as "application/json"
Input formatter of ASP.NET Core deals with Input
- like body of a POST request to create new resources
- input to media type of request body identified through content-type header
Demo: Formatters and Content Negotiation
By Default, only Json input / output are used
Under Startup | ConfigureServices method
services.AddMvc()
.AddMvcOptions(o => o.OutputFormatters.Add(new XmlDataContractSerializerOutputFormatter()));
AddMvcOptions: Configure supported formatters for API
Add XmlDataContractSerializerOutputFormatter to supported formatters
Use o.OutputFormatters.Clear to clear all formatters
Use o.OutputFormatters.Remove to remove a specific one
Summary
MVC Pattern
Routing maps URI to controller method
For API, attribute-routing is advised over convention-based routing
Content Negotiation by
Output formatters (accept header in request)
Input formatters (content-type header)
{Module 4: Manipulating Resources}
Coming Up
Creating Resources
Updating Resources
Deleting Resources
Validating Inputs
Demo: Creating a Resource
Objective: Create DTO without Id with POST
DTO should be different for different needs of actions (read, create, update, delete)
- ID should not be part of BTO for creating resource
Add "PointOfInterestForCreationDto.cs" in Models folder without Id
- Even in cases where "PointOfInterestForDto" and "PointOfInterestForCreationDto" are identical
It would be good to create them saperately
-> create model more inline with functionality
-> easy to refactor or change
-> different validation rules for different models
Create method "CreatePointOfInterest" and decorate with HttpPost attribute
parameters:
int cityId
[FromBody] PointOfInterestForCreationDto pointOfInterest
Obtain data from request body to create DTO "PointOfInterestForCreationDto"
Case Bad request: request body cannot be deserialized
Return BadRequest() if DTO is null
Case Not Found: parent resource not found
Return NotFound() if cityId does not match an existing city
Add new object to in-memory datastore
Calculate Id for the new point of interest
Iterate through all Ids and get the Max value
Add one to Max Id value and assign it to new Id
Assign inputs of other fields to new object
Add new object to in-memory datastore
!! ISSUE with this approach: concurrency and performance
Create At Route helper method (201 Created Response):
Route to single point of interest for a city
Name the action "GetPointOfInterest"
[HttpGet("{cityId}/pointsofinterest/{id}", Name = "GetPointOfInterest")]
Add parameters to CreatedAtRoute()
return CreatedAtRoute("GetPointOfInterest", new
{
cityId = cityId,
id = finalPointOfInterest.Id
},
finalPointOfInterest
);
parameter #1: "GetPointOfInterest" - this is the name of action
parameter #2: anonymous object with values required by route template: cityId and Id
parameter #3: newly created DTO "PointOfInterestDto" (stored in data store) -> ens up in response body
Test with Postman:
Post request URL: http://localhost:56412/api/cities/3/pointsofinterest
Pass in two parameters (name and description) as JSON in request Body
{
"name": "Cookies Store",
"description": "A store that sells cookies..."
}
Specify JSON format in content type header for input formatter
Header
key: "Content-Type",
value: "application/json"
Response: 201 Created
Newly created DTO in the body
Location header in header collection for consumer to access the point of interest
Location -> http://localhost:56412/api/cities/3/pointsofinterest/7
Demo: Validating Input
Objective: Validtae input with ModelState
Send request with invalid input
POST request with empty body -> null DTO reference triggered BadRequest()
POST request with missing property for DTO & very long description -> API will not return error
Check each value manually is too cumbersome -> solution: Data Annotation
Apply Data Annotation to DTO "PointOfInterestForCreationDto"
using System.ComponentModel.DataAnnotations;
[Required] - value required
[MaxLength(50)] - Maximum Length allowed (50)
Model State is a dictionary that contains:
- State of model
- Model binding validation
[Aside from DTO is null]
If there is any rule borken or invalid input, ModelState.IsValid() will return false
if (!ModelState.IsValid)
return BadRequest();
Upon breaking the annotation, a message like following will be in body of the response
{
"Name": [
"Name value is required!"
],
"Description": [
"The field Description must be a string or array type with a maximum length of '200'."
]
}
customized message for Name, default message for Description
For more complex validation or validation that cannot be checked with built-in data annotation:
Customized coding required
Add errors to ModelState so they are returned with ModelState when return BadRequest(ModelState)
Case: Description and Name are the same
Add model error in "PointsOfInterestController"
if (pointOfInterest.Description == pointOfInterest.Name)
{
ModelState.AddModelError("Description", "Provided description should be different from the name.");
}
[When description and name are the same]
Response Body contains following:
{
"Description": [
"Provided description should be different from the name."
]
}
Consider "FluentValidation" for better architecture - support .NET Core after version 6.4
Demo: Updating a Resource
Objective: Full update with HTTP PUT method
Add DTO for updating pointofinterest: PointOfInterestForUpdateDTO
Add action under PointsOfInterestController: UpdatePointOfInterest
Full update:
Consumer of API should provide values for resource, save for ID (coming form URI)
When consumer fail to provide values, those fields should be put to its default value
return 204 NoContent
Request complete successfully without anything to return
e.g. return NoContent();
Partially Updating a Resource
Partially Updating a Resource with PATCH HTTP method
Body of request needs:
fields and values to be updated
necessary operation like copy value of one property to another property
Json Patch (RFC 6902)
http://tools.ietf.org/html/rfc6902
Defines JSON structure for expression a sequence of operations to apply to a JSON document
The API client creates JsonPatch document as body of PATCH request
The body conatins a list of operations: add, replace, copy, etc including resp
examples of request body:
[
{
"op": "replace",
"path": "/name",
"value": "new name"
}
,
{
"op": "replace",
"path": "/description",
"value": "new description"
}
]
1. start with array of operations []
2. operations (like "replace") signified by the name "op"
3. "path" signifies path to property (like "/name" or "/description")
4. "value" signifies new value for the named propery
Demo: Partially Updating a Resource
Objective: Partially Updating a Resource with PATCH
PATCH: HTTP PATCH attribute
Demo: Deleting a Resource
Summary
{Module 5: Working with Services and Dependency Injection}
Coming Up
Inversion of Control and Dependency Injection
Demo: Injecting and Using a Logger
Demo: Logging to a File
Demo: Implementing and Using a Custom Service
Demo: Working with Configuration Files
Demo: Scoping Configuration to Environments
Summary
{Module 6: Getting Acquainted with Entity Framework Core}
Coming Up
Introducing Entity Framework Core
Demo: Creating Entity Classes
Demo: Creating a DbContext
Demo: Working with Migrations
Demo: Safely Storing Sensitive Configuration Data
Demo: Seeding the Database with Data
Summary
{Module 7: Using Entity Framework Core in Our Controllers}
Coming Up
Introducing the Repository Pattern
Demo: Introducing the Repository Pattern
Demo: Returning Data from the Repository When Requesting Resources
Demo: Using AutoMapper to Map Between Entities and DTOs
Demo: Creating a Resource
Demo: Updating a Resource
Demo: Partially Updating a Resource
Demo: Deleting a Resource
Summary