স্বাগতম! আপনার আউটলাইন অনুযায়ী আমরা এখন Section 20 (Filters)-এর “Filter Arguments” (লেকচার ২৮৮) টপিকে আছি।
আজকের টপিকটি খুবই ইন্টারেস্টিং! ধরুন, আপনি এমন একটি Action Filter বানালেন যা খুব দারুণ কাজ করে, কিন্তু আপনি চান বিভিন্ন Action Method-এর জন্য ফিল্টারটি ভিন্ন ভিন্ন ইনপুট বা ডেটা নিয়ে কাজ করুক। অর্থাৎ, ফিল্টারটিকে আমরা কীভাবে ডাইনামিক এবং রিইউজেবল (Reusable) করতে পারি, আজ আমরা ঠিক সেটাই শিখব। চলুন শুরু করা যাক!
📝 Quick Revision Summary
ভবিষ্যতে দ্রুত রিভিশনের জন্য আজকের লেকচারের মূল বিষয়গুলো নিচে দেওয়া হলো:
- Filter Arguments কী: Action Filter-কে ডাইনামিক করার জন্য Controller থেকে Filter-এর Constructor-এ ভ্যালু পাস করার পদ্ধতি।
- কেন ব্যবহার করব: একই ফিল্টার যেন ভিন্ন ভিন্ন Action Method-এ ভিন্ন ভিন্ন ডেটা (যেমন: আলাদা Header Key/Value) নিয়ে কাজ করতে পারে।
- কীভাবে রিসিভ করব: Filter ক্লাসের Constructor-এ Dependency Injection (যেমন ILogger) এর প্যারামিটারগুলোর ঠিক পরেই আমাদের কাস্টম প্যারামিটারগুলো (যেমন
key,value) ডিক্লেয়ার করতে হয়। - কীভাবে পাস করব: Action Method-এর উপরে
[TypeFilter(typeof(FilterClass), Arguments = new object[] { "Value1", "Value2" })]ব্যবহার করে। - Response Header ম্যানিপুলেশন:
context.HttpContext.Response.Headers-এর মাধ্যমে রেসপন্সের সাথে কাস্টম ডেটা ব্রাউজারে পাঠানো যায়।
🔍 Comprehensive Breakdown
১. Why Do We Need Filter Arguments? [Priority: 10/10]
The “Why”: আমরা যখন কোনো Action Filter তৈরি করি, তখন সেটি সাধারণত একটি নির্দিষ্ট লজিক এক্সিকিউট করে। কিন্তু ধরুন, আপনি এমন একটি ফিল্টার বানাতে চাচ্ছেন যা HTTP Response-এ একটি কাস্টম Header অ্যাড করবে।
এখন Index অ্যাকশনের জন্য আপনি হয়তো Header পাঠাতে চান X-Custom-Key: 12, আবার Create অ্যাকশনের জন্য পাঠাতে চান X-Custom-Key: 34।
যদি ফিল্টারের ভেতরেই ভ্যালুগুলো হার্ডকোড করে দেন, তবে এটি আর রিইউজেবল থাকল না। এই সমস্যা সমাধানের জন্যই আমরা Controller থেকে Filter-এ আর্গুমেন্ট পাস করি।
২. Creating a Parameterized Action Filter [Priority: 10/10]
প্রথমে আমরা ResponseHeaderActionFilter নামে একটি কাস্টম ফিল্টার ক্লাস তৈরি করব।
কীভাবে কাজ করে?
Constructor-এ আমরা প্রথমে রেগুলার সার্ভিস (যেমন ILogger) ইনজেক্ট করব। এর ঠিক পরেই আমরা আমাদের কাঙ্ক্ষিত আর্গুমেন্টগুলোর (যেমন key এবং value) জন্য প্যারামিটার তৈরি করব।
using Microsoft.AspNetCore.Mvc.Filters;
using Microsoft.Extensions.Logging;
namespace CrudExample.Filters.ActionFilters
{
public class ResponseHeaderActionFilter : IActionFilter
{
private readonly ILogger<ResponseHeaderActionFilter> _logger;
private readonly string _key;
private readonly string _value;
// Constructor-এ DI Service এবং Custom Parameters রিসিভ করা হচ্ছে
public ResponseHeaderActionFilter(ILogger<ResponseHeaderActionFilter> logger, string key, string value)
{
_logger = logger;
_key = key;
_value = value;
}
public void OnActionExecuting(ActionExecutingContext context)
{
_logger.LogInformation("{FilterName}.{MethodName} executes", nameof(ResponseHeaderActionFilter), nameof(OnActionExecuting));
}
public void OnActionExecuted(ActionExecutedContext context)
{
_logger.LogInformation("{FilterName}.{MethodName} executes", nameof(ResponseHeaderActionFilter), nameof(OnActionExecuted));
// Response-এর Header-এ কাস্টম Key-Value অ্যাড করা হচ্ছে
context.HttpContext.Response.Headers[_key] = _value;
}
}
}
৩. Applying the Filter and Passing Arguments [Priority: 10/10]
এবার এই ফিল্টারটিকে Controller-এর Action Method-এ অ্যাপ্লাই করার পালা। যেহেতু আমাদের ফিল্টারে কাস্টম আর্গুমেন্ট দরকার, তাই আমরা TypeFilter-এর Arguments প্রপার্টি ব্যবহার করব।
using Microsoft.AspNetCore.Mvc;
using CrudExample.Filters.ActionFilters;
namespace CrudExample.Controllers
{
public class PersonsController : Controller
{
// Arguments অ্যারেতে শুধু key এবং value পাঠানো হচ্ছে (ILogger DI নিজে থেকে ম্যানেজ করবে)
[TypeFilter(typeof(ResponseHeaderActionFilter), Arguments = new object[] { "X-Custom-Key", "Custom-Value-From-Index" })]
public IActionResult Index()
{
return View();
}
// অন্য Action Method-এ ভিন্ন আর্গুমেন্ট পাস করার উদাহরণ
[TypeFilter(typeof(ResponseHeaderActionFilter), Arguments = new object[] { "X-Custom-Key", "Custom-Value-From-Create" })]
public IActionResult Create()
{
return View();
}
}
}
গুরুত্বপূর্ণ বিষয়: Arguments = new object[] { ... } অ্যারেতে ভ্যালুগুলো ঠিক সেই ক্রমানুসারে (order) দিতে হবে, যেভাবে Constructor-এ প্যারামিটারগুলো ডিক্লেয়ার করা হয়েছে। Dependency Injection (যেমন ILogger) স্বয়ংক্রিয়ভাবে ইনজেক্ট হয়ে যায়, তাই আর্গুমেন্ট অ্যারেতে সার্ভিসের জন্য কোনো কিছু পাস করার দরকার নেই।
৪. Modifying HTTP Response Headers [Priority: 8/10]
উপরের ফিল্টার কোডে আমরা OnActionExecuted মেথডের ভেতরে context.HttpContext.Response.Headers[_key] = _value; লিখেছি।
Action Method এক্সিকিউট হওয়ার ঠিক পরে (কিন্তু রেজাল্ট ব্রাউজারে যাওয়ার আগে) আমরা Response অবজেক্টে একটি নতুন Header যুক্ত করে দিচ্ছি। সাধারণত API ডেভেলপমেন্টে ক্লায়েন্টকে অতিরিক্ত মেটাডেটা (Metadata) পাঠানোর জন্য এটি ব্যবহৃত হয় (যেমন: X-Pagination-Total-Count)।
৫. Debugging and Verification [Priority: 5/10]
লেকচারার ব্রেকপয়েন্ট বসিয়ে পুরো ফ্লো ডিবাগ করে দেখিয়েছেন।
- 💡 Shortcut Tip: লেকচারার Visual Studio-তে পরবর্তী লাইনে যাওয়ার জন্য
F10(Step Over) ব্যবহার করেছেন। আপনি যদি Visual Studio Code (VS Code) ব্যবহার করেন, সেখানেও ডিবাগিংয়ের সময় পরবর্তী লাইনে যাওয়ার শর্টকাটF10এবং পরবর্তী ব্রেকপয়েন্টে যাওয়ার জন্যF5(Continue)। - প্রজেক্ট রান করার পর ব্রাউজারের Developer Tools (F12) -> Network Tab-এ গিয়ে রিকোয়েস্টে ক্লিক করলে আপনি দেখতে পাবেন Response Headers-এর মধ্যে আপনার দেওয়া কাস্টম
"X-Custom-Key"এবং এর ভ্যালু চলে এসেছে।
৬. Next Topic Teaser (Filter Order) [Priority: 3/10]
লেকচারের শেষে একটি সুন্দর প্রশ্ন করা হয়েছে: যদি একটি Action Method-এর উপর একাধিক ফিল্টার (যেমন PersonsListActionFilter এবং ResponseHeaderActionFilter) বসানো থাকে, তবে কোন ফিল্টারটি আগে কাজ করবে? এই অর্ডার বা ক্রমানুসয় আমরা কীভাবে কন্ট্রোল করব? এটি নিয়েই পরবর্তী লেকচার “Custom Order of Filters”-এ আলোচনা করা হবে।
🚀 Best Practices & .NET 10 Updates
The Problem with [TypeFilter(..., Arguments = new object[] { ... })]:
লেকচারে দেখানো পদ্ধতিটি কাজ করলেও এটি ইন্ডাস্ট্রি স্ট্যান্ডার্ড Best Practice নয়। new object[] ব্যবহার করলে টাইপ সেফটি (Type safety) থাকে না। যদি আপনি ভুল করে স্ট্রিংয়ের জায়গায় ইন্টিজার পাস করেন, তবে কোড রানটাইমে গিয়ে ক্র্যাশ করবে (Compile time error দেবে না)।
.NET 10 Modern Approach (Strongly Typed Filter Attributes):
আধুনিক ASP.NET Core MVC/Web API-তে ম্যাজিক স্ট্রিং বা অবজেক্ট অ্যারে পরিহার করার জন্য আমরা সরাসরি Custom Attribute তৈরি করি, যা IFilterFactory ইমপ্লিমেন্ট করে। এটি অনেক বেশি ক্লিন এবং টাইপ-সেফ।
Modern Code Implementation: প্রথমে ফিল্টারটি আগের মতোই থাকবে, কিন্তু আমরা একটি নতুন Attribute তৈরি করব:
using Microsoft.AspNetCore.Mvc.Filters;
using Microsoft.Extensions.DependencyInjection;
using System;
// ১. কাস্টম অ্যাট্রিবিউট তৈরি
public class ResponseHeaderAttribute : Attribute, IFilterFactory
{
private readonly string _key;
private readonly string _value;
// Constructor-এ সরাসরি ভ্যালু রিসিভ করা
public ResponseHeaderAttribute(string key, string value)
{
_key = key;
_value = value;
}
public bool IsReusable => false;
// ২. রানটাইমে ফিল্টারের অবজেক্ট তৈরি করা এবং DI + Arguments পাস করা
public IFilterMetadata CreateInstance(IServiceProvider serviceProvider)
{
var logger = serviceProvider.GetRequiredService<ILogger<ResponseHeaderActionFilter>>();
return new ResponseHeaderActionFilter(logger, _key, _value);
}
}
Controller-এ ব্যবহার (The Clean Way):
এখন Controller-এ TypeFilter বা new object[] লেখার কোনো ঝামেলাই নেই!
public class PersonsController : Controller
{
// Extremely clean, type-safe, and professional!
[ResponseHeader("X-Custom-Key", "Awesome-Value")]
public IActionResult Index()
{
return View();
}
}
আপনার কোর্সের সামনের লেকচারগুলোতে (বিশেষ করে IFilterFactory লেকচারে) হয়তো এই আধুনিক পদ্ধতিটি সম্পর্কে আরও বিস্তারিত আলোচনা করা হবে।