Models in ASP.NET Core MVC
Understanding and effectively using models is fundamental to building robust and maintainable ASP.NET Core MVC applications.
In the Model-View-Controller (MVC) architectural pattern, the **Model** represents the application's data and the business logic that operates on that data. It's the core of your application's intelligence.
Purpose of Models
The primary purposes of models in an MVC application are:
- Encapsulating Data: Models hold the raw data your application works with. This could be data fetched from a database, external API, or simply configuration settings.
- Implementing Business Logic: They contain the rules, calculations, and operations that define how the data can be manipulated and what constitutes valid states.
- Separation of Concerns: By separating data and logic from the user interface (View) and the request handling (Controller), models promote cleaner, more organized, and testable code.
Data Representation
Models are typically represented as plain old C# objects (POCOs) or classes that map directly to database tables (entities) or data transfer objects (DTOs).
For example, a simple `Product` model might look like this:
public class Product
{
public int Id { get; set; }
public string Name { get; set; }
public decimal Price { get; set; }
public string Description { get; set; }
}
Business Logic
Business logic resides within the model. This logic dictates how data is processed, transformed, or validated. It's the "brains" of your application.
Consider a `Product` model with logic to determine if it's on sale:
public class Product
{
public int Id { get; set; }
public string Name { get; set; }
public decimal Price { get; set; }
public decimal DiscountPercentage { get; set; }
public bool IsOnSale => DiscountPercentage > 0;
public decimal SalePrice
{
get
{
if (IsOnSale)
{
return Price * (1 - DiscountPercentage / 100);
}
return Price;
}
}
}
Validation
Models are also responsible for enforcing data integrity. This is achieved through validation. ASP.NET Core provides built-in data annotation attributes for common validation rules.
using System.ComponentModel.DataAnnotations;
public class Product
{
public int Id { get; set; }
[Required(ErrorMessage = "Product name is required.")]
[StringLength(100, ErrorMessage = "Product name cannot exceed 100 characters.")]
public string Name { get; set; }
[Range(0.01, 10000.00, ErrorMessage = "Price must be between 0.01 and 10000.00.")]
public decimal Price { get; set; }
[StringLength(500)]
public string Description { get; set; }
}
These attributes can be used by model binders and the validation framework to automatically validate incoming data.
View Models vs. Domain Models
It's common to distinguish between Domain Models (representing core business entities) and View Models (tailored specifically for a particular view).
- Domain Models: Represent the actual business entities and often contain the full set of business logic. They might include data that isn't needed by a specific view, or have complex relationships.
- View Models: Are DTOs designed to deliver exactly the data needed by a particular view, in the format that view expects. They can flatten complex domain models or combine data from multiple sources.
Using View Models helps to decouple your views from your core domain logic and ensures that only necessary data is passed to the client.
Creating Models
To create a model in ASP.NET Core MVC:
- Create a new C# class file.
- Define properties for the data you want to represent.
- Add any necessary business logic or validation attributes.
- (Optional) Create separate View Models for specific views.
Example: Product Model
Here's a more complete example of a `Product` model with validation attributes:
using System.ComponentModel.DataAnnotations;
namespace MsdnLearn.Models
{
public class Product
{
public int ProductId { get; set; }
[Required(ErrorMessage = "Please enter the product name.")]
[Display(Name = "Product Name")]
[StringLength(100)]
public string Name { get; set; }
[Required(ErrorMessage = "Please enter the price.")]
[Display(Name = "Price")]
[DataType(DataType.Currency)]
[Range(0.01, 100000.00, ErrorMessage = "Price must be between 1 cent and 100,000 dollars.")]
public decimal Price { get; set; }
[StringLength(1000)]
[Display(Name = "Description")]
public string Description { get; set; }
[Display(Name = "In Stock")]
public bool IsAvailable { get; set; } = true;
}
}
Data Access Layer Interaction
Models themselves typically don't directly interact with the database. This responsibility is usually handled by a separate Data Access Layer (DAL), often implemented using Entity Framework Core or other ORMs. The Controller orchestrates the interaction, fetching data using the DAL and passing it to the Model, or saving Model data via the DAL.
For instance, a controller might:
- Receive a request to view product details.
- Use a repository or DbContext to fetch a `Product` object from the database.
- Pass this `Product` object to a View.