হ্যালো হাসিব! তুমি এখন Section 14: Configuration-এর পঞ্চম লেকচার “Configuration as Service” (Lecture 154)-এ আছো।

আগের লেকচারে আমরা Options Pattern শিখেছিলাম, যেখানে Action Method-এর ভেতরে Get<T>() ব্যবহার করে কনফিগারেশন রিড করা হয়েছিল। কিন্তু আজকের লেকচারে আমরা শিখবো কীভাবে এই Options Pattern-কে Dependency Injection (DI) এর সাথে যুক্ত করে একটি Service হিসেবে Controller-এ ইনজেক্ট করতে হয়। রিয়েল-ওয়ার্ল্ড প্রোজেক্টে কনফিগারেশন হ্যান্ডেল করার এটিই সবচেয়ে স্ট্যান্ডার্ড উপায়।

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


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

  • The Goal: Action Method-এর ভেতর কনফিগারেশন রিড করার কোড না লিখে, সরাসরি কনফিগারেশন অবজেক্টটিকে Controller-এর Constructor-এ ইনজেক্ট করা।
  • Step 1 (Registration): Program.cs ফাইলে builder.Services.Configure<T>(...) মেথড ব্যবহার করে Options Class-টিকে IoC Container-এ রেজিস্টার করতে হয়।
  • Step 2 (Injection): Controller-এর Constructor-এ সরাসরি ক্লাসটির বদলে IOptions<T> ইন্টারফেসটি ইনজেক্ট করতে হয়।
  • Step 3 (Extraction): IOptions<T> এর ভেতরে থাকা .Value প্রপার্টি কল করলে আসল C# অবজেক্টটি (যাতে ডাটা লোড হয়ে আছে) পাওয়া যায়।
  • The Benefit: Action Method অনেক বেশি ক্লিন এবং সিম্পল হয়ে যায়।

Comprehensive Breakdown

১. Why “Configuration as Service”? (প্রয়োজনীয়তা) [Priority: 10/10]

আগের লেকচারে আমাদের Action Method-এর চেহারা ছিল অনেকটা এরকম:

WeatherApiOptions options = _configuration.GetSection("WeatherAPI").Get<WeatherApiOptions>();
 

সমস্যা কোথায়? Action Method-এর মূল কাজ হলো ইউজারের রিকোয়েস্ট প্রসেস করা। কনফিগারেশন সোর্স থেকে ডাটা ম্যাপ করার মতো “Infrastructure” লেভেলের কাজ Action Method-এর ভেতরে করাটা Clean Architecture-এর নিয়ম পরিপন্থী।

এর সমাধান হলো, আমরা Program.cs-এই বলে দেবো যে, “তুমি WeatherAPI সেকশনের ডাটাগুলো WeatherApiOptions ক্লাসে লোড করে DI Container-এ রেখে দাও। যখন যে Controller-এর লাগবে, সে Constructor দিয়ে চেয়ে নেবে।“

২. Program.cs-এ Configuration Service রেজিস্টার করা [Priority: 10/10]

DI Container-এ কনফিগারেশন ক্লাস অ্যাড করার জন্য IServiceCollection-এর একটি স্পেশাল মেথড আছে, যার নাম Configure<T>()

Code Implementation (Program.cs):

var builder = WebApplication.CreateBuilder(args);
 
// Options Pattern-কে Service হিসেবে রেজিস্টার করা হচ্ছে
// <WeatherApiOptions> হলো আমাদের তৈরি করা Model Class
// GetSection("WeatherAPI") হলো appsettings.json-এর সেই ব্লকটি
builder.Services.Configure<WeatherApiOptions>(builder.Configuration.GetSection("WeatherAPI"));
 
builder.Services.AddControllersWithViews();
// ...
 

What happens here? এই এক লাইন কোডের মাধ্যমে ASP.NET Core WeatherAPI সেকশনের ডাটা রিড করে WeatherApiOptions-এর একটি অবজেক্ট তৈরি করে এবং সেটিকে IoC Container-এ একটি Singleton সার্ভিসের মতো সেভ করে রাখে।

৩. Controller-এ IOptions ইনজেক্ট করা [Priority: 10/10]

সবচেয়ে ট্রিকি পার্ট হলো ইনজেকশন। তুমি Controller-এ সরাসরি WeatherApiOptions ইনজেক্ট করতে পারবে না। তোমাকে একটি র‍্যাপার (Wrapper) ইন্টারফেস ব্যবহার করতে হবে, যার নাম IOptions<T>

Code Implementation (Controllers/HomeController.cs):

using Microsoft.AspNetCore.Mvc;
// ১. IOptions ব্যবহার করার জন্য এই Namespace ইমপোর্ট করতে হবে
using Microsoft.Extensions.Options; 
using ConfigurationExample.Models;
 
namespace ConfigurationExample.Controllers
{
    public class HomeController : Controller
    {
        // ২. আমাদের আসল Options Class-এর জন্য Field
        private readonly WeatherApiOptions _options;
 
