স্বাগতম! আপনার কোর্সের Section 20 (Filters)-এর অত্যন্ত গুরুত্বপূর্ণ একটি টপিক—“IFilterFactory” (লেকচার ৩০৩)-এ আমরা চলে এসেছি।

আগের লেকচারে আমরা দেখেছিলাম যে ActionFilterAttribute ব্যবহার করলে আমরা ফিল্টারকে সরাসরি অ্যাট্রিবিউট (যেমন [MyFilter]) হিসেবে ব্যবহার করতে পারি ঠিকই, কিন্তু সেখানে Constructor Injection (ILogger) কাজ করে না। আজ আমরা শিখব কীভাবে IFilterFactory ব্যবহার করে “Best of both worlds” পাওয়া যায়—অর্থাৎ, আমরা ক্লিন অ্যাট্রিবিউট সিনট্যাক্সও পাব, আবার Dependency Injection-ও ব্যবহার করতে পারব! চলুন শুরু করি!


📝 Quick Revision Summary

ভবিষ্যতে দ্রুত রিভিশন দেওয়ার জন্য মূল পয়েন্টগুলো নিচে দেওয়া হলো:

  • The Goal: ক্লিন অ্যাট্রিবিউট সিনট্যাক্স ([MyFilter]) এবং Constructor Injection (ILogger) দুটোই একসাথে ব্যবহার করা।
  • The Architecture (Two Classes): এর জন্য দুটি আলাদা ক্লাস লাগে:
  1. The Filter Class: এটি মূল লজিক ধারণ করে (ইন্টারফেস যেমন IAsyncActionFilter ইমপ্লিমেন্ট করে)।
  2. The Factory Class: এটি Attribute ক্লাস এবং IFilterFactory ইন্টারফেস ইনহেরিট করে। এটি রানটাইমে মূল Filter Class-এর অবজেক্ট তৈরি করে দেয়।
  • Data Flow: Controller -> Factory Class (প্যারামিটার রিসিভ করে) -> Filter Class (Factory থেকে প্যারামিটারগুলো প্রপার্টিতে সেট হয়)।
  • Dependency Injection: Factory ক্লাসের CreateInstance মেথডে IServiceProvider থাকে, যার মাধ্যমে খুব সহজেই Filter Class-এ ILogger বা অন্য সার্ভিস ইনজেক্ট করা যায়।

🔍 Comprehensive Breakdown

১. The Two-Class Architecture [Priority: 10/10]

IFilterFactory ব্যবহার করতে হলে আমাদের কাজকে দুটি ক্লাসে ভাগ করতে হবে।

Class 1: The Actual Filter (ResponseHeaderActionFilter) এই ক্লাসে আমাদের ফিল্টারের মূল লজিক থাকবে। এটি কোনো Attribute ক্লাস নয়, এটি সাধারণ একটি ফিল্টার যা IAsyncActionFilter ইমপ্লিমেন্ট করে। যেহেতু এখানে কাস্টম আর্গুমেন্ট (key, value) কনস্ট্রাক্টর দিয়ে পাঠানো সম্ভব নয় (Factory থেকে DI এর মাধ্যমে অবজেক্ট তৈরি হবে), তাই আর্গুমেন্টগুলোকে Public Properties হিসেবে রাখতে হবে।

using Microsoft.AspNetCore.Mvc.Filters;
using Microsoft.Extensions.Logging;
 
public class ResponseHeaderActionFilter : IAsyncActionFilter, IOrderedFilter
{
    private readonly ILogger<ResponseHeaderActionFilter> _logger;
 
    // Factory ক্লাস থেকে ডাটা রিসিভ করার জন্য Public Properties
    public string Key { get; set; }
    public string Value { get; set; }
    public int Order { get; set; }
 
    // Constructor Injection (শুধুমাত্র সার্ভিস ইনজেক্ট করার জন্য)
    public ResponseHeaderActionFilter(ILogger<ResponseHeaderActionFilter> logger)
    {
        _logger = logger;
    }
 
    public async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next)
    {
        _logger.LogInformation("Before Logic executed.");
        
        await next(); // Action method call
        
        // Properties থেকে ডাটা নিয়ে Header সেট করা হচ্ছে
        context.HttpContext.Response.Headers[Key] = Value;
    }
}
 

Class 2: The Factory Attribute (ResponseHeaderFilterFactoryAttribute) এটি হলো সেই ক্লাস, যা আমরা Controller-এর ওপর বসাব। এটি Attribute এবং IFilterFactory ইনহেরিট করে।

using System;
using Microsoft.AspNetCore.Mvc.Filters;
using Microsoft.Extensions.DependencyInjection;
 
public class ResponseHeaderFilterFactoryAttribute : Attribute, IFilterFactory
{
    // Controller থেকে ডাটা রিসিভ করার জন্য প্রাইভেট ফিল্ডস
    private string _key;
    private string _value;
    private int _order;
 
