OfX .NET, distributed data mapping.
Trong quá trình triển khai hệ thống Microservices(MC), chắc hẳn anh em ko ít lần mệt mỏi với việc mapping data trong hệ thống MC. Đối với dự án nho nhỏ và cấu trúc dữ liệu đơn giản thì có thể không mất nhiều công sức lắm nhưng khi dự án lớn hơn và dữ liệu trở nên phức tạp thì việc mapping data sẽ trở nên mệt mỏi và chán nản. Nay em xin giới thiệu với anh em 1 package .NET giúp việc mapping data trở nên đơn giản và funy hơn nhiều ạ. Ví dụ trước là em có 1 response trông như thế này ạ:
public class MemberResponse
{
public string Id { get; set; }
public string UserId { get; set; }
public string UserName { get; set; }
public string UserEmail { get; set; }
public string UserProvinceId { get; set; }
public string ProvinceName {get; set;}
public string CountryName {get; set;}
}
Bối cảnh:
Member
nằm ở service Workspace
,
UserName
, UserEmail
và UserProvinceId
nằm ở service Identity
,
ProvinceName
và CountryName
nẳm ở service MasterData
.
Response trả về cho phía client là 1 array MemberResponse
.
Hồi xưa thì ban đầu mình sẽ get response từ service Member
ra được 1 array MemberResponse
. Xong đó mình sẽ collect 1 list UserIds
và lại gọi sang service Identity
để lấy Name, Email, UserProvinceId
. Xong đâu đó mình lại có 1 list UserProviceIds
và lại tiếp tục gọi sang MasterData
để lấy được thông tin ProvinceName
và CountryName
(đương nhiên CountryName
thì không nằm cùng bảng với ProvinceName
và có thể đó là phát sinh về business nên có khả năng mình phải coding thêm để lấy CountryName
vào request của GetProvinces...
) và rồi dữ liệu không chỉ như vậy, có thể phức tạp hơn rất nhiều...
Hồi trước em gặp bài toán này nên đã tạo ra 1 thư viện để giải quyết bài toán distributed mapping gọi là OfX
.
Vậy OfX
giải quyết bài toán này như thế nào?
Trước tiên quay lại với response phía trên với 1 chút custom nho nhỏ:
public class MemberResponse
{
public string Id { get; set; }
public string UserId { get; set; }
[UserOf(nameof(UserId))]
public string UserName { get; set; }
[UserOf(nameof(UserId), Expression = 'Email')]
public string UserEmail { get; set; }
[UserOf(nameof(UserId), Expression = 'ProvinceId')]
public string UserProvinceId { get; set; }
[ProvinceOf(nameof(UserProvinceId), Order = 1)]
public string ProvinceName {get; set;}
[ProvinceOf(nameof(UserProvinceId), Expression = "Country.Name", Order = 1)]
public string CountryName {get; set;}
}
OfX
sẽ đọc response của anh em xong đó graph lại những những Attribute
nào có cùng kiểu như là UserOfAttribute
, ProvinceOfAttribute
... xong đó collect lại ids và gọi sang service tương ứng để lấy dữ liệu và mapping lại Properties tương ứng.
Ngoài ra anh em sẽ thấy có thêm 1 cái là Order=1
ở đây là gì? Order = x
nghĩa là các Properties được gắn với order đó sẽ mapping theo thứ tự, ví dụ ở trên: UserName, UserEmail, UserProvinceId
sẽ được mapping trước. Xong đó ProvinceName và CountryName
sẽ được mapping sau. Vì sao lại như vậy? Anh em thấy là mình cần có ProvinceId
trước rồi mới có data để lấy dữ liệu của ProvinceName
và CountryName
đúng không ạ?
OfX
còn có thể mapping được cả Object
, Array Object
nữa. Về chi tiết thì mời anh em tham khảo qua repository: OfX.
Cách cấu hình OfX
cũng hết sức đơn giản.
Anh em chỉ cần Install OfX
core và Extension phù hợp với hệ thống anh em đang sử dụng. Hiện tại em đã support OfX.EntityFrameWorkCore
với DataProvider và OfX.gRPC, OfX.Nats, OfX.RabbitMq và OfX.Kafka
với Transports.
Dưới đây là cách cấu hình cơ bản với OfX, OfX-EFCore và OfX-Nats
để anh em tham khảo (các Package khác cấu hình tương tự, em có ghi trong readMe của từng Package).
Attributes
public sealed class UserOfAttribute(string propertyName) : OfXAttribute(propertyName);
public class ProvinceOfAttribute(string propertyName) : OfXAttribute(propertyName);
Note
: Anh em nên tạo Attributes
ở trong project Shared
hoặc Common
của anh em!
File Program.cs
builder.Services.AddOfX(cfg =>
{
cfg.AddAttributesContainNamespaces(typeof(WhereTheAttributeDefined).Assembly);
cfg.AddNats(config => config.Url("nats://localhost:4222"));
})
.AddOfXEFCore(options =>
{
options.AddDbContexts(typeof(TestDbContext));
options.AddModelConfigurationsFromNamespaceContaining<SomeModelAssemblyMarker>();
})
;
Models:
[OfXConfigFor<UserOfAttribute>(nameof(Id), nameof(Name))]
public class User
{
public string Id { get; set; }
public string Name { get; set; }
public string Email { get; set; }
public string ProvinceId {get; set;}
}
...
[OfXConfigFor<ProvinceOfAttribute>(nameof(Id), nameof(Name))]
public sealed class Province
{
public ProvinceId Id { get; set; }
public string Name { get; set; }
public CountryId CountryId { get; set; }
public Country Country { get; set; }
}
Vậy là xong rồi, anh em có thể tận hưởng kết quả rồi! Em có tạo 1 project demo và bên trong đó DTO response phức tạp hơn nhiều ạ. Mời anh em trải nghiệm: Repository: OfX. Link Demo: Demo.
All rights reserved