হ্যালো হাসিব! এই লেকচারে আমরা গত লেকচারে শুরু করা “Create Person” ফর্মটি সম্পূর্ণ করেছি। ফর্মের UI ফাইনাল করার পর, ইউজার যখন “Create” বাটনে ক্লিক করবে, তখন সার্ভার সাইডে কীভাবে ডাটা প্রসেস হবে, ভ্যালিডেশন কীভাবে চেক করা হবে এবং ডাটাবেসে (বা সার্ভিসে) সেভ করে কীভাবে রিডাইরেক্ট করা হবে, সেটাই বিস্তারিত দেখানো হয়েছে।

চলো প্রথমে লেকচারটির একটি কুইক সামারি দেখে নিই।

📌 Quick Summary for Revision

  • Form UI Completion: textarea, checkbox এবং “Create” (Submit) বাটন দিয়ে ফর্মের ডিজাইন সম্পূর্ণ করা।
  • POST Action Method: ফর্ম সাবমিট হওয়ার পর ডাটা রিসিভ করার জন্য PersonsController-এ [HttpPost] অ্যাট্রিবিউটসহ আরেকটি Create মেথড তৈরি করা।
  • Model Binding: PersonAddRequest অবজেক্টের মাধ্যমে ইউজারের দেওয়া ইনপুটগুলো সার্ভারে রিসিভ করা।
  • Model Validation: ModelState.IsValid চেক করে দেখা ডাটাগুলো ভ্যালিড কি না।
  • Error Handling: ভ্যালিডেশন ফেইল করলে ModelState থেকে এরর মেসেজগুলো এক্সট্রাক্ট করে ViewBag.Errors-এ সেভ করা এবং ফর্মটি পুনরায় রেন্ডার করা।
  • Data Insertion: ভ্যালিডেশন পাস করলে _personsService.AddPerson() কল করে ডাটা সেভ করা এবং RedirectToAction ব্যবহার করে Index ভিউতে ইউজারকে পাঠিয়ে দেওয়া।

🚀 Comprehensive Breakdown & The “Why”

নিচে লেকচারের প্রতিটি কনসেপ্ট বিস্তারিত এবং কারণসহ এক্সপ্লেইন করা হলো:

১. Form UI (Textarea & Checkbox) [Priority: 7/10]

The “Why”: Address-এর মতো বড় টেক্সট ইনপুট নেওয়ার জন্য <textarea> এবং Newsletters রিসিভ করার মতো হ্যাঁ/না অপশনের জন্য <input type="checkbox"> ব্যবহার করা হয়েছে। চেকবক্স চেক করা থাকলে সার্ভারে true সাবমিট হয়।

Implementation:

<textarea id="Address" name="Address" class="form-input"></textarea>
 
<input type="checkbox" id="ReceiveNewsLetters" name="ReceiveNewsLetters" value="true" />
<label for="ReceiveNewsLetters">Receive Newsletters</label>
 
<button class="button button-green-back">Create</button>
 

২. POST Action Method তৈরি করা [Priority: 10/10]

The “Why”: যখন ইউজার ফর্মে ডাটা দিয়ে “Create” বাটনে ক্লিক করে, তখন ব্রাউজার একটি POST রিকোয়েস্ট পাঠায়। আমাদের আগের Create মেথডটি শুধু GET রিকোয়েস্ট রিসিভ করতো (যা শুধু ফাঁকা ফর্ম দেখাতো)। তাই একই নামের আরেকটি মেথড বানাতে হবে যা POST রিকোয়েস্ট রিসিভ করবে এবং ডাটা সেভ করবে।

Implementation:

// PersonsController.cs
[Route("persons/create")]
[HttpPost] // এটি POST রিকোয়েস্ট রিসিভ করার জন্য
public IActionResult Create(PersonAddRequest personAddRequest) // Model Binding
{
    // ... logic here ...
}
 

৩. Model Validation এবং Error Handling [Priority: 10/10]

The “Why”: ইউজার ফর্মে ভুল ডাটা দিতে পারে (যেমন: নাম ফাঁকা রাখা, ইমেইল ফরমেট ভুল দেওয়া)। সার্ভার সাইডে এগুলো চেক করার জন্য MVC-এর ModelState.IsValid ব্যবহার করা হয়। যদি এটি false হয়, তার মানে ডাটায় ভুল আছে। তখন এরর মেসেজগুলো ধরে ইউজারকে আবার ফর্মটি দেখাতে হবে।

Implementation:

if (!ModelState.IsValid)
{
    // ১. Model State থেকে সব এরর মেসেজ কালেক্ট করা
    List<string> errorMessages = ModelState.Values
        .SelectMany(v => v.Errors)
        .Select(e => e.ErrorMessage)
        .ToList();
 
    // ২. এররগুলো ViewBag-এ রাখা
    ViewBag.Errors = errorMessages;
    
    // ৩. ড্রপডাউনের ডাটা আবার পাঠাতে হবে, নাহলে ফর্ম ক্র্যাশ করবে
    ViewBag.Countries = _countriesService.GetAllCountries();
 
    // ৪. ফর্মটি আবার ইউজারকে দেখানো
    return View(personAddRequest); 
}
 