        // ৩. Constructor-এ IOptions<T> ইনজেক্ট করা হচ্ছে
        public HomeController(IOptions<WeatherApiOptions> weatherApiOptions)
        {
            // ৪. .Value প্রপার্টি দিয়ে আসল অবজেক্টটি বের করে ফিল্ডে সেভ করা হচ্ছে
            _options = weatherApiOptions.Value;
        }
 
        [Route("/")]
        public IActionResult Index()
        {
            // (পরবর্তী ধাপে Action Method-এর কোড)
            return View();
        }
    }
}
 

Why .Value? IOptions<WeatherApiOptions> প্যারামিটারটি হলো ফ্রেমওয়ার্কের দেওয়া একটি বাক্স। এই বাক্সের ভেতরে তোমার আসল অবজেক্টটি থাকে। তাই weatherApiOptions.Value কল করে ডাটাভর্তি আসল অবজেক্টটি বের করে নিতে হয়।

৪. Action Method-এ ডাটা ব্যবহার করা [Priority: 9/10]

এখন আমাদের Action Method আগের চেয়ে অনেক বেশি ক্লিন। এখানে কোনো IConfiguration বা GetSection এর ঝামেলা নেই।

Code Implementation (Index Method):

[Route("/")]
public IActionResult Index()
{
    // সরাসরি Field থেকে ডাটা রিড করা যাচ্ছে!
    ViewBag.ClientID = _options.ClientID;
    ViewBag.ClientSecret = _options.ClientSecret;
 
    // লেকচারারের নোট: রিয়েল-ওয়ার্ল্ডে আমরা এগুলো ভিউতে প্রিন্ট করি না, 
    // বরং এগুলো দিয়ে REST API (যেমন HttpClient) কল করি।
    
    return View();
}
 

VS / VS Code Shortcuts (For faster development)

  • Import Missing Namespace: IOptions লেখার পর যদি এরর দেখায় (লাল দাগ), তবে কার্সর সেখানে রেখে Ctrl + . চাপলে using Microsoft.Extensions.Options; ইমপোর্ট করার সাজেশন আসবে। এন্টার চাপলেই উপরে Namespace অ্যাড হয়ে যাবে।

Best Practices & .NET 10 Context

Best Practices for IOptions:

  1. Never print Secrets to View: লেকচারার ভিডিওর শেষে পরিষ্কার করে বলেছেন— কনফিগারেশন ভ্যালুগুলো (বিশেষ করে Client ID বা Secret) কখনোই ভিউতে প্রিন্ট করবে না। এগুলো শুধুমাত্র সার্ভারের ভেতরে থার্ড-পার্টি REST API কল করার জন্য ব্যবহার করা উচিত।
  2. Advanced IOptions (Interview Tip): ASP.NET Core-এ ৩ ধরনের Options Interface আছে।
  • IOptions<T>: অ্যাপ চলার সময় appsettings.json চেঞ্জ হলে আপডেট ডাটা পায় না (Singleton)।
  • IOptionsSnapshot<T>: অ্যাপ রিস্টার্ট না দিয়েই নতুন ডাটা পায়, প্রতি রিকোয়েস্টে আপডেট হয় (Scoped)।
  • IOptionsMonitor<T>: রিয়েল-টাইমে ডাটা আপডেট ট্র্যাক করতে পারে (Singleton)।

.NET 10 Context (Primary Constructors): আধুনিক C# 12+ এবং .NET 10-এ Primary Constructors ব্যবহার করে এই IOptions<T> ইনজেকশনের কোডটিকে আরও অনেক বেশি চমৎকার এবং ক্লিন করে লেখা যায়। এতে আলাদা কোনো কনস্ট্রাক্টর বডির প্রয়োজন হয় না।

.NET 10 Modern MVC Code Example:

using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Options;
using ConfigurationExample.Models;
 
namespace ConfigurationExample.Controllers;
 
// .NET 10 Style: Primary Constructor-এর ভেতরেই IOptions<T> ইনজেক্ট করা হলো
public class HomeController(IOptions<WeatherApiOptions> weatherApiOptions) : Controller
{
    [Route("/")]
    public IActionResult Index()
    {
        // Action Method-এর ভেতরে সরাসরি weatherApiOptions.Value ব্যবহার করা যাচ্ছে
        var options = weatherApiOptions.Value;
 
        string clientId = options.ClientID;
        string clientSecret = options.ClientSecret;
        
        // Use clientId and clientSecret for making external API calls...
        
        return View();
    }
}
 

হাসিব, IOptions<T> ব্যবহার করে কনফিগারেশন ইনজেক্ট করার এই স্ট্যান্ডার্ড প্যাটার্নটি কি তোমার কাছে ক্লিয়ার হয়েছে? রেডি থাকলে আমরা নেক্সট লেকচার “Environment Specific Configuration”-এ মুভ করতে পারি, যেখানে আমরা শিখবো Development এবং Production-এর জন্য আলাদা আলাদা appsettings.json ফাইল কীভাবে কাজ করে!