স্বাগতম! আমরা এখন আপনার কোর্সের Section 20 (Filters)-এর “Resource Filter” (লেকচার ২৯৫) টপিকে আছি।
আমরা এতক্ষণে Action Filter এবং Result Filter নিয়ে বিস্তারিত জেনেছি। কিন্তু আপনি যদি Filter Pipeline-এর আর্কিটেকচার লক্ষ করেন, তবে দেখবেন Resource Filter একদম শুরুতেই (Authorization-এর পরপরই) কাজ করে এবং একদম শেষ পর্যায়ে গিয়ে শেষ হয়। অর্থাৎ এটি পুরো Pipeline-কে ঘিরে রাখে। আজ আমরা শিখব কেন এবং কখন এই পাওয়ারফুল ফিল্টারটি ব্যবহার করা উচিত। চলুন শুরু করি!
📝 Quick Revision Summary
ভবিষ্যতে দ্রুত রিভিশন দেওয়ার জন্য আজকের লেকচারের মূল পয়েন্টগুলো নিচে দেওয়া হলো:
-
Position in Pipeline: Authorization Filter -> Resource Filter (Before) -> Model Binding -> Action Filter -> Action Method -> Result Filter -> Resource Filter (After)।
-
The “Before” Logic (
OnResourceExecuting): এটি Model Binding হওয়ার আগেই রান করে। তাই যদি আপনার রিকোয়েস্টটিকে শুরুতেই শর্ট-সার্কিট (Short-circuit) করার প্রয়োজন হয়, তবে Resource Filter সবচেয়ে পারফরম্যান্ট (কারণ এটি মডেল বাইন্ডিং-এর মতো ভারী কাজগুলো হতে দেয় না)। -
The “After” Logic (
OnResourceExecuted): এটি পুরো রিকোয়েস্ট সাইকেল শেষ হওয়ার পর রান করে। সাধারণত Caching (রেসপন্স ক্যাশ করে রাখা) এর জন্য এটি ব্যবহৃত হয়। -
Common Use Case: * Unsupported Content-Type ব্লক করা।
-
সাময়িকভাবে কোনো Feature বা URL (Action Method) বন্ধ (Disable) করে রাখা।
-
Model Binding-এর আগেই Request Body বা Header মডিফাই করা।
-
Short-circuit Rules:
context.Result-এ ভ্যালু অ্যাসাইন করলে অবশ্যইawait next()কল করা থেকে বিরত থাকতে হবে, নতুবা রানটাইম এক্সেপশন থ্রো করবে।
🔍 Comprehensive Breakdown
১. Why Resource Filters? [Priority: 10/10]
The “Why”: আমরা এর আগে দেখেছি যে Action Filter-এর মাধ্যমেও রিকোয়েস্ট শর্ট-সার্কিট করা যায় (যেমন ভ্যালিডেশন ফেইল করলে)। তাহলে Resource Filter কেন দরকার?
Action Filter রান করার আগে ফ্রেমওয়ার্ককে Model Binding করতে হয়। অর্থাৎ, রিকোয়েস্ট থেকে JSON বা Form ডেটা রিড করে C# অবজেক্ট তৈরি করতে হয়। এটি মেমরি এবং প্রসেসিংয়ের দিক থেকে একটি ভারী কাজ। যদি আপনি আগেই জানেন যে এই রিকোয়েস্টটি আপনি প্রোসেস করবেন না (যেমন: একটি ফিচার সাময়িকভাবে বন্ধ আছে), তাহলে শুধু শুধু মডেল বাইন্ডিং করে মেমরি নষ্ট করার কোনো মানে নেই। যেহেতু Resource Filter মডেল বাইন্ডিংয়ের আগেই রান করে, তাই এখানেই শর্ট-সার্কিট করে দিলে অ্যাপ্লিকেশনের পারফরম্যান্স অনেক ভালো থাকে।
২. Creating an Async Resource Filter [Priority: 10/10]
লেকচারে একটি রিয়েল-ওয়ার্ল্ড ইউজ-কেস দেখানো হয়েছে— একটি Action Method-কে (যেমন Create সাবমিট) সাময়িকভাবে Disable করে রাখা।
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Filters;
using Microsoft.Extensions.Logging;
using System.Threading.Tasks;
// IAsyncResourceFilter ইন্টারফেস ইমপ্লিমেন্ট করা হচ্ছে
public class FeatureDisabledResourceFilter : IAsyncResourceFilter
{
private readonly ILogger<FeatureDisabledResourceFilter> _logger;
private readonly bool _isDisabled;
// isDisabled বাই-ডিফল্ট true রাখা হয়েছে
public FeatureDisabledResourceFilter(ILogger<FeatureDisabledResourceFilter> logger, bool isDisabled = true)
{
_logger = logger;
_isDisabled = isDisabled;
}
public async Task OnResourceExecutionAsync(ResourceExecutingContext context, ResourceExecutionDelegate next)
{
_logger.LogInformation("{FilterName}.{MethodName} - BEFORE", nameof(FeatureDisabledResourceFilter), nameof(OnResourceExecutionAsync));
// ---------------- SHORT-CIRCUIT LOGIC ----------------
if (_isDisabled)
{
// যদি ফিচারটি ডিজেবল থাকে, তবে সরাসরি 501 Not Implemented (বা 404) রিটার্ন করছি
// 501 মানে এটি ভবিষ্যতে আবার চালু হতে পারে (Temporarily Disabled)
// 404 মানে এটি চিরতরে ডিলিট হয়ে গেছে
context.Result = new StatusCodeResult(501);
// 🛑 CRITICAL: শর্ট-সার্কিট করলে next() কল করা যাবে না!
}
else
{
// ---------------- NORMAL EXECUTION ----------------
// যদি ফিচারটি চালু থাকে, তবেই আমরা Pipeline-কে সামনে এগোতে দেব
await next();
}
_logger.LogInformation("{FilterName}.{MethodName} - AFTER", nameof(FeatureDisabledResourceFilter), nameof(OnResourceExecutionAsync));
}
}
৩. Applying the Resource Filter [Priority: 9/10]
এই ফিল্টারটি Controller-এর Action Method-এর উপরে [TypeFilter] দিয়ে অ্যাপ্লাই করতে হয়:
using Microsoft.AspNetCore.Mvc;
public class PersonsController : Controller
{
// Feature-টি Disable করতে চাইলে (যেহেতু ফিল্টারে default true আছে)
[TypeFilter(typeof(FeatureDisabledResourceFilter))]
[HttpPost]
public IActionResult Create(PersonAddRequest personRequest)
{
// ... (লজিক)
}
// Feature-টি আবার Enable করতে চাইলে
// [TypeFilter(typeof(FeatureDisabledResourceFilter), Arguments = new object[] { false })]
// অথবা ফিল্টারটি পুরোপুরি রিমুভ/কমেন্ট করে দিতে হবে।
}
৪. The “Next Delegate” Exception [Priority: 10/10]
লেকচারার লাইভ কোডিংয়ের সময় একটি সুন্দর প্র্যাকটিক্যাল ভুল করে দেখিয়েছেন, যা থেকে অনেক কিছু শেখার আছে।
প্রথমে তিনি context.Result = new StatusCodeResult(501); লেখার ঠিক পরেই (if ব্লকের বাইরে) await next(); কল করেছিলেন।
এর ফলে রানটাইমে একটি বিশাল Error আসে।
কারণ: Resource Filter-এ যদি আপনি context.Result-এ কোনো রেজাল্ট সেট করেন, তবে ফ্রেমওয়ার্ক ধরে নেয় যে আপনি রিকোয়েস্টটি এখানেই শেষ করে দিচ্ছেন। এরপরেও যদি আপনি next() কল করেন (অর্থাৎ বলেন যে সামনের কাজগুলো করো), তখন ফ্রেমওয়ার্ক কনফিউজড হয়ে যায় এবং Exception থ্রো করে।
তাই সমাধান হলো else ব্লক ব্যবহার করে next() কল করা।
🚀 Best Practices & .NET Modern Updates
Best Practices for Resource Filters:
- Caching: Resource Filter-এর সবচেয়ে জনপ্রিয় ইউজ-কেস হলো Response Caching। Before Logic-এ আমরা ক্যাশ (Cache) চেক করি। ক্যাশে ডেটা থাকলে সরাসরি শর্ট-সার্কিট করে ডেটা রিটার্ন করি। আর না থাকলে
next()কল করে Action Method থেকে নতুন ডেটা আনি এবং After Logic-এ সেই ডেটা ক্যাশে সেভ করে রাখি। - Fail Fast: যদি রিকোয়েস্টের Content-Type ভুল হয় বা সাইজ খুব বড় হয়, তবে Resource Filter ব্যবহার করে শুরুতেই সেটি ব্লক করে দেওয়া উচিত (যাকে Fail Fast বলা হয়)।
.NET 10 & API Context (Endpoint Filters): .NET 10 বা Minimal APIs-এ আলাদা করে Resource Filter বা Action Filter-এর ক্লাসিফিকেশন নেই। সেখানে সবকিছুই Endpoint Filter। তবে আপনি যদি মডেল বাইন্ডিংয়ের আগে কিছু চেক করতে চান, তবে Endpoint Filter-এর শুরুতেই (যেখানে প্যারামিটারগুলো রিড করা হয়) চেকটি বসিয়ে দিতে পারেন।
app.MapPost("/api/persons", (PersonAddRequest req) => Results.Ok())
.AddEndpointFilter(async (context, next) =>
{
bool isFeatureDisabled = true; // Configuration থেকে আসতে পারে
// Model Binding-এর আগেই শর্ট-সার্কিট (Like a Resource Filter)
if (isFeatureDisabled)
{
return Results.StatusCode(501);
}
return await next(context);
});
আশা করি Resource Filter-এর কাজ এবং এর পজিশন সম্পর্কে আপনি পরিষ্কার ধারণা পেয়েছেন! পরবর্তী লেকচারে আমরা Pipeline-এর একদম প্রথম ফিল্টার—Authorization Filter নিয়ে আলোচনা করব।