হাসিব, চলো তোমার কোর্সের ৯৪ নম্বর লেকচারটি নিয়ে বিস্তারিত আলোচনা করি। আউটলাইন অনুযায়ী এটি (Section 8: Views - MVC Architecture Pattern) এর অংশ, যার শিরোনাম “ViewData - Part 1”। আগের লেকচারে আমরা Html.Raw দেখেছি, আর এর পরের টপিক হলো ViewData-র Part 2। এই লেকচারে মূলত Controller থেকে View-তে ডেটা পাঠানোর সবচেয়ে প্রাথমিক পদ্ধতি বা মাধ্যম নিয়ে আলোচনা করা হয়েছে।

নিচে পুরো লেকচারটির বিস্তারিত ব্রেকডাউন দেওয়া হলো:

📝 Summary (সারসংক্ষেপ)

  • The Core Concept: MVC প্যাটার্নের নিয়ম অনুযায়ী View-এর ভেতরে কখনো ডেটা তৈরি বা ইনিশিয়ালাইজ করতে হয় না। Controller ডেটা সাপ্লাই দেবে, আর View তা রিসিভ করে শুধু দেখাবে।
  • What is ViewData? Controller থেকে View-তে ডেটা ট্রান্সফার করার একটি বিল্ট-ইন মেকানিজম বা ডিকশনারি অবজেক্ট হলো ViewData।
  • How it works: এটি C#-এর Dictionary-এর মতো কাজ করে। এটি Key-Value pair আকারে ডেটা স্টোর করে (যেখানে Key হলো string এবং Value হলো object)।
  • Casting Requirement: যেহেতু ViewData সব ডেটাকে object টাইপ হিসেবে সেভ করে, তাই View-তে সেই ডেটা (বিশেষ করে Collection বা Complex object) রিড করার সময় ম্যানুয়ালি Typecast করতে হয়।

📌 MVC Golden Rule: Controller Supplies, View Uses [Priority: 10/10]

লেকচারের শুরুতেই ইনস্ট্রাক্টর একটি অত্যন্ত গুরুত্বপূর্ণ প্রশ্ন করেছেন: View (.cshtml) এর ভেতরে ভ্যারিয়েবল বা কালেকশন ইনিশিয়ালাইজ করা কি ঠিক? উত্তর: না, একদমই না।

Why? (কেন?) MVC (Model-View-Controller) আর্কিটেকচারের মূল ভিত্তি হলো Separation of Concerns।

  • Controller: লজিক প্রসেস করবে, ডাটাবেজ থেকে ডেটা আনবে এবং সব রেডি করে View-কে পাঠাবে।
  • View: শুধু এবং শুধুমাত্র ডেটা রেন্ডার (প্রদর্শন) করবে।

কিন্তু Controller কীভাবে View-কে ডেটা পাঠাবে? এটার জন্য ASP.NET Core-এ কয়েকটি মেকানিজম আছে। তার মধ্যে সবচেয়ে বেসিক হলো ViewData


📌 What is ViewData? [Priority: 10/10]

ViewData হলো ControllerBase ক্লাসের একটি বিল্ট-ইন প্রোপার্টি। এর ডেটা টাইপ হলো ViewDataDictionary।

  • এটি মূলত একটি Dictionary of Key-Value pairs
  • এর Key সব সময় string টাইপের হয়।
  • এর Value সব সময় object টাইপের হয় (যার মানে তুমি এখানে string, int, List, Object যেকোনো কিছু রাখতে পারবে)।
  • Controller-এ তুমি ViewData-তে যা কিছু অ্যাড করবে, View-তে হুবহু সেই একই ViewData অবজেক্ট অ্যাক্সেস করতে পারবে।

📌 Step 1: Sending Data from Controller [Priority: 9/10]

ইনস্ট্রাক্টর আগের লেকচারের View-তে থাকা সব ডেটা কাট করে Controller-এ নিয়ে এসেছেন। চলো দেখি Controller-এর কোড কেমন হবে:

// Controllers/HomeController.cs
using Microsoft.AspNetCore.Mvc;
using MyWebApp.Models; // Person মডেল ইমপোর্ট করা হলো
 
public class HomeController : Controller
{
    public IActionResult Index()
    {
        // ১. সাধারণ String ডেটা 
        ViewData["AppTitle"] = "My ASP.NET Core Application";
 
        // ২. Complex Data / Collection
        List<Person> people = new List<Person>
        {
            new Person { Name = "Hasib", Gender = "Male" },
            new Person { Name = "John", Gender = "Male" }
        };
 
        // Collection-টিকে ViewData-তে স্টোর করা হচ্ছে
        ViewData["People"] = people;
 
        return View();
    }
}
 

