স্বাগতম! আপনার কোর্সের আউটলাইন অনুযায়ী আমরা এখন Section 20 (Filters)-এর অত্যন্ত ট্রিকি এবং মজার একটি টপিক—“Filter Overrides” (লেকচার ৩০০)-এ আছি।

ধরুন, আপনি একটি Controller-এর ওপর একটি Filter বসিয়েছেন, যার ফলে ভেতরের ১০০টি Action Method-এই ফিল্টারটি কাজ করছে। কিন্তু আপনি চাচ্ছেন শুধুমাত্র ১টি বা ২টি Action Method-এর জন্য এই ফিল্টারটি যেন কাজ না করে (Skip হয়)। ফ্রেমওয়ার্কে সরাসরি এর কোনো সমাধান নেই! আজ আমরা শিখব কীভাবে একটি স্মার্ট ওয়ার্কঅ্যারাউন্ড (Workaround) বা ট্রিক ব্যবহার করে এই Filter Overrides বা স্কিপিং ইমপ্লিমেন্ট করা যায়। চলুন শুরু করি!


📝 Quick Revision Summary

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

  • Filter Overrides কী: Global বা Controller লেভেলে অ্যাপ্লাই করা কোনো ফিল্টারকে নির্দিষ্ট কোনো Action Method-এর জন্য স্কিপ (Skip) বা ডিজেবল করার প্রক্রিয়া।
  • The Challenge: ASP.NET Core-এ কাস্টম ফিল্টার স্কিপ করার জন্য সরাসরি কোনো বিল্ট-ইন ফিচার নেই।
  • The Workaround (Solution): 1. একটি ডামি Custom Attribute তৈরি করা (যেমন SkipFilter)।
  1. এটি যেন Filter হিসেবে গণ্য হয়, তাই IFilterMetadata ইন্টারফেস ইমপ্লিমেন্ট করা।
  2. যে Action Method-এ ফিল্টার স্কিপ করতে চান, তার ওপর এই [SkipFilter] বসানো।
  3. মূল Filter-এর ভেতরে context.Filters চেক করে দেখা যে SkipFilter আছে কি না। থাকলে return; করে এক্সিকিউশন থামিয়ে দেওয়া।

🔍 Comprehensive Breakdown

১. The Problem: Why do we need Filter Overrides? [Priority: 10/10]

The “Why”: রিয়েল-ওয়ার্ল্ড প্রোজেক্টে আমরা প্রায়ই Global বা Controller লেভেলে ফিল্টার অ্যাপ্লাই করি। উদাহরণস্বরূপ, আপনি PersonsController-এর ওপর AlwaysRunResultFilter অ্যাপ্লাই করেছেন। এর মানে হলো, এর ভেতরের Index, Create, Edit—সবগুলো অ্যাকশনেই এটি কাজ করবে। কিন্তু আপনার রিকোয়ারমেন্ট হলো: “সব অ্যাকশনে কাজ করুক, কিন্তু Index অ্যাকশনে এই ফিল্টারটি কাজ করবে না।” যেহেতু ASP.NET Core-এ [DisableFilter] জাতীয় কোনো ডিফল্ট অ্যাট্রিবিউট নেই, তাই আমাদের নিজেদের লজিক লিখে এটি সমাধান করতে হয়।

২. Step 1: Creating the Dummy Attribute (SkipFilter) [Priority: 10/10]

প্রথমে আমাদের একটি কাস্টম অ্যাট্রিবিউট তৈরি করতে হবে।

using System;
using Microsoft.AspNetCore.Mvc.Filters;
 
// ১. Attribute ক্লাসকে ইনহেরিট করতে হবে যাতে এটি [SkipFilter] হিসেবে ব্যবহার করা যায়।
// ২. IFilterMetadata ইমপ্লিমেন্ট করতে হবে যাতে ফ্রেমওয়ার্ক এটিকে Filter-এর লিস্টে অ্যাড করে।
public class SkipFilter : Attribute, IFilterMetadata
{
    // এর ভেতরে কোনো লজিক লেখার দরকার নেই! এটি শুধু একটি মার্কার (Marker) হিসেবে কাজ করবে।
}
 

কেন IFilterMetadata? ASP.NET Core যখন কোনো রিকোয়েস্ট প্রোসেস করে, তখন সে চেক করে ওই অ্যাকশনের ওপর কী কী ফিল্টার আছে। কোনো ক্লাস যদি IFilterMetadata ইমপ্লিমেন্ট না করে, তবে ফ্রেমওয়ার্ক তাকে Filter Collection-এ রাখে না। আমরা চাই আমাদের এই ডামি অ্যাট্রিবিউটটি যেন Collection-এ থাকে, তাই এই ইন্টারফেসটি জরুরি।

৩. Step 2: Applying the Attribute [Priority: 9/10]

এখন Controller এবং Action Method-এ ফিল্টারগুলো বসানোর পালা।

using Microsoft.AspNetCore.Mvc;
 
