স্বাগতম! আপনার Outline অনুযায়ী আমরা এখন Section 20 (Filters)-এর “Custom Order of Filters” (লেকচার ২৯০) টপিকে আছি।

আগের লেকচারে আমরা Global Filter এবং এর ডিফল্ট Execution Order (Global -> Controller -> Method) সম্পর্কে জেনেছিলাম। কিন্তু রিয়েল-ওয়ার্ল্ড প্রজেক্টে অনেক সময় আমাদের এই ডিফল্ট সিরিয়ালটি ভাঙার বা কাস্টমাইজ করার প্রয়োজন হতে পারে। আজ আমরা শিখব Order প্রপার্টি ব্যবহার করে কীভাবে ফিল্টার এক্সিকিউশনের সম্পূর্ণ কন্ট্রোল নিজের হাতে নেওয়া যায়। চলুন শুরু করি!


📝 Quick Revision Summary

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

  • Order Property: Order প্রপার্টির মাধ্যমে Filter এক্সিকিউশনের ডিফল্ট সিরিয়াল পরিবর্তন করা যায়।
  • Default Value: এক্সপ্লিসিটলি বলে না দিলে যেকোনো Filter-এর ডিফল্ট Order ভ্যালু থাকে 0
  • Accepted Values: Order প্রপার্টি যেকোনো Integer ভ্যালু (Positive, Negative, অথবা Zero) রিসিভ করতে পারে।
  • Execution Sequence (Before Action): OnActionExecuting-এর ক্ষেত্রে Ascending Order (ছোট থেকে বড়) ফলো করে। অর্থাৎ যার Order Number সবচেয়ে ছোট, সে আগে রান করবে।
  • Execution Sequence (After Action): OnActionExecuted-এর ক্ষেত্রে Descending Order (বড় থেকে ছোট) ফলো করে।
  • Tie Breaker: যদি একাধিক Filter-এর Order সমান হয়, তবে Scope-এর উপর ভিত্তি করে (Broader to Narrower) প্রায়োরিটি নির্ধারিত হয়।

🔍 Comprehensive Breakdown

১. Understanding the Order Property [Priority: 10/10]

The Concept: ফ্রেমওয়ার্ক যখন ফিল্টারগুলো এক্সিকিউট করতে যায়, তখন সে প্রথমেই তাদের Order নাম্বার চেক করে। বাই-ডিফল্ট সব ফিল্টারের অর্ডার 0 থাকে।

  • OnActionExecuting (Action Method-এর আগে): সিস্টেম Ascending Order ফলো করে। অর্থাৎ, Order = -10 আগে রান করবে, তারপর Order = 0, এরপর Order = 1
  • OnActionExecuted (Action Method-এর পরে): সিস্টেম ঠিক উল্টো, অর্থাৎ Descending Order ফলো করে। যার অর্ডার নাম্বার বেশি, সে আগে রান করবে।

২. Conflict Resolution (যখন Order Number সমান হয়) [Priority: 9/10]

ধরুন, আপনি Global, Controller এবং Method লেভেলে তিনটি ফিল্টার বসালেন, কিন্তু কোনোটিরই Order সেট করলেন না। তাহলে তিনটিরই Order হবে 0। এই অবস্থায় কে আগে রান করবে? উত্তর: যখন Order Number-এর মধ্যে Tie (সমান) হয়, তখন সিস্টেম আগের লেকচারে শেখা Scope Rule অ্যাপ্লাই করে। অর্থাৎ, Broader Scope আগে রান করবে (Global -> Controller -> Method)।

৩. Code Implementation: Changing the Default Order [Priority: 10/10]

ধরা যাক, আমাদের একটি রিকোয়ারমেন্ট আছে যেখানে আমরা চাই:

  1. Global Filter (Order = 0, Default) আগে রান করুক।
  2. এরপর Method Level Filter রান করুক।
  3. সবার শেষে Controller Level Filter রান করুক।

এই কাস্টম সিরিয়ালটি তৈরি করতে আমাদের [TypeFilter]-এর ভেতরে Order প্রপার্টি অ্যাসাইন করতে হবে।

using Microsoft.AspNetCore.Mvc;
using CrudExample.Filters.ActionFilters;
 
