হাসিব, তোমার দেওয়া লেকচার ট্রান্সক্রিপ্টটির বিস্তারিত বিশ্লেষণ নিচে দেওয়া হলো। এই লেকচারে Model Validation-এর বেশ কিছু গুরুত্বপূর্ণ এবং বহুল ব্যবহৃত Attributes (যেমন: [RegularExpression], [EmailAddress], [Compare]) নিয়ে আলোচনা করা হয়েছে।
📝 Quick Summary for Revision
ভবিষ্যতে দ্রুত রিভিশন দেওয়ার জন্য লেকচারের মূল পয়েন্টগুলো নিচে লিস্ট করা হলো:
[RegularExpression]: নির্দিষ্ট কোনো প্যাটার্ন (Pattern) চেক করার জন্য। যেমন: শুধু Alphabet, নির্দিষ্ট কোনো Zip Code বা Custom Format।[EmailAddress]&[Phone]: Email এবং Phone number ভ্যালিডেট করার জন্য ফ্রেমওয়ার্কের বিল্ট-ইন Attributes, এগুলোর জন্য কষ্ট করে Regex লেখার প্রয়োজন নেই।[Compare]: Model-এর দুটি Property-র ভ্যালু সমান কি না তা চেক করার জন্য (যেমন: Password এবং Confirm Password ম্যাচ করা)।[Url]: কোনো ইনপুট ভ্যালিড Website Address বা লিংক কি না তা নিশ্চিত করতে ব্যবহৃত হয়।[ValidateNever]: নির্দিষ্ট কোনো Property-র ওপর থেকে Model Validation সাময়িকভাবে বা পুরোপুরি বন্ধ রাখার জন্য এটি ব্যবহার করা হয়।
🧠 Comprehensive Breakdown
এখানে লেকচারের প্রতিটি কনসেপ্ট বিস্তারিতভাবে এবং সহজবোধ্যভাবে ব্যাখ্যা করা হলো।
1. Custom Patterns with [RegularExpression] [Priority: 9/10]
Why do we need this?
অনেক সময় আমাদের স্পেসিফিক রিকোয়ারমেন্ট থাকে, যেমন— “Person Name-এ শুধু লেটার (A-Z) থাকতে পারবে, কোনো সংখ্যা বা স্পেশাল ক্যারেক্টার থাকা যাবে না।” এই ধরনের কাস্টম প্যাটার্ন ম্যাচ করানোর জন্য [RegularExpression] ব্যবহার করা হয়।
How it works:
Regex-এর প্যাটার্ন সাধারণত ^ (Start) দিয়ে শুরু হয় এবং $ (End) দিয়ে শেষ হয়। মাঝখানে [] এর ভেতরে আমরা বলে দিই কোন কোন ক্যারেক্টার অ্যালাউড।
public class Person
{
// ^[a-zA-Z \.]*$ means:
// a-z : All lowercase letters
// A-Z : All uppercase letters
// \. : Dot symbol
// space : Space character
// * : Zero or more times
[RegularExpression(@"^[a-zA-Z \.]*$", ErrorMessage = "{0} should contain only alphabets, space, and dot.")]
public string? PersonName { get; set; }
}
এখানে ইউজার যদি “Hasib 123” বা “Hasib$” ইনপুট দেয়, তবে সেটি Invalid হিসেবে ট্রিট হবে এবং Error Message রিটার্ন করবে।
2. Built-in Format Attributes: [EmailAddress], [Phone], [Url] [Priority: 10/10]
Why do we need this? তুমি চাইলে Email বা Phone number-এর জন্যও অনেক বড় Regular Expression লিখতে পারো। কিন্তু এগুলো এত বেশি ব্যবহৃত হয় যে, ফ্রেমওয়ার্ক নিজেই এগুলোর জন্য আলাদা Attribute বানিয়ে রেখেছে।
[EmailAddress]: ইনপুটটিতে@এবং একটি ভ্যালিড ডোমেইন আছে কি না তা চেক করে।[Phone]: এটি একটি ভ্যালিড ফোন নাম্বার কি না তা যাচাই করে।[Url]: ইনপুটটিhttp://বাhttps://সহ ভ্যালিড ওয়েব এড্রেস কি না তা চেক করে।
public class Person
{
[Required]
[EmailAddress(ErrorMessage = "Please provide a valid email address.")]
public string? Email { get; set; }
[Phone(ErrorMessage = "Invalid phone number format.")]
public string? Phone { get; set; }
[Url(ErrorMessage = "Please provide a valid website link.")]
public string? Website { get; set; }
}
3. Matching Fields with [Compare] [Priority: 10/10]
Why do we need this?
Registration ফর্মে প্রায়ই “Password” এবং “Confirm Password” ফিল্ড থাকে। এই দুটি ফিল্ডের ডেটা হুবহু এক কি না, তা ব্যাকএন্ডে চেক করার জন্য [Compare] Attribute ব্যবহার করা হয়।
Index Positioning in Error Message:
{0}= Current Property (যেই প্রোপার্টির ওপর Attribute বসানো হয়েছে)।{1}= Target Property (যার সাথে তুলনা করা হচ্ছে)।
public class Person
{
[Required]
public string? Password { get; set; }
[Required]
[Display(Name = "Re-enter Password")]
// Comparing "ConfirmPassword" with the "Password" property
[Compare("Password", ErrorMessage = "{0} and {1} do not match.")]
public string? ConfirmPassword { get; set; }
}
// Output Error if mismatched: "Re-enter Password and Password do not match."
4. Disabling Validation with [ValidateNever] [Priority: 6/10]
Why do we need this?
কখনো কখনো আমাদের এমন কিছু Property থাকে, যেগুলোতে আমরা Model Validation অ্যাপ্লাই করতে চাই না (হতে পারে টেস্টিংয়ের জন্য বা নির্দিষ্ট কোনো লজিকের কারণে)। তখন ওই Property-র ওপর [ValidateNever] বসিয়ে দিলে Model Binding-এর সময় ফ্রেমওয়ার্ক ওই ফিল্ডের Validation স্কিপ করে যায়।
এটি ব্যবহার করতে হলে Microsoft.AspNetCore.Mvc.ModelBinding.Validation Namespace ইমপোর্ট করতে হয়।
using Microsoft.AspNetCore.Mvc.ModelBinding.Validation;
public class Person
{
[ValidateNever] // Validation will be completely ignored for this property
public string? OptionalReference { get; set; }
}
5. Mindset Shift: Developer vs. User [Priority: 4/10]
লেকচারের মাঝখানে ইন্সট্রাক্টর একটি চমৎকার পয়েন্ট বলেছেন। যখন তুমি Postman বা ব্রাউজার থেকে API-তে রিকোয়েস্ট পাঠাচ্ছো, তখন নিজেকে User হিসেবে চিন্তা করবে (কীভাবে ভুল ইনপুট দেওয়া যায়)। আর যখন Visual Studio বা VS Code-এ কোড লিখছো, তখন নিজেকে Developer হিসেবে চিন্তা করবে (কীভাবে ওই ভুলগুলো আটকানো যায়)।
(VS Code Shortcut: VS Code-এ দ্রুত কোড কমেন্ট/আনকমেন্ট করার জন্য Ctrl + / ব্যবহার করতে পারো, যা এই ধরনের টেস্টিংয়ের সময় খুব কাজে দেয়।)
🚀 Best Practices & .NET 10 Updates
যেহেতু তুমি .NET ইকোসিস্টেম নিয়ে কাজ করছো, তাই বর্তমান ইন্ডাস্ট্রির বেস্ট প্র্যাকটিস এবং .NET 10-এর আধুনিক ব্যবহার জেনে রাখা উচিত:
**1. Best Practice: DTOs (Data Transfer Objects) instead of [ValidateNever]**
ইন্ডাস্ট্রিতে এখন [ValidateNever] খুব একটা ব্যবহার করা হয় না। এর বদলে আমরা DTO (Data Transfer Object) প্যাটার্ন ব্যবহার করি। ইউজার থেকে যে ডেটাগুলো আসবে, শুধু সেগুলোর জন্যই একটি আলাদা ক্লাস (যেমন: PersonRegistrationRequestDto) তৈরি করা হয়। যে ডেটা দরকার নেই, সেটি DTO-তেই রাখা হয় না। এর ফলে [ValidateNever] ব্যবহার করার ঝামেলা থাকে না এবং কোড অনেক সিকিউর হয়।
2. Modern C# 13 + .NET 10: Using Record Types for DTOs
C# 13 এবং .NET 10-এ Immutable ডেটা ট্রান্সফারের জন্য class-এর বদলে record টাইপ বেশি প্রেফার করা হয়। Records অনেক লাইটওয়েট এবং Minimal API-র সাথে দারুণ কাজ করে।
using System.ComponentModel.DataAnnotations;
// Using C# 13 Record for DTO
public record PersonRegistrationDto(
[Required]
[RegularExpression(@"^[a-zA-Z \.]*$")]
string PersonName,
[Required]
[EmailAddress]
string Email,
[Required]
string Password,
[Compare(nameof(Password), ErrorMessage = "Passwords do not match")]
string ConfirmPassword
);
// Minimal API in .NET 10
app.MapPost("/api/register", (PersonRegistrationDto request) =>
{
// Minimal APIs automatically validate the Data Annotations and return 400 Bad Request if invalid!
return Results.Ok($"Registered user: {request.PersonName}");
});
Note: এখানে হার্ডকোড করে স্ট্রিং "Password" লেখার বদলে nameof(Password) ব্যবহার করা হয়েছে। এটি একটি বেস্ট প্র্যাকটিস, কারণ ভবিষ্যতে প্রোপার্টির নাম পরিবর্তন করলে এটি অটোমেটিকভাবে আপডেট হয়ে যায় এবং টাইপিং মিসটেক হওয়ার ভয় থাকে না।
লেকচারের শেষে ইন্সট্রাক্টর বলেছেন যে, এই বিল্ট-ইন Attributes দিয়ে প্রোজেক্টের ৯০% ভ্যালিডেশন হয়ে যায়। বাকি ১০% কমপ্লেক্স লজিকের জন্য Custom Validation Attributes লিখতে হয়, যা তুমি পরবর্তী লেকচারে দেখতে পাবে।