হ্যালো হাসিব! তুমি এখন Section 12: Dependency Injection-এর চতুর্থ লেকচার “Inversion of Control (IoC)” (Lecture 131)-এ আছো। আগের লেকচারে আমরা একটি ইন্টারফেস (ICitiesService) তৈরি করে Controller এবং Service-কে আলাদা (Loosely Coupled) করেছিলাম। কিন্তু আমাদের একটি প্রশ্ন ছিল: Controller-এর ভেতরে Service-এর অবজেক্টটা কে তৈরি করবে?

আজকের লেকচারে আমরা সেই প্রশ্নের উত্তর পাবো। আমরা শিখবো Inversion of Control (IoC) কী এবং ASP.NET Core-এর বিল্ট-ইন IoC Container কীভাবে কাজ করে।

চলো, লেকচারটি বিস্তারিতভাবে ডিকোড করি।


সারসংক্ষেপ (Quick Revision List)

  • The Big Question: Controller যদি new CitiesService() লিখতে না পারে, তাহলে অবজেক্টটা কে তৈরি করবে? উত্তর: IoC Container
  • Inversion of Control (IoC): এটি একটি ডিজাইন প্যাটার্ন। এর মানে হলো, অবজেক্ট তৈরি করার দায়িত্ব (Control) ডেভেলপারের হাত থেকে নিয়ে ফ্রেমওয়ার্কের (Container) হাতে তুলে দেওয়া। (Don’t call us, we will call you)।
  • IoC Container in ASP.NET Core: ASP.NET Core-এ builder.Services (বা IServiceCollection) হলো বিল্ট-ইন IoC Container।
  • Registering the Service: Container-কে জানাতে হবে যে কোন ইন্টারফেসের জন্য কোন ক্লাসের অবজেক্ট বানাতে হবে। এর জন্য ServiceDescriptor ক্লাস ব্যবহার করে builder.Services.Add(new ServiceDescriptor(...)) লিখতে হয়।
  • Service Lifetime: Container-কে বলে দিতে হয় যে সে অবজেক্টটি কতক্ষণ মেমোরিতে ধরে রাখবে (Transient, Scoped, বা Singleton)।

Comprehensive Breakdown

১. Inversion of Control (IoC) কী? [Priority: 10/10]

নাম দেখেই বোঝা যাচ্ছে, Inversion (উল্টে দেওয়া) of Control (নিয়ন্ত্রণ)। সাধারণত একটি ক্লাসের ভেতরে আমরা নিজেই new কি-ওয়ার্ড দিয়ে অন্য ক্লাসের অবজেক্ট তৈরি করি। অর্থাৎ, অবজেক্ট বানানোর কন্ট্রোল আমাদের (ডেভেলপারের) হাতে থাকে। কিন্তু IoC প্যাটার্নে এই কন্ট্রোল আমাদের হাত থেকে ফ্রেমওয়ার্কের হাতে চলে যায়।

The Hollywood Principle: IoC-কে প্রায়ই ‘Hollywood Principle’ বলা হয়— “Don’t call us, we’ll call you.” যেমন: তুমি চাকরির জন্য ইন্টারভিউ দিলে, এরপর HR তোমাকে বলে “আমাদেরকে আর কল করার দরকার নেই, আমাদের প্রয়োজন হলে আমরাই তোমাকে কল করবো।” একইভাবে, Controller নিজে থেকে Service-কে তৈরি করবে না, বরং IoC Container প্রয়োজন অনুযায়ী Service তৈরি করে Controller-এর হাতে ধরিয়ে দেবে।

২. ASP.NET Core-এ IoC Container কোথায় থাকে? [Priority: 10/10]

ASP.NET Core অ্যাপ্লিকেশনে একটি ডিফল্ট IoC Container থাকে, যাকে Service Container-ও বলা হয়। Program.cs ফাইলে builder.Services টাইপের যে অবজেক্টটি আছে (যার টাইপ IServiceCollection), সেটিই হলো আমাদের IoC Container।

৩. Container-এ Service রেজিস্টার করা (Registration Phase) [Priority: 10/10]

Container একা একা তো আর বুঝবে না যে ICitiesService চাইলে তাকে CitiesService-এর অবজেক্ট বানাতে হবে। তাই আমাদের Program.cs ফাইলে Container-কে এই নিয়মটি বলে দিতে হবে। একে বলে Registering the Service

লেকচারার এখানে বেসিক এবং কোর মেকানিজম বোঝানোর জন্য ServiceDescriptor ক্লাস ব্যবহার করেছেন। (পরবর্তীতে এর অনেক শর্টকাট মেথড আছে যা আমরা শিখবো)।

Code Implementation (Program.cs):

using ServiceContracts; // Interface-এর namespace
using Services;         // Service class-এর namespace
 
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddControllersWithViews();
 