namespace CrudExample.Controllers
{
    // Controller Level Filter (আমরা চাই এটি Method-এর পরে রান করুক, তাই Order = 2 দিচ্ছি)
    [TypeFilter(typeof(ResponseHeaderActionFilter), Order = 2)]
    public class PersonsController : Controller
    {
        // Method Level Filter (আমরা চাই এটি Controller-এর আগে রান করুক, তাই Order = 1 দিচ্ছি)
        [TypeFilter(typeof(ResponseHeaderActionFilter), Order = 1)]
        public IActionResult Index()
        {
            return View();
        }
    }
}
 

ফলাফল (OnActionExecuting-এর ক্ষেত্রে):

  1. Global Filter (যেহেতু এর অর্ডার ডিফল্ট 0, তাই এটি সবচেয়ে ছোট)।
  2. Method Level Filter (কারণ এর অর্ডার 1)।
  3. Controller Level Filter (কারণ এর অর্ডার 2)।

৪. Why Change the Order? (Real-World Use Case) [Priority: 8/10]

আপনার মনে হতে পারে, “আমি কেন শুধু শুধু এই ডিফল্ট অর্ডার চেঞ্জ করতে যাব?” The “Why”: রিয়েল-ওয়ার্ল্ড প্রজেক্টে এমন পরিস্থিতি হতে পারে যেখানে একাধিক ফিল্টার একে অপরের উপর ডিপেন্ডেন্ট। ধরুন, আপনার দুটি Action Filter আছে— Filter A এবং Filter BFilter A ডেটাবেস থেকে কিছু সিকিউরিটি টোকেন ভ্যালিডেট করে সেটি HttpContext.Items-এ সেভ করে রাখে। আর Filter B সেই টোকেনটি রিড করে ডিসিশন নেয়। এক্ষেত্রে Filter B রান করার আগেই Filter A-কে অবশ্যই রান করতে হবে। এই সিরিয়াল গ্যারান্টি দেওয়ার জন্যই আমরা Filter A এর Order = 1 এবং Filter B এর Order = 2 সেট করে দিই।

৫. The Limitation with Global Filters [Priority: 7/10]

লেকচারের একদম শেষে একটি সমস্যার কথা বলা হয়েছে। আমরা [TypeFilter] ব্যবহার করে খুব সহজেই Controller বা Method লেভেলে Order সেট করতে পারি। কিন্তু Program.cs-এ যখন আমরা গ্লোবাল ফিল্টার অ্যাড করি, তখন সেখানে সরাসরি Order সেট করার কোনো প্রপার্টি থাকে না:

// Program.cs
builder.Services.AddControllersWithViews(options => {
    // এখানে Order সেট করার কোনো সরাসরি অপশন নেই!
    options.Filters.Add(new ResponseHeaderActionFilter(...)); 
});
 

এই সমস্যার সমাধান কী? কীভাবে আমরা গ্লোবাল ফিল্টারের অর্ডার কন্ট্রোল করব? এর সমাধান লুকিয়ে আছে IOrderedFilter ইন্টারফেসে, যা ঠিক এর পরের লেকচারেই আমরা শিখব!


🚀 Best Practices

Best Practices for Filter Ordering:

  1. Avoid Changing Orders if Unnecessary: যদি ফিল্টারগুলোর মধ্যে কোনো ডেটা ডিপেন্ডেন্সি (একে অপরের উপর নির্ভরশীলতা) না থাকে, তবে খামোখা Order প্রপার্টি পরিবর্তন করবেন না। ডিফল্ট স্কোপ-বেসড অর্ডারই (Global -> Controller -> Method) সবচেয়ে ভালো এবং সহজে বোধগম্য।
  2. Leave Gaps Between Order Numbers: যখন কাস্টম Order সেট করবেন, তখন 1, 2, 3 ব্যবহার না করে 10, 20, 30 ব্যবহার করা ইন্ডাস্ট্রি স্ট্যান্ডার্ড।
  • উদাহরণ: [TypeFilter(typeof(FilterA), Order = 10)] এবং [TypeFilter(typeof(FilterB), Order = 20)]
  • কারণ: ভবিষ্যতে যদি এই দুইয়ের মাঝখানে আপনার নতুন একটি ফিল্টার বসানোর প্রয়োজন হয়, তবে আপনি সহজেই Order = 15 দিয়ে দিতে পারবেন। 1, 2, 3 দিলে আপনাকে সবগুলো ফিল্টারের অর্ডার রিক্যালকুলেট করতে হতো।

আশা করি কনসেপ্টটি আপনার কাছে ক্লিয়ার হয়েছে! আপনি প্রস্তুত হলে আমরা পরের লেকচার (IOrderedFilter) শুরু করতে পারি।