আজকের টপিকে স্বাগতম! Outline অনুযায়ী আমরা এখন Section 20 (Filters)-এ আছি। আগের লেকচারে আমরা ফিল্টারের বেসিক আর্কিটেকচার নিয়ে জেনেছিলাম। আজ আমরা সরাসরি Action Filters-এর গভীরে প্রবেশ করব। আমরা দেখব কীভাবে একটি কাস্টম অ্যাকশন ফিল্টার তৈরি করতে হয়, কীভাবে সেটি রিকোয়েস্টের আগে ও পরে কাজ করে এবং ঠিক কী কী পাওয়ারফুল কাজ আমরা এর মাধ্যমে করতে পারি।
📝 Quick Revision Summary
ভবিষ্যতে দ্রুত রিভিশন দেওয়ার জন্য আজকের লেকচারের মূল পয়েন্টগুলো নিচে দেওয়া হলো:
- Core Methods: Action Filter-এর মূলত দুটি মেথড থাকে—
OnActionExecuting(Action Method রান করার ঠিক আগে) এবংOnActionExecuted(Action Method রান করার ঠিক পরে)। - Implementation: কাস্টম ফিল্টার বানাতে
IActionFilterইন্টারফেস ইমপ্লিমেন্ট করতে হয়। - Dependency Injection: ফিল্টারের কনস্ট্রাক্টরের মাধ্যমে খুব সহজেই অন্য সার্ভিস (যেমন
ILogger) ইনজেক্ট করা যায়। - Applying the Filter: Controller-এর নির্দিষ্ট অ্যাকশনের উপরে
[TypeFilter(typeof(YourFilterClass))]অ্যাট্রিবিউট ব্যবহার করে ফিল্টার অ্যাপ্লাই করতে হয়। - Key Use Cases: Parameter validation, View Data ম্যানিপুলেশন, Result পরিবর্তন করা এবং রিকোয়েস্টকে Short-circuit করা।
🔍 Comprehensive Breakdown
১. Action Filter-এর বেসিক ধারণা ও ইন্টারফেস [Priority: 10/10]
লেকচারের শুরুতেই বলা হয়েছে Action Filter-এর দুটি প্রধান অংশ নিয়ে। যখন Routing Middleware ঠিক করে ফেলে যে Controller-এর কোন Action Method-টি কল হবে, তখন সেই মেথডটি এক্সিকিউট হওয়ার ঠিক আগে এবং পরে Action Filter কাজ করে।
এটি তৈরি করতে আমাদের একটি সাধারণ ক্লাসে IActionFilter ইন্টারফেস ইমপ্লিমেন্ট করতে হয়। এর ফলে আমরা দুটি মেথড পাই:
OnActionExecuting(ActionExecutingContext context): এটি Action Method-এর আগে কল হয়।OnActionExecuted(ActionExecutedContext context): এটি Action Method-এর পরে কল হয়।
২. কাস্টম Action Filter তৈরি ও Dependency Injection [Priority: 10/10]
প্রজেক্টটি গুছিয়ে রাখার জন্য আমরা Filters ফোল্ডারের ভেতর ActionFilters নামে একটি সাবফোল্ডার তৈরি করে সেখানে PersonsListActionFilter নামের ক্লাস বানাব।
যেহেতু Action Filter নিজে একটি সার্ভিসের মতো কাজ করে, তাই আমরা Controller-এর মতোই এর ভেতরে Dependency Injection ব্যবহার করতে পারি। লেকচারে ILogger ইনজেক্ট করে দেখানো হয়েছে:
using Microsoft.AspNetCore.Mvc.Filters;
using Microsoft.Extensions.Logging;
namespace CrudExample.Filters.ActionFilters
{
public class PersonsListActionFilter : IActionFilter
{
private readonly ILogger<PersonsListActionFilter> _logger;
// Constructor Injection
public PersonsListActionFilter(ILogger<PersonsListActionFilter> logger)
{
_logger = logger;
}
public void OnActionExecuting(ActionExecutingContext context)
{
// Executes BEFORE the action method
_logger.LogInformation("This is from PersonsListActionFilter.OnActionExecuting");
}
public void OnActionExecuted(ActionExecutedContext context)
{
// Executes AFTER the action method
_logger.LogInformation("This is from PersonsListActionFilter.OnActionExecuted");
}
}
}
কেন (Why): এই লগিংয়ের মাধ্যমে আমরা ট্র্যাক করতে পারি রিকোয়েস্টটি ঠিক কখন ফিল্টারে প্রবেশ করেছে এবং কখন বের হয়েছে।
৩. Action Method-এ Filter অ্যাপ্লাই করা [Priority: 9/10]
ফিল্টার ক্লাস তো তৈরি হলো, কিন্তু এটি কাজ করবে কীভাবে? এর জন্য Controller-এর যে Action Method-এ আমরা ফিল্টারটি ব্যবহার করতে চাই, তার উপরে [TypeFilter] অ্যাট্রিবিউট বসাতে হবে।
using Microsoft.AspNetCore.Mvc;
using CrudExample.Filters.ActionFilters;
namespace CrudExample.Controllers
{
public class PersonsController : Controller
{
[TypeFilter(typeof(PersonsListActionFilter))]
public IActionResult Index()
{
// Actual Action Method Logic
return View();
}
}
}
কেন [TypeFilter]? সরাসরি [PersonsListActionFilter] না লিখে TypeFilter ব্যবহার করার কারণ হলো, আমাদের ফিল্টার ক্লাসে Dependency Injection (যেমন ILogger) আছে। TypeFilter নিজে থেকে সেই ডিপেন্ডেন্সিগুলো রিজল্ভ করে ফিল্টারের একটি অবজেক্ট তৈরি করে নেয়।
৪. Execution Sequence ও Debugging [Priority: 8/10]
লেকচারার ব্রেকপয়েন্ট (Breakpoint) বসিয়ে দেখিয়েছেন কোড কীভাবে রান করে।
- রিকোয়েস্ট আসার পর Model Binding সম্পন্ন হয়।
- এরপর
OnActionExecutingফায়ার হয়। - তারপর Controller-এর মূল
Indexমেথড কাজ করে (DB থেকে ডেটা আনা ইত্যাদি)। - Action Method থেকে যখন View Result রিটার্ন হয়, তখন ভিউ জেনারেট হওয়ার ঠিক আগে
OnActionExecutedকল হয়। - সবার শেষে HTML রেসপন্স ব্রাউজারে যায়।
💡 Pro Tip: লেকচারার ডিবাগিংয়ের সময় পরবর্তী লাইনে যাওয়ার জন্য F10 (Step Over) শর্টকাট ব্যবহার করেছেন। মনে রাখবেন, Visual Studio এবং Visual Studio Code—উভয় এডিটরেই ডিবাগিংয়ের সময় পরবর্তী লাইনে যাওয়ার শর্টকাট হলো F10।
৫. Action Filter-এর Use Cases (কেন ব্যবহার করব?) [Priority: 10/10]
লেকচারের শেষের দিকে Action Filter-এর বাস্তব প্রয়োগ নিয়ে আলোচনা করা হয়েছে:
-
OnActionExecuting-এর কাজ (আগে):
-
Manipulate/Validate Parameters: Action Method-এর প্যারামিটারগুলো চেক করা (যেমন
sortByবাsearchByইনভ্যালিড হলে ডিফল্ট ভ্যালু সেট করে দেওয়া)। -
Short-circuiting: যদি ইউজারের দেওয়া ডেটা ইনভ্যালিড হয়, তবে Controller মেথড পর্যন্ত রিকোয়েস্ট না পাঠিয়ে ফিল্টার থেকেই সরাসরি
IActionResult(যেমন Error View বা Redirect) রিটার্ন করে দেওয়া। -
ViewData Manipulation: Controller-এ যাওয়ার আগেই ViewData-তে কিছু গ্লোবাল ডেটা পুশ করা।
-
OnActionExecuted-এর কাজ (পরে):
-
Change Result: Controller থেকে যে Result (যেমন
ViewResult) রিটার্ন হচ্ছে, দরকার হলে সেটি পাল্টে অন্য কোনো Result (যেমনRedirectResult) পাঠানো। -
Exception Throwing: কোনো নির্দিষ্ট কন্ডিশনে এরর থ্রো করে ইউজারকে স্পেসিফিক এরর পেজে পাঠানো।
🚀 Best Practices & .NET 10 Updates
Best Practices for Action Filters:
- Use
IAsyncActionFilterinstead ofIActionFilter: যদি আপনার ফিল্টারের ভেতর কোনো ডেটাবেস কল বা নেটওয়ার্ক রিকোয়েস্ট থাকে, তবে সিঙ্ক্রোনাসIActionFilterব্যবহার করবেন না। এর বদলে অ্যাসিন্ক্রোনাস ভার্সন ব্যবহার করুন। - Keep it lightweight: ফিল্টার মূলত ক্রস-কাটিং কনসার্নের (যেমন লগিং, ক্যাশিং) জন্য। এর ভেতর কোনো বড় বিজনেস লজিক না রাখাই ভালো।
.NET 10 & Modern Approach (Code Implementation):
ট্রান্সক্রিপ্টে দেখানো সিঙ্ক্রোনাস অ্যাপ্রোচটি এখনো কাজ করে, তবে .NET 10-এর আধুনিক MVC এবং Web API ডেভেলপমেন্টে Async Filters ব্যবহার করাটা স্ট্যান্ডার্ড। নিচে IAsyncActionFilter-এর একটি আপডেটেড ইমপ্লিমেন্টেশন দেওয়া হলো:
using Microsoft.AspNetCore.Mvc.Filters;
using System.Threading.Tasks;
public class ModernAsyncActionFilter : IAsyncActionFilter
{
public async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next)
{
// 1. Executes BEFORE the action method (Like OnActionExecuting)
Console.WriteLine("Executing before the action...");
// 2. Call the next delegate/filter in the pipeline (or the action method itself)
var resultContext = await next();
// 3. Executes AFTER the action method (Like OnActionExecuted)
Console.WriteLine("Executing after the action...");
// Note: You can inspect resultContext.Result or resultContext.Exception here
}
}
এখানে দুটি আলাদা মেথডের বদলে একটি OnActionExecutionAsync মেথড দিয়েই আগে ও পরের কাজ অত্যন্ত পারফরম্যান্ট ওয়েতে হ্যান্ডেল করা যায়।