View Implementation: (সাবমিট বাটনের নিচে এরর দেখানোর জন্য)

@if (ViewBag.Errors != null)
{
    <div class="text-red">
        <ul>
            @foreach (string error in ViewBag.Errors)
            {
                <li>@error</li>
            }
        </ul>
    </div>
}
 

৪. ডাটা সেভ করা এবং Redirect [Priority: 9/10]

The “Why”: যদি ModelState.IsValid সত্য (true) হয়, তার মানে ডাটা একদম ঠিক আছে। তখন আমরা সার্ভিসের মাধ্যমে ডাটা সেভ করবো এবং ইউজারকে Index পেজে পাঠিয়ে দেবো, যাতে সে টেবিলে তার নতুন ডাটা দেখতে পারে। এখানে RedirectToAction ব্যবহার করা হয় যা ব্রাউজারকে নতুন একটি GET রিকোয়েস্ট করতে বলে (PRG - Post/Redirect/Get pattern)।

Implementation:

// যদি ভ্যালিডেশন পাস করে
PersonResponse personResponse = _personsService.AddPerson(personAddRequest);
 
// Index মেথডে রিডাইরেক্ট করে দেওয়া
return RedirectToAction("Index", "Persons"); 
 

🆕 .NET 10 & Modern Approaches (Tag Helpers for Validation)

লেকচারে সার্ভার সাইড এররগুলো ম্যানুয়ালি LINQ দিয়ে ফিল্টার করে ViewBag.Errors-এ রাখা হয়েছে এবং foreach লুপ চালিয়ে দেখানো হয়েছে। মডার্ন MVC-তে এটি করার কোনো দরকারই নেই! Validation Summary Tag Helper এই কাজগুলো অটোমেটিক করে দেয়।

Modern Approach (No ViewBag.Errors needed!):

// Controller (Modern Approach)
if (!ModelState.IsValid)
{
    ViewBag.Countries = _countriesService.GetAllCountries();
    return View(personAddRequest); // Error ফিল্টার করার দরকার নেই!
}
 
<div asp-validation-summary="All" class="text-red"></div>
 
<span asp-validation-for="PersonName" class="text-red"></span>
 

⌨️ IDE Shortcuts (Debugging Flow)

লেকচারার Debugging করার সময় কিছু স্টেপ দেখিয়েছেন, তার শর্টকাটগুলো হলো:

  • Step Over (F10): এটি কোডকে পরবর্তী লাইনে নিয়ে যায়, কিন্তু কোনো মেথড কল থাকলে তার ভেতরে ঢোকে না।
  • Step Into (F11): এটি কোনো মেথডের ভেতরের লজিক দেখতে চাইলে মেথডের ভেতরে ঢুকে যায়।
  • Step Out (Shift + F11): মেথডের ভেতর থেকে বের হয়ে আসতে চাইলে এটি ব্যবহার করা হয়।

💡 Best Practices (Create/Insert Operations)

১. PRG Pattern (Post/Redirect/Get): যখনই কোনো ফর্ম সাবমিট (POST) করে ডাটা সেভ করা হয়, কখনোই return View() দিয়ে সাকসেস পেজ দেখানো উচিত নয়। সব সময় return RedirectToAction() ব্যবহার করা উচিত। নাহলে ইউজার পেজ রিফ্রেশ করলে ব্রাউজার আবার ডাটা সাবমিট (Duplicate Entry) করার চেষ্টা করে। লেকচারার এটি সঠিকভাবে ফলো করেছেন। ২. Repopulate Dropdowns: যদি ভ্যালিডেশন ফেইল করে এবং ফর্মটি পুনরায় রেন্ডার করতে হয় (return View), তবে ড্রপডাউনের ডাটাগুলো (ViewBag.Countries) অবশ্যই আবার লোড করে পাঠাতে হবে, নাহলে View-তে ড্রপডাউন জেনারেট হওয়ার সময় Null Reference Exception খাবে। ৩. Client-Side Validation: লেকচারের শেষে বলা হয়েছে, ফর্ম সাবমিট করে সার্ভারে গিয়ে এরর ধরার চেয়ে ইউজারের ব্রাউজারেই (JavaScript দিয়ে) আগে ভ্যালিডেশন করা বেস্ট। পরবর্তী লেকচারগুলোতে এটি দেখানো হবে।

Create Person-এর সম্পূর্ণ ফ্লো তো আমরা শিখে নিলাম। এরপর কি আমরা Client-Side Validation-এর লেকচারে যাবো, নাকি Edit/Update পেজ তৈরি করবো?