স্বাগতম! আমরা এখন আপনার কোর্সের Section 20 (Filters)-এর অত্যন্ত গুরুত্বপূর্ণ একটি টপিক—“Exception Filter” (লেকচার ২৯৭)-এ আছি।
অ্যাপ্লিকেশন ডেভেলপ করার সময় ভুল বা ক্র্যাশ (Runtime Error) হওয়াটা খুব স্বাভাবিক। কিন্তু একজন সাধারণ ইউজারের কাছে সেই ক্র্যাশের টেকনিক্যাল ডিটেইলস চলে যাওয়াটা মোটেও প্রফেশনাল নয়। আজ আমরা শিখব কীভাবে Exception Filter ব্যবহার করে স্পেসিফিক Action Method বা Controller-এর ক্র্যাশগুলো সুন্দরভাবে হ্যান্ডেল করা যায় এবং সিকিউরিটি মেইনটেইন করা যায়। চলুন শুরু করি!
📝 Quick Revision Summary
ভবিষ্যতে দ্রুত রিভিশন দেওয়ার জন্য আজকের লেকচারের মূল পয়েন্টগুলো নিচে দেওয়া হলো:
- Exception Filter কী: এটি রানটাইমে ঘটা আনহ্যান্ডেলড এক্সেপশন (Unhandled Exception) বা ক্র্যাশ ধরার জন্য ব্যবহৃত হয়।
- সীমিত স্কোপ (Scope Limitation): এটি পুরো অ্যাপ্লিকেশনের সব এরর ধরতে পারে না। এটি শুধুমাত্র Model Binding, Action Filter এবং Action Method-এর ভেতরে ঘটা এররগুলোই ধরতে পারে।
- Short-circuiting:
context.Result-এ কোনো রেজাল্ট অ্যাসাইন করলে অথবাcontext.ExceptionHandled = trueকরে দিলে, রিকোয়েস্ট শর্ট-সার্কিট হয়ে যায় এবং ডিফল্ট এরর পেজের বদলে আপনার কাস্টম রেসপন্স ব্রাউজারে যায়। - Environment Check: সিকিউরিটি নিশ্চিত করতে
IHostEnvironmentব্যবহার করে চেক করা হয় অ্যাপ্লিকেশনটি Development নাকি Production এনভায়রনমেন্টে আছে। প্রোডাকশনে কখনোই এক্সেপশনের বিস্তারিত তথ্য ক্লায়েন্টকে পাঠানো উচিত নয়।
🔍 Comprehensive Breakdown
১. The “Why” and Default Behavior [Priority: 10/10]
The “Why”: যখন আপনার Action Method-এর ভেতরে কোনো ক্র্যাশ হয় (যেমন: ডেটাবেসের নাম ভুল দেওয়া হয়েছে বা সার্ভার ডাউন), তখন ASP.NET Core ডিফল্টভাবে একটি HTTP 500 (Internal Server Error) রেসপন্স এবং একটি ডিফল্ট এরর পেজ ব্রাউজারে পাঠায়। কিন্তু আমরা চাই এই এররটি লগ (Log) করে রাখতে এবং ইউজারকে একটি সুন্দর কাস্টম মেসেজ (যেমন JSON বা সাধারণ টেক্সট) পাঠাতে। এই স্পেসিফিক কাজের জন্যই Exception Filter ব্যবহার করা হয়।
২. Execution Scope (কোথায় কাজ করে আর কোথায় করে না?) [Priority: 10/10]
এটি এই লেকচারের সবচেয়ে গুরুত্বপূর্ণ কনসেপ্ট। Exception Filter সব জায়গায় কাজ করে না।
- যেখানে কাজ করে: Model Binding, Action Filter (
OnActionExecuting/OnActionExecuted) এবং Action Method-এর ভেতরে কোনো এরর হলে এটি ফায়ার হবে। - যেখানে কাজ করে না: Middleware, Authorization Filter, Resource Filter বা Result Filter-এর ভেতরে কোনো এরর হলে Exception Filter সেটি ধরতে পারবে না। (এগুলোর জন্য Exception Handling Middleware ব্যবহার করতে হয়, যা আমরা পরের সেকশনে শিখব)।
৩. Creating the Exception Filter [Priority: 10/10]
Exception Filter তৈরি করতে IExceptionFilter (Synchronous) অথবা IAsyncExceptionFilter (Asynchronous) ইন্টারফেস ইমপ্লিমেন্ট করতে হয়।
Asynchronous Note: যদি আপনি IAsyncExceptionFilter ব্যবহার করেন এবং ভেতরে কোনো await কিওয়ার্ড না থাকে, তবে মেথডের শেষে অবশ্যই return Task.CompletedTask; লিখতে হবে, যাতে কম্পাইলার বুঝতে পারে মেথডের কাজ শেষ।
নিচে লেকচারে দেখানো সিঙ্ক্রোনাস ফিল্টারটির সম্পূর্ণ কোড দেওয়া হলো:
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Filters;
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging;
public class HandleExceptionFilter : IExceptionFilter
{
private readonly ILogger<HandleExceptionFilter> _logger;
private readonly IHostEnvironment _hostEnvironment;
// ১. Logger এবং HostEnvironment ইনজেক্ট করা হচ্ছে
public HandleExceptionFilter(ILogger<HandleExceptionFilter> logger, IHostEnvironment hostEnvironment)
{
_logger = logger;
_hostEnvironment = hostEnvironment;
}
public void OnException(ExceptionContext context)
{
// ২. এরর লগ করা হচ্ছে (Serilog বা ডিফল্ট লগারে সেভ হবে)
_logger.LogError("Exception Filter: {FilterName}.{MethodName}\nException Type: {ExceptionType}\nMessage: {ExceptionMessage}",
nameof(HandleExceptionFilter),
nameof(OnException),
context.Exception.GetType().Name,
context.Exception.Message);
// ৩. Environment চেক করা হচ্ছে (সিকিউরিটির জন্য)
if (_hostEnvironment.IsDevelopment())
{
// Development Environment: ডেভেলপারদের জন্য বিস্তারিত এরর মেসেজ পাঠানো হচ্ছে
context.Result = new ContentResult()
{
Content = context.Exception.Message,
StatusCode = 500
};
// Short-circuit হয়ে গেল!
}
else
{
// Production Environment: ইউজারদের কাছে বিস্তারিত এরর হাইড করে রাখা হচ্ছে।
// এখানে Result-এ কিছু অ্যাসাইন না করলে ডিফল্ট HTTP 500 পেজ চলে যাবে,
// অথবা আপনি চাইলে কাস্টম "Something went wrong" মেসেজ দিতে পারেন।
}
}
}
৪. Applying the Filter [Priority: 9/10]
যেহেতু আমরা চাই Controller-এর সব Action Method-এর এরর হ্যান্ডেল করতে, তাই আমরা সরাসরি Controller লেভেলে এটি অ্যাপ্লাই করব:
using Microsoft.AspNetCore.Mvc;
// Controller-এর সব মেথডের জন্য Exception Filter অ্যাপ্লাই করা হলো
[TypeFilter(typeof(HandleExceptionFilter))]
public class PersonsController : Controller
{
// ...
}
ডিবাগিং টিপস: লেকচারার এটি টেস্ট করার জন্য appsettings.json ফাইলে ডেটাবেসের নাম ভুল দিয়ে (যেমন persons database1) একটি SqlException তৈরি করেছিলেন। এর ফলে রিকোয়েস্ট Action Method থেকে সরাসরি Exception Filter-এ চলে আসে।
৫. Security Concept: Development vs Production [Priority: 10/10]
লেকচারের শেষের দিকের অংশটি ইন্ডাস্ট্রি স্ট্যান্ডার্ডের জন্য খুবই জরুরি।
IHostEnvironment.IsDevelopment() চেক করা হয় কারণ, প্রোডাকশনে (লাইভ সার্ভারে) যদি আপনি ইউজারের কাছে context.Exception.Message বা Stack Trace পাঠিয়ে দেন, তবে হ্যাকাররা আপনার ডেটাবেসের আর্কিটেকচার বা কোডের ভেতরের তথ্য জেনে যেতে পারে। তাই প্রোডাকশনে সবসময় সিক্রেট বা ইন্টারনাল এরর মেসেজগুলো হাইড করে জেনেরিক মেসেজ দিতে হয়।
🚀 Best Practices & .NET Modern Updates
Best Practices for Exception Handling:
- Prefer Global Exception Middleware: লেকচারার নিজেই বলেছেন, Exception Filter-এর চেয়ে Exception Handling Middleware ব্যবহার করা অনেক বেশি সেইফ এবং গ্লোবাল। কারণ মিডলওয়্যার অ্যাপ্লিকেশনের যেকোনো জায়গার (এমনকি অন্যান্য ফিল্টারের) এরর ধরতে পারে। Exception Filter শুধুমাত্র তখন ব্যবহার করবেন যখন আপনার স্পেসিফিক কোনো ১-২টি Action Method-এর জন্য ভিন্ন ধরনের এরর হ্যান্ডেলিং লজিক দরকার হয়।
.NET 10 & Modern Minimal API Context (The New Standard):
.NET 8/9/10 এবং Minimal APIs-এ Exception Filter-এর ব্যবহার প্রায় নেই বললেই চলে। আধুনিক .NET-এ গ্লোবাল এরর হ্যান্ডেল করার জন্য IExceptionHandler ইন্টারফেস নামক একটি নতুন এবং অত্যন্ত পাওয়ারফুল ফিচার নিয়ে আসা হয়েছে।
Modern .NET 10 Approach (IExceptionHandler):
// 1. Create a Global Exception Handler Class
public class GlobalExceptionHandler : IExceptionHandler
{
private readonly ILogger<GlobalExceptionHandler> _logger;
public GlobalExceptionHandler(ILogger<GlobalExceptionHandler> logger) => _logger = logger;
public async ValueTask<bool> TryHandleAsync(HttpContext httpContext, Exception exception, CancellationToken cancellationToken)
{
_logger.LogError(exception, "An unhandled exception occurred.");
httpContext.Response.StatusCode = 500;
await httpContext.Response.WriteAsJsonAsync(new { Error = "Server Error. Try again later." });
return true; // True means the exception was handled
}
}
// 2. In Program.cs (Registering the modern way)
builder.Services.AddExceptionHandler<GlobalExceptionHandler>();
builder.Services.AddProblemDetails(); // Standardizes error responses
var app = builder.Build();
app.UseExceptionHandler(); // Activates the handler
আপনার কোর্সের ঠিক পরের সেকশনেই Middleware দিয়ে গ্লোবাল এক্সেপশন হ্যান্ডেলিং নিয়ে বিস্তারিত আলোচনা করা হবে।
আজকের টপিকটি ক্লিয়ার হয়েছে তো?