02 - ASP.NET Core MVC
MVC
Just a reminder
- Model
- Business logic and its persistence
- View
- Template for displaying data
- Controller
- Communication between Model, View and end-user
- ViewModel
- Models used for supplying views with complex (strongly typed) data
- MVC Viewmodels vs MVVM (Model-View-ViewModel - WPF)
Request Pipeline
Simplest aspnet middleware/app
1 2 3 4 5 6 7 8 9 10 11 |
|
Chain multiple request delegates together with Use
. The next
parameter represents the next
delegate in the pipeline.
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 |
|
Don't call next.Invoke
after the response has been sent to the client (terminal middleware).
Check httpContext.Response.HasStarted
!
Branching middleware
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 |
|
When Map
is used, the matched path segments are removed from HttpRequest.Path
and appended to HttpRequest.PathBase
for each request.
Pipeline is configured with methods
- Run – short circuit, return
- Map - branch
- Use – Chaining middleware-s together
Custom middleware
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 |
|
And inject it into pipeline
1 2 |
|
NB! Dependncy injection and scoped dependencies
Middleware is singleton, use constructor DI.
For scoped DI use InvokeAsync additional parameters.
Middleware ordering
Middlewares are called in order they are added. So the ordering is important/critical for severel reasons - security, performance, and functionality.
1 2 3 4 5 6 7 8 9 |
|
ASP.NET Middleware
Typical ASP.NET Core MVC pipeline
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
|
Endpoint middleware...
Filters in MVC
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
|
Controller
- Controller – define and group actions (or action method) for servicing incoming web requests.
- Controller can be any class that ends in “Controller” or inherits from class that ends with “Controller”
- Convention is (but are not required)
- Controllers are located in "Controllers" folder
- Controllers inherit from Microsoft.AspNetCore.Mvc.Controller
- The Controller is a UI level abstraction. Its responsibility is to ensure incoming request data is valid and to choose which view or result should be returned.
In well-factored apps it will not directly include data access or business logic, but instead will delegate to services handling these responsibilities.
Inheriting from base Controller gives lots of helpful methods and properties
Most importantly returning various responses
- View
- Return View(viewModel);
- HTTP Status Code
- Return BadRequest();
- Formatted Response
- Return Json(someObject);
- Content negotiated response
- Return Ok();
- Redirect
- Return RedirectToAction(“Complete”, viewModel);
Routing
Routing middleware is used to match incoming requests to suitable controller and action
Actions are routed by convention or by attribute
Routing middleware (sets up the convention)
1 2 3 |
|
By "classic" convention, request should take this form
.../SomeController/SomeAction/ID
Multiple routes
1 2 3 4 5 6 7 8 |
|
- Routes are matched from top-down
- On first match corresponding controller.action is called
Multiple matching action
When multiple actions match, MVC must select suitable action
Use HTTP verbs to select correct action
1 2 3 4 5 6 7 8 9 10 11 |
|
If not possible to choose, exception is thrown
show form -> submit form -> redirect pattern is common
Routing attributes
With attribute routing, controller and action name have no role!
Typically attribute based routing is used in api programming
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
|
Route Template
-
{ }
– define route parameters
Can specify multiple, must be separated by literal value
Must have a name, my have additional attributes -
*
- catch all parameter
blog/{*foo}
would match any URI that started with/blog
and had any value following it (which would be assigned to thefoo
route value). - Route parameters may have default values
name?
– may be optionalname:int
– use : to specify an route constraintblog/{article:minlength(10)}
Route constraints
Avoid using constraints for input validation, because doing so means that invalid input will result in a 404 (Not Found) instead of a 400 with an appropriate error message.
Route constraints should be used to disambiguate between similar routes, not to validate the inputs for a particular route.
Constraints are
int, bool, datetime, decimal, double, float, guid, long, minlength(value), maxlength(value), length(value), length(min,max), min(value), max(value), range(min, max), alpha, regex(expression), required
Model Binding
- Maps data from from HTTP request to action parameters
- Order of binding
- Form values (POST)
- Route values
- Query string (…foo/?bar=fido)
Route: {controller=Home}/{action=Index}/{id?}
request: .../movies/edit/2
public IActionResult Edit(int? id)
Model binding also works on complex types – reflection, recursion – type must have default constructor
Model binding attributes
- BindRequired – adds an model state error, if property cannot be binded (int Foo for example)
- BindNever – switch off binder for this parameter
If you want to modify the default binding source order:
- FromHeader
, FromQuery
, FromRoute
, FromForm
– select source
- FromBody
– from request body, use formatter based on content type (json, xml)
View scaffolding
Use [ScaffoldColumn(false)]
attribute in your model to exclude some property from scaffolding.
Not a proper way to approach this, use correct ViewModels instead (DTO).
Model validation
- Validation attributes mostly in
System.ComponentModel.DataAnnotations
[Required]
,[MaxLength()]
, etc.- Model validation occurs prior to action invocation
- Action has to inspect
ModelState.IsValid
- If needed, call
TryValidateModel(someModel)
again
Custom validation, client-side validation, remote validation - it's coming...
ModelState
-
ModelState builds up metadata representation of your viewmodel
-
When repopulating view with data in postback (Edit/Post) ModelState values are used first by tag-helpers/html helper, if not found then values from actual viewmodel. (ie when re-rendering edit view due to validation errors)
- So, if you need update viewmodel data in Post method, remove responding fields from ModelState
1 2 |
|