হ্যালো হাসিব! তুমি এখন Section 12: Dependency Injection-এর সপ্তম লেকচার “Transient, Scoped, Singleton - Part 1” (Lecture 134)-এ আছো। এই লেকচারটি পুরো Dependency Injection (DI) সেকশনের সবচেয়ে গুরুত্বপূর্ণ থিওরিটিক্যাল লেকচার এবং ইন্টারভিউয়ের জন্য এটা একটা 100% Guaranteed Interview Question।
আজকের লেকচারে আমরা শিখবো IoC Container যখন কোনো সার্ভিস তৈরি করে, তখন সেটার Lifetime (আয়ুষ্কাল) কীভাবে কাজ করে এবং Transient, Scoped, ও Singleton এর মধ্যে পার্থক্য কী।
চলো, এই লেকচারটি বিস্তারিতভাবে ডিকোড করি।
সারসংক্ষেপ (Quick Revision List)
- Service Lifetime কী: IoC Container কখন একটি সার্ভিসের অবজেক্ট (Instance) তৈরি করবে এবং কখন সেটিকে মেমোরি থেকে মুছে (Destroy/Dispose) ফেলবে, সেটিই হলো Service Lifetime।
- Transient: Per Injection. যতবারই তুমি এই সার্ভিসটি ইনজেক্ট করবে (যেকোনো ক্লাসে), Container ততবারই একটি সম্পূর্ণ নতুন অবজেক্ট তৈরি করে দেবে। (সবচেয়ে বেশি মেমোরি খায়)।
- Scoped: Per Request. ব্রাউজার থেকে একটি HTTP রিকোয়েস্ট আসলে একটি নতুন স্কোপ তৈরি হয়। ঐ রিকোয়েস্টের পুরো লাইফসাইকেলে তুমি যতবারই সার্ভিস ইনজেক্ট করো না কেন, Container একই অবজেক্ট দিবে। রিকোয়েস্ট শেষ তো অবজেক্টও ডিলিট।
- Singleton: Per Application. অ্যাপ রান হওয়ার পর প্রথমবার কেউ চাইলে Container একবারই অবজেক্ট বানায়। এরপর আজীবন (অ্যাপ বন্ধ না হওয়া পর্যন্ত) সবাইকে ঐ একই অবজেক্ট দেয়।
- Destruction Time: Transient এবং Scoped অবজেক্টগুলো রিকোয়েস্ট (বা স্কোপ) শেষ হলেই ডেস্ট্রয় হয়ে যায়। আর Singleton অবজেক্ট ডেস্ট্রয় হয় অ্যাপ যখন শাটডাউন (বন্ধ) হয় তখন।
Comprehensive Breakdown
১. Service Lifetime-এর ধারণা [Priority: 10/10]
আগের লেকচারে আমরা ServiceLifetime.Transient লিখেছিলাম। এর মানে আমরা Container-কে বলে দিয়েছিলাম যে, “এই সার্ভিসের অবজেক্ট তুমি Transient নিয়মে ম্যানেজ করবে।”
IoC Container-এর দুইটি প্রধান দায়িত্ব আছে:
- অবজেক্ট তৈরি করা (Instantiation)।
- কাজ শেষে মেমোরি থেকে অবজেক্ট মুছে ফেলা (Disposal/Destruction)। এই দুটি কাজ কখন ঘটবে, তা নির্ধারণ করে দেয় Service Lifetime।
২. Transient, Scoped, এবং Singleton (বিস্তারিত পার্থক্য) [Priority: 10/10]
লেকচারার এই তিনটি বিষয়ের একটি গ্রাফিক্যাল উদাহরণ দিয়েছেন। চলো এটা সহজে বুঝি:
১. Transient (Per Injection):
- Rule: তুমি যতবারই সার্ভিসের নাম ধরবে, সে ততবার নতুন অবজেক্ট বানাবে।
- Example: ধরো, তোমার
HomeController-এর কনস্ট্রাক্টরেICitiesServiceইনজেক্ট করা আছে। আবার ঐ একই Controller-এ তুমি অন্য একটি মেথডে[FromServices]দিয়ে আবার ইনজেক্ট করলে। Container এখানে দুটি আলাদাCitiesServiceঅবজেক্ট বানাবে। - When to use: যখন তোমার সার্ভিসে কোনো ডাটা সেভ রাখার দরকার নেই (Stateless) এবং হালকা-পাতলা লজিক থাকে।
২. Scoped (Per Request / Per Scope):
- Rule: একটি HTTP রিকোয়েস্ট যতক্ষণ সার্ভারে ঘুরবে (Middleware -> Controller -> View), এর মধ্যে তুমি যত জায়গায়ই ইনজেক্ট করো না কেন, Container একটি অবজেক্টই দিবে। কিন্তু তুমি যদি ব্রাউজারে রিফ্রেশ দিয়ে নতুন রিকোয়েস্ট পাঠাও, তখন সে নতুন আরেকটি অবজেক্ট বানাবে।
- Example: ইউজার ‘A’ পেজে রিকোয়েস্ট করলো, তার জন্য
Object 1তৈরি হলো। ঐ একই রিকোয়েস্টে Controller এবং View-তেObject 1ই ব্যবহৃত হবে। ইউজার ‘B’ রিকোয়েস্ট করলে তার জন্যObject 2তৈরি হবে। - When to use: ডাটাবেস কানেকশন (যেমন Entity Framework-এর
DbContext), ইউজার অথেনটিকেশন বা সেশন ডাটা ম্যানেজ করার জন্য এটি বেস্ট।
৩. Singleton (Per Application):
- Rule: অ্যাপ রান করার পর প্রথমবার যে এই সার্ভিস চাইবে, তার জন্য Container একটি অবজেক্ট বানাবে। এরপর পৃথিবীর যে প্রান্ত থেকে, যে রিকোয়েস্টই আসুক না কেন— সবাইকে ঐ একই অবজেক্ট দেওয়া হবে।
- Example:
Object 1তৈরি হওয়ার পর ইউজার A, B, C সবাই ঐ একইObject 1পাবে। - When to use: এমন কোনো সার্ভিস যেখানে ডাটা সবার জন্য সেম থাকে (যেমন: Country List, Application Settings, Cache Data)।
৩. Graphical Representation Flow [Priority: 9/10]
ভিডিওর গ্রাফটি মনে করার চেষ্টা করো:
- Request 1, Injection 1: Transient (Obj 1), Scoped (Obj 1), Singleton (Obj 1).
- Request 1, Injection 2 (একই রিকোয়েস্ট): Transient (Obj 2 - নতুন), Scoped (Obj 1 - সেম), Singleton (Obj 1 - সেম).
- Request 2, Injection 1 (নতুন রিকোয়েস্ট): Transient (Obj 3 - নতুন), Scoped (Obj 2 - নতুন), Singleton (Obj 1 - সেম).
৪. Destruction/Disposal Rule (কখন মেমোরি থেকে ডিলিট হবে?) [Priority: 10/10]
অবজেক্ট তৈরি হওয়ার চেয়েও এটা জানা বেশি জরুরি যে অবজেক্ট কখন ডিলিট হয়। (এটি ইন্টারভিউতে কনফিউজ করার জন্য জিজ্ঞেস করা হয়)।
- Transient: অনেকেই মনে করে, যে মেথডে বা ক্লাসে ইনজেক্ট হয়েছে, সেই ক্লাস শেষ হলেই Transient অবজেক্ট ডিলিট হয়ে যায়। এটি ভুল! Transient অবজেক্ট তৈরি হয় বারবার, কিন্তু ডিলিট হয় রিকোয়েস্ট (Scope) শেষ হলে। অর্থাৎ, যতক্ষণ রেসপন্স ব্রাউজারে না যায়, Transient অবজেক্টগুলো মেমোরিতে বসে থাকে। (এজন্য অতিরিক্ত Transient ব্যবহার করলে মেমোরি লিক হতে পারে)।
- Scoped: এটি রিকোয়েস্ট শেষ হওয়ার সাথে সাথেই ডিলিট হয়ে যায়।
- Singleton: এটি অ্যাপ চালু থাকা অবস্থায় কখনোই ডিলিট হয় না। যখন সার্ভার বা কনসোল উইন্ডো বন্ধ করা হয় (App Shutdown), তখনই কেবল এটি ডিলিট হয়।
৫. DI Graph (Service to Service Injection) [Priority: 8/10]
লেকচারার একটি চমৎকার পয়েন্ট বলেছেন— শুধু Controller-এ নয়, তুমি চাইলে এক Service-এর ভেতরে অন্য Service ইনজেক্ট করতে পারো। ধরো, Controller -> Service A -> Service B -> Service C. IoC Container এই পুরো চেইনটাকে একা একাই ম্যানেজ করে। তোমাকে শুধু কনস্ট্রাক্টরে প্যারামিটার দিয়ে যেতে হবে। এই চেইনটাকে বলা হয় DI Graph বা Service Tree।
Best Practices & .NET 10 Context
Best Practices for Lifetimes:
- Avoid Singleton for Database: কখনোই ডাটাবেসের কাজ (DbContext) Singleton-এ রাখবে না। ডাটাবেস কোয়েরিগুলো একসাথে মিলে ক্র্যাশ করবে (Concurrency issue)। ডাটাবেসের জন্য সবসময় Scoped ব্যবহার করবে।
- Stateless = Transient: যদি তোমার সার্ভিসের শুধু কিছু মেথড থাকে (কোনো গ্লোবাল ভ্যারিয়েবল বা ডাটা হোল্ড না করে), তবে তাকে Transient রাখা ভালো।
- Caching = Singleton: যদি ডাটাবেস থেকে কিছু ফিক্সড ডাটা (যেমন: দেশের নাম) এনে মেমোরিতে রেখে দিতে চাও, তবে তাকে Singleton করবে।
.NET 10 Context:
ASP.NET Core 10-এ এই ৩টি Lifetime-এর রুলস এবং কনসেপ্ট একদম সেম আছে। তুমি যখন রিয়েল-লাইফ প্রোজেক্ট করবে, তখন দেখবে .NET 10-এ এই সার্ভিসগুলোকে Program.cs-এ কীভাবে খুব সহজে এক লাইনে রেজিস্টার করা যায়:
// Modern .NET 10 style (আগামী লেকচারে এগুলোই দেখানো হবে)
builder.Services.AddTransient<ICitiesService, CitiesService>();
builder.Services.AddScoped<IDbContext, MyDbContext>();
builder.Services.AddSingleton<ICacheService, MemoryCacheService>();
হাসিব, Transient, Scoped এবং Singleton এর থিওরি এবং পার্থক্যগুলো কি ক্লিয়ার হয়েছে? তুমি রেডি থাকলে আমরা নেক্সট লেকচার “Transient, Scoped, Singleton - Part 2”-এ মুভ করতে পারি, যেখানে আমরা এই থিওরিগুলোকে কোডে প্রমাণ করে দেখবো!