কিভাবে কাজ করছে?

  • ViewData[“AppTitle”] এ আমরা একটি সাধারণ string রাখলাম। এখানে “AppTitle” হলো Key।
  • ViewData[“People”] এ আমরা পুরো List কালেকশনটি রেখে দিলাম।

📌 Step 2: Reading Data in View [Priority: 10/10]

Controller থেকে পাঠানো ডেটা এখন View-তে রিড করতে হবে।

1. Reading Simple Types (String/Int)

সাধারণ String বা Int রিড করা খুবই সহজ। সরাসরি Key ধরে কল করলেই ব্রাউজারে ভ্যালু প্রিন্ট হয়ে যায়।

<!-- Views/Home/Index.cshtml -->
<!-- AppTitle রিড করে প্রিন্ট করা হচ্ছে -->
<h1>@ViewData["AppTitle"]</h1>
 

2. Reading Complex Types & Typecasting (The Catch!)

সমস্যা শুরু হয় যখন আমরা Collection বা অবজেক্ট রিড করতে যাই। যেহেতু ViewData বাই-ডিফল্ট সব ভ্যালুকে object হিসেবে ট্রিট করে, তাই View জানে না যে ViewData[“People”] এর ভেতরে আসলে একটি List আছে।

তাই লুপ চালানোর আগে আমাদের Typecasting (টাইপ কাস্টিং) করে নিতে হবে।

@{
    // ViewData থেকে ডেটা রিড করে List<Person>-এ কাস্ট করা হচ্ছে।
    // ? (Question mark) দেওয়া হয়েছে Nullable Warning দূর করার জন্য।
    List<Person>? people = (List<Person>?)ViewData["People"];
}
 
<!-- লুপ চালানোর আগে Null Check করে নেওয়া ভালো প্র্যাকটিস -->
@if (people != null)
{
    @foreach (var person in people)
    {
        <div>
            <span>@person.Name</span> - <span>@person.Gender</span>
        </div>
    }
}
 

Typecasting কেন দরকার? তুমি যদি সরাসরি @foreach(var p in ViewData[“People”]) লিখতে যাও, তাহলে C# এরর দিবে, কারণ একটি সাধারণ object-এর ওপর foreach লুপ চালানো যায় না। তাকে অবশ্যই IEnumerable বা List এ কাস্ট করে নিতে হয়।


⭐ Best Practices & Modern .NET 10 Context

ViewData জানাটা বেসিক ক্লিয়ার করার জন্য খুব জরুরি, কিন্তু রিয়েল-ওয়ার্ল্ড প্রজেক্টে বা আধুনিক MVC অ্যাপ্লিকেশনে এর ব্যবহার বেশ সীমিত।

Why avoid ViewData for Complex Objects? (কেন এড়িয়ে চলবো?)

  1. Magic Strings: ViewData[“People”] এ “People” একটি হার্ডকোডেড স্ট্রিং। যদি Controller-এ তুমি বানান ভুল করে “Peoples” লেখো এবং View-তে “People” খোঁজো, তাহলে কম্পাইল-টাইমে কোনো এরর আসবে না। অ্যাপ্লিকেশন রান করার পর পেজ ক্র্যাশ করবে বা ডেটা আসবে না। একে Magic String এর সমস্যা বলে।
  2. Typecasting Overhead: বারবার View-তে (List) কাস্ট করাটা বিরক্তিকর এবং View-এর কোডকে নোংরা করে ফেলে।

The Better Approach (Strongly Typed Views): ভিডিওর আউটলাইনে দেখো, এরপরই (লেকচার ৯৭ থেকে) “Strongly Typed Views” নামে একটি টপিক আছে। আধুনিক .NET 10 MVC প্রজেক্টে ViewData-এর বদলে সবসময় Strongly Typed Models ব্যবহার করা হয়।

Modern Approach Example:

// Controller
return View(people); // ViewData-তে না রেখে সরাসরি Model হিসেবে পাঠানো
 
<!-- View -->
@model IEnumerable<Person> 
<!-- কাস্টিংয়ের দরকার নেই, সরাসরি Model এর ওপর লুপ চলবে -->
@foreach (var person in Model) { ... }
 

Where to actually use ViewData? (কোথায় ব্যবহার করবো?) ViewData পুরোপুরি বাতিল নয়। খুব ছোটখাটো ডেটা (যেমন- Page Title, Meta Description, Notification message) যা মূল Model-এর অংশ নয়, সেগুলো পাঠানোর জন্য ViewData এখনও ব্যাপকভাবে ব্যবহৃত হয়। যেমন: ViewData[“Title”] = “Home Page”;