    // Constructor (Controller-এ [ResponseHeaderFilterFactory("Key", "Value")] লেখার জন্য)
    public ResponseHeaderFilterFactoryAttribute(string key, string value, int order)
    {
        _key = key;
        _value = value;
        _order = order;
    }
 
    public bool IsReusable => false;
 
    // 🚀 THE MAGIC METHOD 🚀
    // ফ্রেমওয়ার্ক রানটাইমে এই মেথড কল করে ফিল্টারের অবজেক্ট বানায়
    public IFilterMetadata CreateInstance(IServiceProvider serviceProvider)
    {
        // 1. Dependency Injection-এর মাধ্যমে Filter-এর অবজেক্ট তৈরি করা হচ্ছে (ILogger অটোমেটিক ইনজেক্ট হবে)
        var filter = serviceProvider.GetRequiredService<ResponseHeaderActionFilter>();
 
        // 2. Factory-র রিসিভ করা ডাটাগুলো Filter-এর প্রপার্টিতে সেট করে দেওয়া হচ্ছে
        filter.Key = _key;
        filter.Value = _value;
        filter.Order = _order;
 
        return filter;
    }
}
 

২. Registering in the IoC Container [Priority: 10/10]

যেহেতু CreateInstance মেথডে আমরা serviceProvider.GetRequiredService<ResponseHeaderActionFilter>() ব্যবহার করছি, তাই Program.cs-এ ফিল্টার ক্লাসটিকে অবশ্যই রেজিস্টার করতে হবে (ঠিক ServiceFilter-এর মতো)।

// Program.cs
builder.Services.AddTransient<ResponseHeaderActionFilter>();
 

৩. Applying the Filter in the Controller [Priority: 9/10]

এখন আমাদের Controller-এর কোড দেখতে একদম পারফেক্ট এবং ক্লিন হয়ে গেল! [TypeFilter] লেখার কোনো ঝামেলাই নেই।

using Microsoft.AspNetCore.Mvc;
 
public class PersonsController : Controller
{
    // Factory Attribute ব্যবহার করে সরাসরি ফিল্টার অ্যাপ্লাই করা হচ্ছে
    [ResponseHeaderFilterFactory("X-Custom-Key", "Custom-Value", 1)]
    public IActionResult Index()
    {
        return View();
    }
}
 

৪. The Execution Flow (কীভাবে কাজ করছে?) [Priority: 8/10]

  1. রিকোয়েস্ট Controller-এ আসে।
  2. ফ্রেমওয়ার্ক দেখে যে [ResponseHeaderFilterFactory] অ্যাট্রিবিউট বসানো আছে।
  3. ফ্রেমওয়ার্ক Factory ক্লাসের CreateInstance মেথড কল করে।
  4. Factory ক্লাস DI কন্টেইনার থেকে ILogger সহ ResponseHeaderActionFilter-এর একটি অবজেক্ট তৈরি করে।
  5. Factory ক্লাস তার কাস্টম আর্গুমেন্টগুলো (key, value) Filter অবজেক্টের প্রপার্টিতে অ্যাসাইন করে।
  6. সবশেষে, Filter অবজেক্টটি তার মূল কাজ (Before/After Logic) শুরু করে।

🚀 Best Practices & The Industry Standard

Industry Standard Recommendation: লেকচারার স্পষ্ট করে বলেছেন, রিয়েল-ওয়ার্ল্ড প্রোজেক্টে কাস্টম ফিল্টার বানানোর সবচেয়ে সেরা উপায় হলো:

  • যদি আপনার কাস্টম আর্গুমেন্ট না লাগে: TypeFilter বা ServiceFilter ব্যবহার করুন।
  • যদি কাস্টম আর্গুমেন্ট এবং DI দুটোই লাগে: IFilterFactory ব্যবহার করুন।
  • Avoid: ActionFilterAttribute ক্লাস ইনহেরিট করা থেকে বিরত থাকুন, কারণ এটি Constructor Injection ব্লক করে দেয়।

.NET 10 Modern Context: আধুনিক .NET-এ এই IFilterFactory প্যাটার্নটিই কাস্টম অ্যাট্রিবিউট-বেসড ফিল্টারের জন্য গোল্ড স্ট্যান্ডার্ড।

আশা করি এই লেকচারটির মাধ্যমে Filter সম্পর্কিত আপনার সমস্ত দ্বিধা দূর হয়ে গেছে। আমরা ফিল্টারের একদম গভীরে গিয়ে সবগুলো আর্কিটেকচার দেখেছি।

পরবর্তী লেকচারে আমরা Filters বনাম Middleware-এর পার্থক্য নিয়ে আলোচনা করব, যা যেকোনো ইন্টারভিউয়ের জন্য “Must Know” টপিক!