// Controller লেভেলে মূল ফিল্টারটি বসানো হলো (সবার জন্য কাজ করবে)
[TypeFilter(typeof(PersonsAlwaysRunResultFilter))]
public class PersonsController : Controller
{
    // এই মেথডটির জন্য আমরা ফিল্টারটি স্কিপ করতে চাই, তাই [SkipFilter] বসালাম
    [SkipFilter]
    public IActionResult Index()
    {
        return View();
    }
 
    // এর ওপর [SkipFilter] নেই, তাই এখানে মূল ফিল্টারটি ঠিকই কাজ করবে
    public IActionResult Edit()
    {
        return View();
    }
}
 

৪. Step 3: Implementing the Skip Logic in the Target Filter [Priority: 10/10]

এবার আমাদের মূল ফিল্টারে (PersonsAlwaysRunResultFilter) গিয়ে একটি if কন্ডিশন লিখতে হবে।

using Microsoft.AspNetCore.Mvc.Filters;
using System.Linq; // LINQ-এর জন্য
 
public class PersonsAlwaysRunResultFilter : IAlwaysRunResultFilter
{
    public void OnResultExecuting(ResultExecutingContext context)
    {
        // 🚀 THE OVERRIDE LOGIC 🚀
        // চেক করা হচ্ছে: এই অ্যাকশনের ওপর কি 'SkipFilter' নামের কোনো মেটাডেটা আছে?
        if (context.Filters.OfType<SkipFilter>().Any())
        {
            // যদি থাকে, তবে মেথড থেকে সরাসরি return করে দেওয়া হচ্ছে (লজিক স্কিপড!)
            return; 
        }
 
        // --- NORMAL FILTER LOGIC ---
        // যদি [SkipFilter] না থাকে, তবে নিচের কাজগুলো স্বাভাবিকভাবে হবে
        context.HttpContext.Response.Headers["X-Custom-Header"] = "Executed";
    }
 
    public void OnResultExecuted(ResultExecutedContext context)
    {
        // এখানেও একই চেক বসাতে হবে
        if (context.Filters.OfType<SkipFilter>().Any())
        {
            return;
        }
 
        // ... After logic ...
    }
}
 

কীভাবে কাজ করছে? যখন রিকোয়েস্ট Index মেথডে আসে, তখন context.Filters-এর ভেতরে SkipFilter খুঁজে পাওয়া যায় (.Any() true রিটার্ন করে)। ফলে ফিল্টারটি তার মূল কাজ না করেই return; হয়ে যায়।


🚀 Best Practices & .NET Modern Updates

Best Practices for Filter Overrides:

  1. Don’t Reinvent the Wheel for Authentication: লেকচারার বলেছেন, “Global লেভেলে Authorization দিয়ে নির্দিষ্ট পেজের জন্য স্কিপ করতে এই ট্রিক ব্যবহার করা যায়।” তবে মনে রাখবেন, Authentication/Authorization-এর জন্য ASP.NET Core-এ আগে থেকেই একটি বিল্ট-ইন ওভাররাইড আছে, যার নাম [AllowAnonymous]। তাই সিকিউরিটির ক্ষেত্রে এই ট্রিক ব্যবহার না করে সরাসরি [AllowAnonymous] ব্যবহার করাই বেস্ট প্র্যাকটিস। এই ট্রিকটি শুধুমাত্র আপনার কাস্টম ফিল্টারগুলোর (যেমন: Custom Logging, Caching) জন্য ব্যবহার করবেন।

.NET 10 & Minimal APIs Context (The Modern Way): .NET 10-এ Minimal API-তে Filter স্কিপ করার জন্য অ্যাট্রিবিউট বানানোর দরকার হয় না। সেখানে WithMetadata() ব্যবহার করে খুব সহজেই লজিক লেখা যায়।

Minimal API Example:

var app = WebApplication.CreateBuilder(args).Build();
 
// Endpoint Metadata-তে একটি কাস্টম ট্যাগ দিয়ে দেওয়া
app.MapGet("/api/skip-me", () => "No filter here!")
   .WithMetadata("SkipMyCustomFilter");
 
app.MapGet("/api/run-me", () => "Filter runs here!");
 
// Global Endpoint Filter
app.AddEndpointFilter(async (context, next) =>
{
    // মেটাডেটা চেক করা হচ্ছে
    if (context.HttpContext.GetEndpoint()?.Metadata.GetMetadata<string>() == "SkipMyCustomFilter")
    {
        return await next(context); // Skip logic and move to next
    }
 
    Console.WriteLine("Filter executed!");
    return await next(context);
});
 

আশা করি “Filter Overrides”-এর এই ট্রিকটি আপনি খুব সহজেই বুঝতে পেরেছেন! Filter নিয়ে আপনার কি আর কোনো কনফিউশন আছে, নাকি আমরা কোর্সের পরবর্তী লেকচার “Service Filter”-এর দিকে এগিয়ে যাব?