হ্যালো হাসিব! কোর্স আউটলাইন অনুযায়ী, আমরা এখন Section 11: View Components-এর তৃতীয় লেকচার “View Components with ViewData” (Lecture 122)-এ আছি। এই লেকচারে আমরা শিখবো কীভাবে View Component Class (C#) থেকে ডাটা তৈরি করে ViewData বা ViewBag-এর মাধ্যমে তার নিজস্ব Partial View-তে ডাটা পাস করতে হয়।
চলো, পুরো প্রসেসটিকে ধাপে ধাপে ডিকোড করে ফেলি।
সারসংক্ষেপ (Quick Revision List)
- The Goal: View Component Class-এর ভেতরে ডাটা (Model) তৈরি করে সেটিকে Partial View (
Sample.cshtml)-এ পাঠানো। - Crucial Rule: View Component Class এবং এর Partial View-এর নিজস্ব একটি আলাদা
ViewDataঅবজেক্ট থাকে। এটি Controller-এরViewDataথেকে সম্পূর্ণ স্বাধীন (Independent)। - Sending Data: Class ফাইলে
ViewData["key"] = data;ব্যবহার করে ডাটা পাঠানো হয়। - Receiving Data: Partial View-তে Type Casting-এর ঝামেলা এড়াতে
ViewData-এর বদলেViewBag.keyব্যবহার করে খুব সহজেই ডাটা অ্যাক্সেস করা যায়। - Intellisense Tip:
foreachলুপ চালানোর সময়varএর বদলে স্পেসিফিক ক্লাসের নাম (যেমনPerson) লিখলে Visual Studio-তে ভালো Intellisense (Auto-completion) পাওয়া যায়।
Comprehensive Breakdown
১. Model Classes তৈরি করা [Priority: 10/10]
যেহেতু আমরা ডাটা পাস করতে চাই, তাই আগে ডাটার স্ট্রাকচার (Model) বানাতে হবে।
Modelsফোল্ডারে দুটি ক্লাস তৈরি করা হয়েছে: একটি হলোPerson(যার ডেটা থাকবে) এবং আরেকটি হলোPersonGridModel(যা লিস্ট এবং টাইটেল ধারণ করবে)।
Code Implementation (Models/Person.cs & Models/PersonGridModel.cs):
namespace ViewComponentsExample.Models
{
public class Person
{
public string? PersonName { get; set; } // C# 8/9+ feature: Nullable string
public string? JobTitle { get; set; }
}
public class PersonGridModel
{
public string GridTitle { get; set; } = string.Empty;
public List<Person> Persons { get; set; } = new List<Person>();
}
}
২. View Component Class-এ ডাটা সেট করা [Priority: 10/10]
এখন GridViewComponent ক্লাসের InvokeAsync মেথডের ভেতরে আমরা ডাটাবেস থেকে ডাটা আনার বদলে হার্ডকোড করে কিছু ডাটা তৈরি করবো এবং সেটাকে ViewData-তে সেট করবো।
Code Implementation (ViewComponents/GridViewComponent.cs):
using ViewComponentsExample.Models; // Namespace import
public class GridViewComponent : ViewComponent
{
public async Task<IViewComponentResult> InvokeAsync()
{
// ১. Model অবজেক্ট তৈরি এবং ইনিশিয়ালাইজ করা
PersonGridModel gridModel = new PersonGridModel()
{
GridTitle = "Persons List",
Persons = new List<Person>()
{
new Person() { PersonName = "John", JobTitle = "Manager" },
new Person() { PersonName = "Jones", JobTitle = "Asst. Manager" },
new Person() { PersonName = "Smith", JobTitle = "Clerk" }
}
};
// ২. ViewData-তে অবজেক্টটি অ্যাসাইন করা
ViewData["Grid"] = gridModel;
// ৩. ভিউ রিটার্ন করা
return View("Sample");
}
}
৩. Partial View-তে ডাটা রিসিভ ও রেন্ডার করা [Priority: 10/10]
এই অংশটি খুব গুরুত্বপূর্ণ। আমরা Sample.cshtml-এ ViewData["Grid"] রিসিভ করবো।
The Type Casting Problem (কেন ViewData ব্যবহার করবো না?):
যদি আমরা Partial View-তে সরাসরি ViewData["Grid"].GridTitle লিখতে যাই, তাহলে এরর খাবে। কারণ ViewData ডাটাকে object টাইপে সেভ করে। প্রপার্টি অ্যাক্সেস করতে হলে আগে তাকে কাস্ট (Typecast) করতে হয়:
<!-- Very Complex! -->
<h2>@(((PersonGridModel)ViewData["Grid"]).GridTitle)</h2>
The Smart Solution (ViewBag):
এই ঝামেলা এড়ানোর জন্য আমরা ViewBag ব্যবহার করবো। ViewBag হলো ViewData-এরই একটি ডাইনামিক র্যাপার (Dynamic Wrapper)।
<!-- Very Clean! -->
<h2>@ViewBag.Grid.GridTitle</h2>
Code Implementation (Views/Shared/Components/Grid/Sample.cshtml):
<!-- ViewImports ফাইলে '@using ViewComponentsExample.Models' ইমপোর্ট করা থাকতে হবে -->
<div class="box">
<!-- ViewBag দিয়ে টাইটেল প্রিন্ট করা -->
<h2>@ViewBag.Grid.GridTitle</h2>
<table class="w-100">
<thead>
<tr>
<th>Person Name</th>
<th>Job Title</th>
</tr>
</thead>
<tbody>
<!-- ViewBag থেকে লিস্টটি নিয়ে লুপ চালানো -->
<!-- var এর বদলে Person লিখলে intellisense সাপোর্ট পাওয়া যায় -->
@foreach (Person person in ViewBag.Grid.Persons)
{
<tr>
<td>@person.PersonName</td>
<td>@person.JobTitle</td>
</tr>
}
</tbody>
</table>
</div>
৪. Execution Flow (ডাটা কীভাবে ফ্লো হচ্ছে?) [Priority: 8/10]
লেকচারার আবার ব্রেকপয়েন্ট দিয়ে ফ্লো-টা ক্লিয়ার করেছেন:
- Home Controller:
Indexএকশন কল হয়। - Index View: সেখানে
<vc:grid>ট্যাগ হেল্পার বাInvokeAsyncএর মাধ্যমে View Component কল হয়। - View Component Class:
GridViewComponentএরInvokeAsyncমেথডে আসে। ডাটা তৈরি হয় এবংViewData-তে সেট হয়। - Partial View (
Sample.cshtml): মেথড থেকেreturn View()কল হওয়ায় এটি রেন্ডার হওয়া শুরু হয়। এখানে সেViewBagএর মাধ্যমে ডাটাগুলো এক্সট্রাক্ট করে লুপ চালিয়ে HTML তৈরি করে। - Back to Index View: তৈরি হওয়া HTML-টা প্যারেন্ট ভিউয়ের নির্দিষ্ট জায়গায় বসে যায় এবং ফাইনালি লেআউটসহ ইউজার ব্রাউজারে দেখতে পায়।
VS / VS Code Shortcuts (For robust coding)
- Check Definition:
Personক্লাসের উপরCtrl + Clickকরলে অথবাF12চাপলে সরাসরিPerson.csফাইলে চলে যাবে। - Auto Implement Properties: ক্লাসের ভেতরে
propলিখেTab+Tabচাপলে অটোমেটিকpublic int MyProperty { get; set; }তৈরি হয়ে যায়।
Best Practices & .NET 10 Context
Best Practices for Passing Data in View Components:
- Avoid ViewData/ViewBag in View Components: এই লেকচারে যদিও
ViewDataদিয়ে ডাটা পাস করা দেখানো হয়েছে, প্রফেশনাল লেভেলে এটি একটি Anti-pattern বা Bad Practice। View Component-এ ডাটা পাস করার ডিফল্ট এবং বেস্ট ওয়ে হলো Strongly Typed Models ব্যবহার করা। (যা তুমি ঠিক এর পরের লেকচারেই শিখবে)। - Independent ViewData: লেকচারার যে কথাটি বারবার বলেছেন তা মনে রাখবে— View Component এর
ViewDataআর Controller এরViewDataএক নয়। তারা সম্পূর্ণ আলাদা মেমোরি শেয়ার করে।
.NET 10 Context:
ASP.NET Core 10-এও এই মেকানিজমটি সেম। তবে আধুনিক C# 12/13 (যা .NET 8, 9 এবং 10 এ ব্যবহৃত হচ্ছে)-তে আমরা new কি-ওয়ার্ডকে আরও শর্ট করে ফেলি (Target-typed new expression):
// Modern .NET 10 style
PersonGridModel gridModel = new() // 'PersonGridModel' দুবার লিখতে হয় না
{
GridTitle = "Persons List",
Persons = new()
{
new() { PersonName = "John", JobTitle = "Manager" }
}
};
হাসিব, View Component-এ ViewData দিয়ে ডাটা পাস করার কনসেপ্ট কি ক্লিয়ার হয়েছে? তুমি রেডি হলে আমরা এর সবচেয়ে প্রফেশনাল এপ্রোচ “Strongly Typed View Components”-এ মুভ করবো!