স্বাগতম! আমরা এখন আপনার কোর্সের Section 20 (Filters)-এর “Result Filter” (লেকচার ২৯৪) টপিকে আছি।
আগের লেকচারগুলোতে আমরা Action Filter নিয়ে কাজ করেছি, যা Action Method এক্সিকিউট হওয়ার ঠিক আগে ও পরে কাজ করে। কিন্তু Action Method এক্সিকিউট হওয়া মানেই কিন্তু রেসপন্স ক্লায়েন্টের কাছে চলে যাওয়া নয়। Action Method সাধারণত একটি “Result” (যেমন: ViewResult, JsonResult) রিটার্ন করে। সেই Result এক্সিকিউট হওয়ার (অর্থাৎ View জেনারেট হয়ে HTML তৈরি হওয়া বা ডেটা JSON-এ কনভার্ট হওয়া) ঠিক আগে ও পরে যে ফিল্টারটি কাজ করে, সেটিই হলো Result Filter। চলুন বিস্তারিত জেনে নিই!
📝 Quick Revision Summary
ভবিষ্যতে দ্রুত রিভিশন দেওয়ার জন্য আজকের লেকচারের মূল পয়েন্টগুলো নিচে দেওয়া হলো:
- Result Filter কী: এটি Action Method এক্সিকিউট হওয়ার পরে, কিন্তু Action Result (যেমন: View বা JSON) এক্সিকিউট হওয়ার ঠিক আগে এবং পরে রান করে।
- Execution Sequence: Action Method -> Action Filter (
OnActionExecuted) -> Result Filter (Before) -> Action Result Execution (e.g., HTML Generation) -> Result Filter (After)。 - The “Before” Logic (
OnResultExecuting): এখানে চাইলে রেজাল্ট শর্ট-সার্কিট করা যায়। যেমন,ViewResult-এর বদলে ইউজারকেContentResultবাJsonResultপাঠিয়ে দেওয়া। অথবা View এক্সিকিউট হওয়ার আগেই ViewData মডিফাই করা। - The “After” Logic (
OnResultExecuted): রেজাল্ট এক্সিকিউট হওয়ার পর (অর্থাৎ HTML জেনারেট হওয়ার পর) “Last-minute changes” করা। যেমন— Response Body ফরম্যাট করা বা Response Header-এ ডেটা যুক্ত করা। - Real-World Usage: Result Filter সাধারণত খুব কম ব্যবহৃত হয়। এটি মূলত Response ফরম্যাটিং (যেমন XML থেকে JSON-এ রূপান্তর) বা ডায়নামিক হেডার যুক্ত করার কাজে ব্যবহৃত হয়।
🔍 Comprehensive Breakdown
১. Result Filter-এর Execution Path [Priority: 10/10]
The “Why”: Action Method থেকে যখন আমরা return View(); লিখি, তখন ভিউটি কিন্তু সাথে সাথে এক্সিকিউট (রেন্ডার) হয়ে যায় না। এটি শুধু একটি ViewResult অবজেক্ট রিটার্ন করে।
ফ্রেমওয়ার্ক যখন এই ViewResult-কে রেন্ডার করে HTML বানাতে যায়, ঠিক সেই মুহূর্তে Result Filter কাজ শুরু করে।
Execution Flow (The Big Picture):
- Model Binding
- Action Filter (
OnActionExecuting) - Action Method (Returns
ViewResult) - Action Filter (
OnActionExecuted) - Result Filter (
OnResultExecuting) ⬅️ (View রেন্ডার হওয়ার ঠিক আগে) - Action Result Executes (HTML Generated)
- Result Filter (
OnResultExecuted) ⬅️ (HTML রেন্ডার হওয়ার ঠিক পরে)
২. Syntax and Interface [Priority: 10/10]
Action Filter-এর মতোই Result Filter দুই ধরনের হয়:
- Synchronous:
IResultFilterইমপ্লিমেন্ট করতে হয় (দুটি মেথড:OnResultExecutingএবংOnResultExecuted)। - Asynchronous:
IAsyncResultFilterইমপ্লিমেন্ট করতে হয় (একটি মেথড:OnResultExecutionAsync)। আধুনিক অ্যাপ্লিকেশনে অ্যাসিন্ক্রোনাস অ্যাপ্রোচ বেশি প্রেফার করা হয়।
৩. Code Implementation: The Async Result Filter [Priority: 10/10]
লেকচারে একটি অ্যাসিন্ক্রোনাস রেজাল্ট ফিল্টার তৈরি করা হয়েছে যা View এক্সিকিউট হওয়ার ঠিক পরে (After Logic) Response-এ একটি Last-Modified হেডার যুক্ত করে।
using Microsoft.AspNetCore.Mvc.Filters;
using Microsoft.Extensions.Logging;
using System.Threading.Tasks;
using System;
// IAsyncResultFilter ইন্টারফেস ইমপ্লিমেন্ট করা হচ্ছে
public class PersonsListResultFilter : IAsyncResultFilter
{
private readonly ILogger<PersonsListResultFilter> _logger;
public PersonsListResultFilter(ILogger<PersonsListResultFilter> logger)
{
_logger = logger;
}
public async Task OnResultExecutionAsync(ResultExecutingContext context, ResultExecutionDelegate next)
{
// ----------------------------------------------------
// BEFORE LOGIC (OnResultExecuting)
// ----------------------------------------------------
_logger.LogInformation("{FilterName}.{MethodName} - BEFORE execution", nameof(PersonsListResultFilter), nameof(OnResultExecutionAsync));
// এখানে চাইলে শর্ট-সার্কিট করা যায়: (যেমন: context.Cancel = true; বা অন্য Result সেট করা)
// ----------------------------------------------------
// CALLING THE NEXT FILTER OR ACTION RESULT
// ----------------------------------------------------
// এই লাইনটি এক্সিকিউট হওয়ার অর্থ হলো, View রেন্ডার হয়ে HTML জেনারেট হচ্ছে
await next();
// ----------------------------------------------------
// AFTER LOGIC (OnResultExecuted)
// ----------------------------------------------------
_logger.LogInformation("{FilterName}.{MethodName} - AFTER execution", nameof(PersonsListResultFilter), nameof(OnResultExecutionAsync));
// View এক্সিকিউট হওয়ার পর (Last-minute change) রেসপন্স হেডারে টাইমস্ট্যাম্প যুক্ত করা হচ্ছে
context.HttpContext.Response.Headers["Last-Modified"] = DateTime.Now.ToString("yyyy-MM-dd HH:mm");
}
}
৪. Applying the Result Filter [Priority: 9/10]
Action Filter-এর মতোই इसे Controller-এর নির্দিষ্ট Action Method-এর উপরে অ্যাপ্লাই করতে হয়:
using Microsoft.AspNetCore.Mvc;
using CrudExample.Filters.ResultFilters;
public class PersonsController : Controller
{
// TypeFilter ব্যবহার করে Result Filter কল করা হচ্ছে
[TypeFilter(typeof(PersonsListResultFilter))]
public IActionResult Index()
{
return View();
}
}
৫. Debugging and Use Cases [Priority: 8/10]
- লেকচারার ডিবাগ করে দেখিয়েছেন যে,
await next()পার হওয়ার পর View এক্সিকিউট হয় এবং এরপর After Logic-এ এসে Header সেট হয়। - ব্রাউজারের Developer Tools (F12) -> Network Tab-এ গিয়ে দেখলে
Last-Modifiedনামের কাস্টম হেডারটি দেখা যাবে।
Real-World Use Cases (কখন ব্যবহার করবেন): লেকচারারের মতে, Result Filter প্রোডাকশনে খুব বেশি ব্যবহৃত হয় না। তবে নিচের কাজগুলোর জন্য এটি দরকারি:
- Response Formatting: যদি কোনো ক্লায়েন্ট XML রিকোয়েস্ট করে, আর আপনার API বাই-ডিফল্ট JSON রিটার্ন করে, তবে আপনি Result Filter-এর After Logic-এ JSON-কে পার্স করে XML-এ কনভার্ট করে দিতে পারেন।
- Global Header Injection: সমস্ত API রেসপন্সে সিকিউরিটি হেডার বা টাইমস্ট্যাম্প যুক্ত করা।
- Short-circuiting the Result: Action Method থেকে আসা ViewResult-কে থামিয়ে দিয়ে অন্য কোনো ContentResult রিটার্ন করা (Before Logic-এ)।
🚀 Best Practices & .NET Modern Updates
Best Practices for Result Filters:
- Don’t Manipulate Data Here: ডাটাবেস আপডেট বা লজিক্যাল কাজ Result Filter-এ করা উচিত নয়। এটি শুধুমাত্র UI/Response মডিফিকেশনের জন্য বরাদ্দ রাখুন।
- Beware of Exceptions:
await next()-এর পর (অর্থাৎ After Logic-এ) কোনো এক্সেপশন থ্রো হলে ক্লায়েন্টের কাছে ভুল রেসপন্স যেতে পারে, কারণ ততক্ষণে HTML বা JSON জেনারেট হয়ে রেসপন্স স্ট্রিমে লেখা শুরু হয়ে গেছে।
.NET 10 & API Context (Endpoint Filters):
.NET 10-এ Minimal API ব্যবহার করলে Result Filter-এর কনসেপ্টটি Endpoint Filter-এই কভার হয়ে যায়।
Endpoint Filter-এ await next()-এর পর যে রেজাল্টটি আসে, আপনি চাইলে সেটিকেই মডিফাই করতে পারেন।
app.MapGet("/api/persons", () => Results.Ok(new { Name = "John" }))
.AddEndpointFilter(async (context, next) =>
{
// Wait for the endpoint logic to run
var result = await next(context);
// Modify the result response headers (Like After Logic of Result Filter)
context.HttpContext.Response.Headers["X-Processed-By"] = "MinimalAPI-Filter";
return result;
});
আশা করি Result Filter-এর কনসেপ্টটি পুরোপুরি পরিষ্কার হয়েছে। পরবর্তী লেকচারে আমরা Resource Filter নিয়ে আলোচনা করব।