স্বাগতম! আপনি এখন আপনার আউটলাইনের Section 20 (Filters)-এর তৃতীয় লেকচারে (Parameter Validation in Action Filter) আছেন। আগের লেকচারে আমরা Action Filter-এর বেসিক ধারণা এবং তৈরি করার নিয়ম শিখেছি। আজ আমরা দেখব Action Filter-এর একটি অন্যতম রিয়েল-লাইফ Use Case: Action Method Parameter Validation। অর্থাৎ, ইউজারের দেওয়া ডেটা Action Method-এ পৌঁছানোর আগেই কীভাবে আমরা ফিল্টারের মাধ্যমে চেক, ভ্যালিডেট এবং মডিফাই করতে পারি, তা আজ শিখব।
📝 Quick Revision Summary
- Action Arguments: Action Filter-এর
OnActionExecutingমেথডেcontext.ActionArgumentsব্যবহার করে আমরা Action Method-এর সমস্ত প্যারামিটার অ্যাক্সেস করতে পারি। - Validation Logic: রিকোয়েস্ট থেকে আসা প্যারামিটারের ভ্যালু আমাদের এক্সপেক্টেড ভ্যালুর সাথে ম্যাচ করে কি না, তা চেক করা যায়।
- Value Modification: ইউজার যদি ইনভ্যালিড ডেটা দেয় (যেমন:
searchBy=ABCD), ফিল্টারের মাধ্যমে আমরা সেটিকে ডিফল্ট ভ্যালু (যেমন:PersonName) দিয়ে ওভাররাইট করতে পারি। - Structured Logging: লগিংয়ের সময় ভেরিয়েবলের নাম সরাসরি লগে দিয়ে দেওয়া, যাতে পরে Seq বা অন্যান্য লগিং টুলে ফিল্টার করে সহজে খোঁজা যায়।
🔍 Comprehensive Breakdown
১. Why Parameter Validation in Action Filters? [Priority: 10/10]
কেন আমরা এই কাজটি ফিল্টারে করছি?
ধরুন, আপনার একটি Index অ্যাকশন মেথড আছে যেখানে ইউজাররা ডেটা সার্চ এবং সর্ট করতে পারে। এর জন্য searchBy এবং searchString নামের প্যারামিটার আছে।
এখন ইউজার যদি searchBy এর ভ্যালু হিসেবে এমন কিছু পাঠায় যা আপনার ডেটাবেসে বা টেবিলে নেই (যেমন: ABCD), তাহলে আপনার অ্যাপ্লিকেশনে এরর আসতে পারে বা ভুল রেজাল্ট দেখাতে পারে।
সাধারণত এই চেকিং বা ভ্যালিডেশন আমরা Controller-এর ভেতরেই করতে পারি। কিন্তু Best Practice হলো, Controller-কে যতটা সম্ভব ক্লিন এবং শুধুমাত্র বিজনেস লজিক কল করার কাজে ব্যবহার করা। তাই এই ভ্যালিডেশন এবং ডিফল্ট ভ্যালু সেট করার কাজটি আমরা Action Filter-এ (OnActionExecuting মেথডে) করে ফেলি। এতে Action Method-এ সবসময় ক্লিন এবং ভ্যালিডেটেড ডেটা প্রবেশ করে।
২. Accessing Action Method Parameters [Priority: 10/10]
Action Filter-এ OnActionExecuting(ActionExecutingContext context) মেথডের ভেতরে context.ActionArguments নামের একটি প্রপার্টি থাকে। এটি মূলত একটি ডিকশনারি (IDictionary<string, object>), যেখানে:
- Key: প্যারামিটারের নাম (যেমন:
"searchBy") - Value: ইউজারের দেওয়া প্যারামিটারের ভ্যালু (যেমন:
"ABCD")
Note: Model Binding প্রসেস Filter Pipeline-এর আগেই হয়ে যায়, তাই আপনি নিশ্চিত থাকতে পারেন যে রিকোয়েস্ট থেকে আসা ডেটাগুলো ActionArguments-এ রেডি আছে।
৩. Code Implementation: Parameter Validation and Modification [Priority: 10/10]
লেকচারে দেখানো কোডটি নিচে ধাপে ধাপে গুছিয়ে দেওয়া হলো:
using Microsoft.AspNetCore.Mvc.Filters;
using Microsoft.Extensions.Logging;
using System.Linq;
using System.Collections.Generic;
public class PersonsListActionFilter : IActionFilter
{
private readonly ILogger<PersonsListActionFilter> _logger;
public PersonsListActionFilter(ILogger<PersonsListActionFilter> logger)
{
_logger = logger;
}
public void OnActionExecuting(ActionExecutingContext context)
{
// ১. চেক করা হচ্ছে ইউজারের রিকোয়েস্টে "searchBy" প্যারামিটারটি আছে কিনা
if (context.ActionArguments.ContainsKey("searchBy"))
{
// ২. "searchBy" এর ভ্যালুটি রিড করা হচ্ছে
string? searchBy = Convert.ToString(context.ActionArguments["searchBy"]);
// ৩. আমাদের অনুমোদিত বা ভ্যালিড কলামগুলোর একটি লিস্ট তৈরি করছি
// nameof() ব্যবহার করার সুবিধা হলো, প্রপার্টির নাম পরিবর্তন হলে এখানেও অটো আপডেট হয়ে যাবে
var searchByOptions = new List<string>
{
nameof(PersonResponse.PersonName),
nameof(PersonResponse.Email),
nameof(PersonResponse.DateOfBirth),
nameof(PersonResponse.Gender),
nameof(PersonResponse.CountryID),
nameof(PersonResponse.Address)
};
// ৪. ভ্যালিডেশন: ইউজারের দেওয়া searchBy ভ্যালুটি কি আমাদের লিস্টে আছে?
if (searchBy != null && !searchByOptions.Any(option => option == searchBy))
{
// যদি ইউজারের দেওয়া ভ্যালু (যেমন: "ABCD") লিস্টে না থাকে, তবে লগিং করছি
_logger.LogWarning("searchBy actual value {searchBy} is invalid.", searchBy);
// ৫. মডিফিকেশন (Resetting): আমরা ভ্যালুটিকে ডিফল্ট "PersonName" দিয়ে রিপ্লেস করে দিচ্ছি
context.ActionArguments["searchBy"] = nameof(PersonResponse.PersonName);
// মডিফাই করার পর কনফার্মেশন লগ
_logger.LogInformation("searchBy updated value is {searchBy}", Convert.ToString(context.ActionArguments["searchBy"]));
}
}
}
public void OnActionExecuted(ActionExecutedContext context)
{
// Executes after the action method
}
}
৪. Execution Flow (কী ঘটছে এখানে?) [Priority: 9/10]
- ইউজার ব্রাউজারে রিকোয়েস্ট করল:
/persons/index?searchBy=ABCD - Model Binding: ফ্রেমওয়ার্ক
searchByএর ভ্যালুABCDহিসেবে ধরে নিল। - Action Filter
OnActionExecuting:
- ফিল্টার দেখল যে
ABCDকোনো ভ্যালিড কলাম নয়। - ফিল্টার
ActionArguments["searchBy"]এর ভ্যালু পরিবর্তন করেPersonNameকরে দিল।
- Action Method (
Index):
- কন্ট্রোলার যখন এক্সিকিউট হবে, তখন সে
searchByএর ভ্যালু হিসেবেABCDএর পরিবর্তে ফিল্টার থেকে সেট করে দেওয়াPersonNameরিসিভ করবে। - ফলে অ্যাপ্লিকেশনটি ভুল ইনপুটের কারণে ক্র্যাশ করার হাত থেকে বেঁচে গেল!
৫. Structured Logging [Priority: 8/10]
লেকচারে একটি গুরুত্বপূর্ণ টার্ম ব্যবহার করা হয়েছে— Structured Logging।
সাধারণত আমরা লগ লিখি এভাবে:
_logger.LogWarning("searchBy actual value is " + searchBy);
কিন্তু Structured Logging-এ আমরা ভেরিয়েবলকে প্লেসহোল্ডারের ভেতরে রাখি:
_logger.LogWarning("searchBy actual value {searchBy} is invalid.", searchBy);
উপকারিতা:
Seq বা অন্যান্য থার্ড-পার্টি লগিং ড্যাশবোর্ডে এই {searchBy} একটি আলাদা প্রপার্টি বা কলাম হিসেবে সেভ হয়। পরবর্তীতে আপনি ড্যাশবোর্ডে সার্চ বক্সে searchBy == "ABCD" লিখে ফিল্টার করে খুব সহজেই স্পেসিফিক লগ খুঁজে বের করতে পারবেন।
🚀 Best Practices & .NET 10 Updates
Best Practices for Parameter Validation in Filters:
- Use
nameof(): প্রপার্টির নাম হার্ডকোড (যেমন:"PersonName") করার চেয়ে সব সময়nameof(Model.Property)ব্যবহার করুন। এতে পরবর্তীতে মডেলের প্রপার্টির নাম চেঞ্জ হলে কোড ভাঙবে না। - Fail Fast vs Auto-Correct: এই লেকচারে ইনভ্যালিড ডেটাকে ডিফল্ট ডেটায় (Auto-correct) কনভার্ট করা হয়েছে। তবে অনেক সময় ভুল ডেটা আসলে রিকোয়েস্টটি সরাসরি রিজেক্ট করে দেওয়া (Fail Fast / Short-circuit) বেটার প্র্যাকটিস হতে পারে। (এটি পরবর্তী লেকচারগুলোতে কভার করা হবে)।
- Use FluentValidation: খুব কমপ্লেক্স ভ্যালিডেশনের জন্য Action Filter-এ ম্যানুয়াল কোড না লিখে FluentValidation লাইব্রেরি ব্যবহার করা ইন্ডাস্ট্রিতে স্ট্যান্ডার্ড।
.NET 10 & Minimal APIs Context:
এই সেকশনের আলোচনাটি মূলত MVC বা Controller-based API এর জন্য। .NET 10-এ যদি আপনি Minimal APIs ব্যবহার করেন, তবে এই একই ভ্যালিডেশন বা মডিফিকেশনের কাজটি Endpoint Filters দিয়ে করা যায়।
Minimal API Endpoint Filter Example (.NET 10):
app.MapGet("/api/persons", (string searchBy) =>
{
return $"Searching by: {searchBy}";
})
.AddEndpointFilter(async (context, next) =>
{
// Getting the parameter value by index
var searchBy = context.GetArgument<string>(0);
var validOptions = new[] { "PersonName", "Email" };
if (!validOptions.Contains(searchBy))
{
// Fail Fast approach - returning bad request immediately
return Results.BadRequest("Invalid search parameter.");
// OR Auto-correct approach (Requires modifying the argument logic which is trickier in endpoint filters)
}
return await next(context);
});
আশা করি পুরো লেকচারটি আপনার কাছে ক্লিয়ার হয়েছে! পরের লেকচারে আমরা Action Filter দিয়ে ViewData ম্যানিপুলেট করা শিখব।