// ১. IoC Container-এ Service Register করা হচ্ছে
builder.Services.Add(new ServiceDescriptor(
    typeof(ICitiesService), // First Arg: Interface (কে অবজেক্ট চাচ্ছে?)
    typeof(CitiesService),  // Second Arg: Class (কোন অবজেক্ট বানিয়ে দেবো?)
    ServiceLifetime.Transient // Third Arg: Lifetime (কতক্ষণ বাঁচিয়ে রাখবো?)
));
 
var app = builder.Build();
// ... (Routing & Middlewares)
 

What does this code do? এই কোডটি IoC Container-কে বলে দিচ্ছে: “হে Container, যখনই কেউ তোমার কাছে ICitiesService টাইপের কোনো অবজেক্ট চাইবে, তুমি তাকে CitiesService ক্লাসের একটি নতুন অবজেক্ট (new CitiesService()) বানিয়ে দিয়ে দেবে।“

৪. Service Lifetime (Transient, Scoped, Singleton) [Priority: 9/10]

উপরের কোডে ৩য় আর্গুমেন্ট হিসেবে ServiceLifetime.Transient দেওয়া হয়েছে। IoC Container যখন একটি অবজেক্ট বানায়, সে সেই অবজেক্টটিকে মেমোরিতে কতক্ষণ ধরে রাখবে বা রিইউজ করবে, সেটি নির্ধারণ করে Service Lifetime। এর ৩টি অপশন আছে:

  1. Transient: প্রতিবার রিকোয়েস্ট করার সময় একটি নতুন অবজেক্ট তৈরি করবে।
  2. Scoped: প্রতি HTTP রিকোয়েস্টের জন্য একটি অবজেক্ট তৈরি করবে এবং পুরো রিকোয়েস্ট জুড়ে সেটিই ব্যবহার করবে।
  3. Singleton: অ্যাপ চালু হওয়ার সময় একবারই অবজেক্ট তৈরি করবে এবং অ্যাপ বন্ধ না হওয়া পর্যন্ত সেটিই সবাইকে দেবে। (এই লেকচারে শুধু নামগুলো বলা হয়েছে, পরবর্তী লেকচারগুলোতে এগুলো নিয়ে বিস্তারিত প্র্যাকটিক্যাল এক্সাম্পল থাকবে)।

৫. The Unanswered Question (অবজেক্ট রিসিভ করবো কীভাবে?) [Priority: 8/10]

আমরা Container-কে রুল বলে দিয়েছি, কিন্তু Controller-এর কোডে আমরা এখনো অবজেক্টটি রিসিভ করিনি।

public HomeController() {
    _citiesService = null; // এখনো null আছে!
}
 

যদি এখন অ্যাপ রান করো, তুমি আগের মতোই NullReferenceException খাবে।

কারণ, Container অবজেক্ট তৈরি করতে পারে, কিন্তু সেই তৈরি করা অবজেক্টকে Controller-এর ভেতরে ঢুকিয়ে (Inject) দেওয়ার কাজটি করে Dependency Injection (DI)। এটিই আমরা পরের লেকচারে শিখবো।


VS / VS Code Shortcuts (For faster development)

  • typeof() operator: C#-এ typeof(ClassName) ব্যবহার করলে ঐ ক্লাসের Type অবজেক্ট পাওয়া যায়। DI Container-এ টাইপ চেক করার জন্য এটি ব্যাপকভাবে ব্যবহৃত হয়।

Best Practices & .NET 10 Context

Best Practices for IoC Container:

  1. Registering Order: Program.cs ফাইলে builder.Build() কল করার আগেই সব সার্ভিস builder.Services-এ রেজিস্টার করতে হবে। একবার Build হয়ে গেলে Container লক হয়ে যায়, তখন আর নতুন সার্ভিস অ্যাড করা যায় না।
  2. Use Shortcuts: প্রফেশনাল প্রজেক্টে কখনোই new ServiceDescriptor(...) ব্যবহার করে এত বড় কোড লেখা হয় না। এর শর্টকাট মেথড আছে (যেমন: AddTransient(), যা তুমি সামনেই শিখবে)। লেকচারার শুধু ব্যাকএন্ডে কী হয় তা বোঝানোর জন্য এটি দেখিয়েছেন।

.NET 10 Context: ASP.NET Core 10-এ IoC Container এবং IServiceCollection-এর মেকানিজম .NET Core এর শুরু থেকেই অপরিবর্তিত এবং ১০০% সেম আছে। .NET 10-এও builder.Services-ই হলো মূল Container।

// Modern .NET 10 style (using extensions)
// এটি ServiceDescriptor-এর শর্টকাট
builder.Services.AddTransient<ICitiesService, CitiesService>(); 
 

হাসিব, Inversion of Control-এর কনসেপ্ট কি ক্লিয়ার হয়েছে? তুমি রেডি থাকলে আমরা পরবর্তী লেকচার “Dependency Injection”-এ মুভ করতে পারি, যেখানে আমরা এই পাজলের শেষ অংশটুকু মেলাবো!