MVC & WebAPI
Models: Data model Views: UI Components Controllers: Handle browser requests, retrieve model data then return a response Service Layer: Additional layer that separates validation logic from your controller
Ideas behind MVC:
- Separation of converns. E.G. Views don't handle business logic
Controller
- MVC implements URL routing logic in this format:
/[Controller]/[ActionName]/[Parameters]
public string Index()
: BaseURL methodMapControllerRoute
: URL template where you define parameters of a route- Components of a route method
IActionResult
: Interface for contracts that return the result of an action method. Generally return this or a something derived from ActionResultView
method : Renders the view- If the view is not specified, MVC defaults to using the view with the same name as the action method
- E.G.
/HelloWorld/Index
-->/Views/HelloWorld/Index.cshtml
- How to pass data from controllers to views?
- The preferred method is to use a View Model
- View Model : Pass strongly typed models using the queryset as a parameter in the
View()
method. You can define the model to be passed to a view with a@model
directive - Controllers can set
ViewData
K/V pairs which can be used in the Views through theViewData
dictionary. These models are not strongly typed.
Views
Views/_ViewStart.cshtml
brings in shared layouts to each view- Layout : Reduce duplicated code in views by specifying common structure in a webpage
- The default page is named
_Layout.cshtml
by convention
- The default page is named
- Views should avoid doing business logic or interacting with the db directly
View Model: Alternate way to prevent overposting
- Not the same as Data Transfer objects (DTO). View models encapsulate behaviour while DTOs cannot
- View models cannot be serialised unlike DTOs, so they are not used in SPAs
Models
- DbContext : Represents the unit of work
- KNOWS Entities that have been previously queried on it --> This can introduce bugs
- DbSet
Register DbContext with the dependency injection container
Foreign Keys:
- A One-To-One relationship requires:
- A primary key on the principal entity
- Optional: Reference navigation to principal
- By default, Id is the primary key
- A foreign key on the dependent entity
- Optional: Reference navigation to principal
- By default, EF makes a property as a foreign key when its name matches with the principal entity's primary key
- A primary key on the principal entity
- Use
[ForeignKey(name)
to override the default attribute for a foreign key
using System.ComponentModel.DataAnnotations.Schema;
public class Post { // principal
public int Id { get; set; }
public ICollection<Comment> Comments { get; set; } // One to many relationship with Comment
}
public class Comment { // dependent
public int Id { get; set; }
public int PostId { get; set; } // Reference to Post's PK makes this the foreign key
public Post Post { get; set; } // Reference navigation to principal
}
Conditions & DataAnnotation
Attributes on Entity attributes:
required
keyword : Used to prevent warning on uninitialized non-nullable values.- Many-to-one relationships: Uze
ICollection<>
- Can override
OnModelCreating
in your DbContext and do custom configuration with the fluent API [Comment("")]
[MaxLength(X)]
[Unicode]
configured as unicode by default[Column(Order = X)]
Default Values
[DatabaseGenerated(DatabaseGeneratedOption.Identity)]
value generated on inserted entities (On ANY INSERT)[DatabaseGenerated(DatabaseGeneratedOption.Computed)]
value generated on add or update- ^ is equvalent to:
modelBuilder.Entity<Blog>()
.Property(b => b.Rating)
.HasDefaultValue(3);
- EF Core doesn't specify a default way to set timestamps:
modelBuilder.Entity<Blog>()
.Property(b => b.Created)
.HasDefaultValueSql("getdate()");
- Computed values:
modelBuilder.Entity<Person>()
.Property(p => p.DisplayName)
.HasComputedColumnSql("[LastName] + ', ' + [FirstName]");
JSON Columns: Requires EF Core 7
Select:
_context.model.FirstOrDefaultAsync
: Select one or return defaultSingleOrDefaultAsync
: throw error if more than one (extra work unnecessary if you just select one)FindAsync
: Find entity with PK
Model validation:
- TODO: https://learn.microsoft.com/en-us/aspnet/core/mvc/models/validation?view=aspnetcore-7.0
- Encountering this error frequently?
Loading related data:
- Lazy loading by default --> Data is not retried until a navigation property is accessed
- Eager loading: Use
Include
andThenInclude
to read related classes in a larger, single query - Explicit loading: Use
Load
method to do explicit loading
Performance:
- Pagination
- Limiting number of fetched objects with
Take
Service Layer
WebAPI
- Data Transfer Object (DTO)