Cách thêm model vào dự án ASP.NET Core
Các từ ngữ kỹ thuật giúp chúng ta giao tiếp trong cộng đồng của mình một cách hiệu quả và chính xác hơn nhưng có mặt trái là gây khó khăn cho người mới. Vì vậy, điều cần thiết là phải làm rõ các thuật ngữ có nghĩa là gì trong một miền nhất định.
Trong bài viết này, chúng ta sẽ khám phá ý nghĩa của các nhà phát triển khi sử dụng tên ** Model ** trong ngữ cảnh của ASP.NET Core và các sub-framework khác nhau của nó như ASP.NET Core MVC, Razor Pages, Endpoints và Blazor.
Nếu bạn là người mới bắt đầu, bạn sẽ học mọi thứ bạn cần biết về Model và làm việc với các chuyên gia ngay lập tức. Bắt đầu nào.
Model là gì?
Trong ngăn xếp .NET, thuật ngữ Model đề cập đến bất kỳ đối tượng nào trong ứng dụng của chúng ta đại diện cho một thực thể logic trong miền của chúng ta. Thuật ngữ chính xác của ** Model ** bắt nguồn từ mẫu thiết kế phần mềm được gọi là MVC hoặc Model-View-Controller.
Model là cấu trúc dữ liệu động của ứng dụng, độc lập với giao diện người dùng. Nó trực tiếp quản lý dữ liệu, logic và các quy tắc của ứng dụng. – WIKIPEDIA
Như đã nêu trong định nghĩa Wikipedia, Model thường chịu trách nhiệm về các thay đổi trạng thái và các quy tắc logic nghiệp vụ. Định nghĩa model có thể bao gồm từ các đối tượng C# cũ (POCO) đến các kiểu dữ liệu được liên kết với các framework truy cập dữ liệu như Entity Framework.
Quy tắc chung cho Model là nó tồn tại bên trong trong ngữ cảnh ứng dụng của chúng ta và quyền truy cập trực tiếp của người dùng bị giới hạn bởi layer giao diện người dùng. Các layer giao diện người dùng bao gồm nhưng không giới hạn ở các layer HTTP API, các lệnh gọi HTML và HTTP và các interface hệ điều hành gốc.
Thêm model vào dự án ASP.NET Core MVC
Như đã đề cập trước đây, thuật ngữ Model là không thể thiếu với mẫu MVC. Bắt đầu một ứng dụng ASP.NET Core MVC mới, chúng ta được giới thiệu với cấu trúc thư mục với vị trí được đề xuất để đặt các định nghĩa model của chúng ta.
|- Controllers
|- Models
|- Views
Trong thư mục Models
, chúng ta có thể tạo định nghĩa lớp mới trực tiếp tại thư mục gốc hoặc trong một thư mục lồng nhau mới.
Hãy thêm một model Person
mới. Trong trường hợp này, chúng ta không ràng buộc nó với cơ chế truy cập dữ liệu, nhưng nếu bạn muốn làm như vậy, vui lòng đọc các bài đăng liên quan đến Entity Framework khác của tôi hoặc đặt câu hỏi bên dưới trong phần nhận xét.
namespace WebApplication.Models
{
public class Person
{
public int Id { get; set; }
public string Name { get; set; }
}
}
Cuối cùng, chúng ta có thể sử dụng model Person
mới của mình trong một action method của Controller
. Trong ví dụ sau, chúng ta truyền model mới được tạo vào phương thức View
, điều này sẽ cho phép chúng ta sử dụng model để hiển thị thông tin cho phía máy khách.
public IActionResult Index()
{
var model = new Person
{
Id = 1,
Name = "Trung Nguyen"
}
return View(model);
}
Sự khác biệt giữa Models và ViewModels là gì?
Các nhà phát triển ASP.NET Core mới có thể nhận thấy class ErrorViewModel
trong thư mục Models
của ứng dụng của họ. Câu hỏi trước mắt có thể là:
ViewModel là gì và nó khác với Model như thế nào?
Câu hỏi tuyệt vời! Cả Model và ViewModel đều là các định nghĩa trong miền ứng dụng của chúng ta. Sự khác biệt giữa hai loại là mục đích dự định của chúng.
Như đã đề cập trong phần trước, Model có thể có các logic và quản lý trạng thái, và chúng ta có thể coi đó là các hoạt động hiển thị. Các hoạt động có thể bao gồm gọi cơ sở dữ liệu, dịch vụ của bên thứ ba hoặc truy cập I/O chung.
Trong khi đó, ViewModel chỉ hiển thị dữ liệu hoặc logic hoạt động trên các thuộc tính hiện có trong instance của nó. Chúng ta cũng có thể nghe thấy ViewModel được so sánh với Đối tượng truyền dữ liệu (Data Transfer Objects – DTO), một đối tượng dùng để chuyển thông tin từ vị trí này sang vị trí khác, thường là phép chiếu của dữ liệu hiện có được truy xuất từ một model. Class ErrorViewModel
là một ví dụ tuyệt vời của cách tiếp cận này.
public class ErrorViewModel
{
public string RequestId { get; set; }
public bool ShowRequestId => !string.IsNullOrEmpty(RequestId);
}
Chúng ta có thể thấy rằng trong ViewModel này, chúng ta có một thuộc tính RequestId
và một thuộc tính read-only ShowRequestId
đóng gói một logic cơ bản.
Thường có sự phân biệt rõ ràng giữa Model và ViewModel, nhưng giống như hầu hết mọi thứ trong cuộc sống, một số cơ sở mã có thể kéo dài các định nghĩa này để giải quyết các vấn đề theo nhu cầu. Việc hiểu các định nghĩa này cho phép chúng ta thử nghiệm và tinh chỉnh Model và ViewModel trong các giải pháp của chúng ta.
Thêm Model vào Razor Pages
Các Model hơi mù mờ trong các ứng dụng dựa trên Razor Pages. Bắt đầu một ứng dụng Razor Pages mới, chúng ta sẽ nhận thấy cấu trúc thư mục khác với ứng dụng ASP.NET Core MVC của chúng ta. Chúng ta thấy chỉ có một thư mục Pages
.
Tại đây, chúng ta có thể quyết định hành động cụ thể của mình. Chúng ta có thể coi thư mục Pages như là thư mục Models hoặc hoàn toàn đi theo một cách tiếp cận khác có thể tạo một thư mục mới có tên Models
như chúng ta đã có trong ứng dụng dựa trên MVC của mình.
Một nguyên tắc chung vẫn là tạo một thư mụcModels
và thêm các model của chúng ta vào đó để tách biệt với các PageModel
củaRazor Pages. Ngoài ra, chúng ta có thể coi Razor Pages của mình là ViewModel, ngoại trừ việc PageModel của chúng ta có thể có các logic để xử lý các giá trị thuộc tính từ các Model của chúng ta.
Để thêm một Model mới vào ứng dụng Razor Pages, trước tiên chúng ta cần tạo thư mục Models
, sau đó chúng ta có thể thêm các class của mình. Cách tiếp cận này là cần thiết khi xử lý các thư viện truy cập dữ liệu như Entity Framework hoặc Dapper.
Trong ví dụ này, chúng ta đã thêm model Person
vào trong dự án của chúng ta và sử dụng nó ở IndexPageModel
.
Lưu ý: PageModel
có thuộc tính Name
, nó được gán giá trị cho mọi yêu cầu tới trang. Nhìn vào ví dụ MVC ở trên, bạn có thể nhận thấy sự giống nhau. Trong trường hợp Razor Pages, chúng ta có thể nghĩ đến phần VC của MVC do PageModel xử lý.
public class IndexModel : PageModel
{
private readonly ILogger<IndexModel> _logger;
private readonly Person _person;
public string Name { get; set; }
public IndexModel(ILogger<IndexModel> logger, Person person)
{
_logger = logger;
_person = person;
}
public void OnGet()
{
Name = _person.Name;
}
}
Razor Pages tạo ra một tình huống mà chúng ta có thể đạt được rất nhiều, nếu không muốn nói là tất cả mọi thứ, trong một trang duy nhất.
Các cách tiếp cận chỉ dựa vào PageModel
có thể vừa có lợi vừa có vấn đề:
- Các lợi ích bao gồm logic tập trung, cơ sở mã nhỏ hơn và triển khai đơn giản.
- Các vấn đề bao gồm code liên kết chặt chẽ, trùng lặp code và tiềm ẩn phình to code.
Một lần nữa, chúng ta phải đánh giá vấn đề đang giải quyết và tính đến các mục tiêu trong tương lai.
Thêm Model vào ASP.NET Core Endpoints
ASP.NET Core đã chứng kiến một sự phát triển đối với cơ sở hạ tầng định tuyến của nó, chủ yếu được tách ra khỏi ASP.NET Core MVC và hoạt động độc lập với bất kỳ framework nào.
Trong các phiên bản mới nhất của ASP.NET Core, chúng ta có thể ánh xạ trực tiếp các endpoint vào cơ sở hạ tầng định tuyến. Cách tiếp cận này có sự đánh đổi, với ý tưởng về các HTTP endpoint chuyên biệt ưu tiên hiệu suất hơn là tính linh hoạt và mạnh mẽ của MVC, có thể làm tăng thêm chi phí hoạt động.
Giống như Razor Pages, chúng ta có thể tự do lựa chọn cách tiếp cận để thêm Model vào giải pháp của mình. Tuy nhiên, một nguyên tắc chung là tạo thư mục Models
và thêm các model của chúng ta vào đó. Hãy làm việc với model Person
một lần nữa, nhưng bây giờ trong một endpoint được đăng ký bằng cách sử dụng MapGet
.
Hãy nhớ đăng ký bất kỳ model nào được truy xuất thông qua RequestServices
vào dependency injection container của ASP.NET Core trong phương thứcConfigureServices
được tìm thấy trong classStartup
.
app.UseEndpoints(endpoints =>
{
endpoints.MapGet("/", async (context) =>
{
var person = context.RequestServices.GetService<Person>();
await context.Response.WriteAsJsonAsync(new
{
greetings = $"Hello, {person.Name}"
});
});
});
Ở đây, chúng ta có thể bị cám dỗ để trả lại model Person
của mình bằng cách chuyển nó đến phương thức WriteAsJsonAsync
. Hãy nhớ rằng, Model nói chung có các logic nội bộ được liên kết với chúng và việc trả lại chúng trực tiếp sẽ vô tình làm rò rỉ thông tin nhạy cảm. Tốt hơn là dựa vào DTO và cân nhắc kỹ lưỡng với những gì chúng ta gửi cho phía máy khách.
Thêm Model vào Blazor phía máy chủ
Mô hình phát triển ứng dụng máy chủ Blazor tương tự như của Razor Pages. Thay vì xử lý các kiểu PageModel
, bây giờ chúng ta xử lý các component Blazor. Các tệp này rất dễ phân biệt vì chúng có phần mở rộng là .razor
trong giải pháp của chúng ta.
Không giống như Razor Pages, các ứng dụng Blazor bắt đầu bằng thư mục Data
, nơi chúng ta có thể thêm Model của mình. Mẫu Blazor mặc định bắt đầu với hai class trong thư mục Data
: WeatherForecast
và WeatherForecastService
.
public class WeatherForecast
{
public DateTime Date { get; set; }
public int TemperatureC { get; set; }
public int TemperatureF => 32 + (int) (TemperatureC / 0.5556);
public string Summary { get; set; }
}
public class WeatherForecastService
{
private static readonly string[] Summaries = new[]
{
"Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching"
};
public Task<WeatherForecast[]> GetForecastAsync(DateTime startDate)
{
var rng = new Random();
return Task.FromResult(Enumerable.Range(1, 5).Select(index => new WeatherForecast
{
Date = startDate.AddDays(index),
TemperatureC = rng.Next(-20, 55),
Summary = Summaries[rng.Next(Summaries.Length)]
}).ToArray());
}
}
Trong tệp FetchData.razor
, chúng ta sử dụng model này trong khối @code
của chúng ta. Dưới đây, chúng ta có thể thấy ASP.NET Core truyền model WeatherForecastService
vào component Blazor. Tôi đã loại trừ mã HTML cho ngắn gọn.
@page "/fetchdata"
@using WebApplication2.Data
@inject WeatherForecastService ForecastService
// HTML goes here
@code {
private WeatherForecast[] forecasts;
protected override async Task OnInitializedAsync()
{
forecasts = await ForecastService.GetForecastAsync(DateTime.Now);
}
}
Tương tự như Razor Pages, các component của chúng ta hoạt động như một sự kết hợp của VC trong mẫu MVC. Chúng ta có thể làm được nhiều thứ trong khối @code
nhưng chúng ta nên giữ hầu hết các quy tắc và logic trong Model. Như mọi khi, yêu cầu của các vấn đề sẽ giúp chúng ta xác định cách tốt nhất để thực hiện khi làm việc với Blazor.
Phần kết luận
Các nhà phát triển không dễ dàng khi chọn cách tiếp cận với ASP.NET Core. Chúng ta có nhiều lựa chọn, từ các framework mạnh mẽ như ASP.NET Core MVC, Razor Pages và Blazor, đến các chiến lược hướng hiệu suất đơn giản như Endpoints.
Chúng ta nên nhớ rằng Model chỉ là một khái niệm hơn là một quy tắc cố định. Bài đăng này phác thảo các cách tiếp cận phổ biến để thêm model, nhưng mã rất linh hoạt và chúng ta có thể đánh giá lại các lựa chọn của mình dựa trên nhu cầu của chúng ta.
Trên thực tế, không có “đúng-sai” khi tạo thư mục Models để chứa các model của chúng ta, nhưng nó sẽ giúp hiểu được nơi chúng ta có thể muốn thêm chúng khi phạm vi ứng dụng của chúng ta phát triển.
Tôi hy vọng bạn thích bài viết này và nếu bạn là người mới bắt đầu học ASP.NET Core lần đầu tiên, vui lòng theo dõi blog của tôi.