স্বাগতম! আমরা এখন আপনার কোর্সের 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):

  1. Model Binding
  2. Action Filter (OnActionExecuting)
  3. Action Method (Returns ViewResult)
  4. Action Filter (OnActionExecuted)
  5. Result Filter (OnResultExecuting) ⬅️ (View রেন্ডার হওয়ার ঠিক আগে)
  6. Action Result Executes (HTML Generated)
  7. 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:

  1. Don’t Manipulate Data Here: ডাটাবেস আপডেট বা লজিক্যাল কাজ Result Filter-এ করা উচিত নয়। এটি শুধুমাত্র UI/Response মডিফিকেশনের জন্য বরাদ্দ রাখুন।
  2. 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 নিয়ে আলোচনা করব।