হাসিব! আজকের এই লেকচার ট্র্যান্সক্রিপ্টে আমরা শিখবো UseWhen মেথড সম্পর্কে, যা ASP.NET Core-এ মিডলওয়্যারের ব্রাঞ্চিং (Branching) বা কন্ডিশনাল এক্সিকিউশনের জন্য ব্যবহৃত হয়।

আগের লেকচারগুলোতে আমরা দেখেছি যে সব মিডলওয়্যার পরপর (Linearly) এক্সিকিউট হয়। কিন্তু যদি আমরা চাই যে, “শুধুমাত্র একটি নির্দিষ্ট শর্ত পূরণ হলেই একটি বিশেষ মিডলওয়্যার চলবে, নাহলে স্কিপ করে যাবে”, তখন আমরা UseWhen ব্যবহার করি।

চলো বিস্তারিত আলোচনা করি।


১. Topic Overview (বিষয়বস্তু)

এই লেকচারের মূল ফোকাস হলো UseWhen মেথডের মাধ্যমে মিডলওয়্যার পাইপলাইনে একটি শর্তসাপেক্ষ শাখা (Conditional Branch) তৈরি করা। ইনস্ট্রাক্টর দেখিয়েছেন কীভাবে রিকোয়েস্টের Query String-এ নির্দিষ্ট কোনো Key (যেমন: isAuthorized বা username) থাকলে একটি এক্সট্রা মিডলওয়্যার চালানো যায় এবং কাজ শেষে আবার মূল পাইপলাইনে ফিরে আসা যায়।


২. Detailed Breakdown (ধাপে ধাপে আলোচনা ও কোড)

ক) UseWhen কীভাবে কাজ করে?

UseWhen মেথড মূলত দুটি আর্গুমেন্ট (Argument) বা প্যারামিটার নেয়:

  1. Predicate (Condition): একটি ল্যাম্বডা এক্সপ্রেশন যা রিকোয়েস্ট চেক করে true বা false রিটার্ন করে।
  2. Configuration (Branch): আরেকটি ল্যাম্বডা এক্সপ্রেশন যেখানে নতুন মিডলওয়্যারগুলো যুক্ত করা হয় (এটি কেবল তখন চলবে যখন প্রথম শর্তটি true হবে)।

খ) Execution Flow (এক্সিকিউশন ফ্লো)

  • রিকোয়েস্ট আসার পর ডটনেট UseWhen এর শর্ত চেক করে।
  • যদি শর্ত False হয়: সে ওই UseWhen ব্লককে পুরোপুরি স্কিপ করে মূল পাইপলাইনের পরবর্তী মিডলওয়্যারে চলে যায়।
  • যদি শর্ত True হয়: সে UseWhen এর ভেতরের মিডলওয়্যারগুলো এক্সিকিউট করে এবং সেগুলোর কাজ শেষ হলে আবার মূল পাইপলাইনে ফিরে আসে এবং বাকি মিডলওয়্যারগুলো চালায় (যদি টার্মিনেট না করা হয়)।

গ) প্র্যাকটিক্যাল কোড ইমপ্লিমেন্টেশন

ধরা যাক, আমরা চাই যদি ইউজার URL-এ ?username=Harsha লিখে রিকোয়েস্ট করে, তবেই আমরা তাকে একটি স্পেশাল মেসেজ দেখাবো।

**ফাইল: Program.cs**

var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();
 
// ১. UseWhen - কন্ডিশনাল ব্রাঞ্চিং
app.UseWhen(
    // প্রথম আর্গুমেন্ট: শর্ত (Condition)
    context => context.Request.Query.ContainsKey("username"),
    
    // দ্বিতীয় আর্গুমেন্ট: ব্রাঞ্চের কনফিগারেশন (কী ঘটবে)
    appBuilder =>
    {
        appBuilder.Use(async (context, next) =>
        {
            await context.Response.WriteAsync("Hello from UseWhen Branch! \n");
            
            // ব্রাঞ্চের কাজ শেষ, এবার মূল পাইপলাইনে ফিরে যাওয়ার নির্দেশ
            await next(); 
        });
    }
);
 
// ২. Main Pipeline-এর সাধারণ মিডলওয়্যার
app.Use(async (context, next) =>
{
    await context.Response.WriteAsync("Hello from Middleware Chain! \n");
    await next();
});
 
// ৩. Terminating Middleware
app.Run(async context =>
{
    await context.Response.WriteAsync("End of Pipeline.\n");
});
 
app.Run();
 

ঘ) টেস্টিং এবং আউটপুট

সিনারিও ১: শর্ত False হলে (সাধারণ রিকোয়েস্ট)

  • URL: http://localhost:5000/ (কোনো username নেই)
  • আউটপুট:
Hello from Middleware Chain! 
End of Pipeline.
 

(UseWhen ব্লকটি পুরোপুরি স্কিপ হয়েছে)

সিনারিও ২: শর্ত True হলে (Query String সহ)

  • URL: http://localhost:5000/?username=Harsha
  • আউটপুট:
Hello from UseWhen Branch! 
Hello from Middleware Chain! 
End of Pipeline.
 

(প্রথমে UseWhen ব্লকটি চলেছে, এরপর সে মূল পাইপলাইনে ফিরে গিয়ে বাকিগুলোও এক্সিকিউট করেছে!)


৩. Added Context (Gaps Filled) - ইন্টারনাল মেকানিজম

তোমার মনে একটা প্রশ্ন আসতে পারে: “UseWhen-এর ভেতর থেকে তো await next() কল করেছি, কিন্তু এরপরের মিডলওয়্যারটা তো UseWhen-এর ব্লকের বাইরে। সে বাইরে গেল কীভাবে?”

এর পেছনের জাদুকরী কারণ হলো Rejoining the Main PipelineUseWhen এর সবচেয়ে বড় বৈশিষ্ট্য হলো, এটি একটি “Sub-pipeline” বা উপ-শাখা তৈরি করে। যখন উপ-শাখার সব কাজ শেষ হয়ে যায়, ডটনেট ফ্রেমওয়ার্ক নিজে থেকেই রিকোয়েস্টটিকে আবার মূল পাইপলাইনের (Main Chain) যেখান থেকে সে আলাদা হয়েছিল, ঠিক তার পরের স্টেপে যুক্ত করে দেয়।

বাস্তব জীবনের উদাহরণ: মনে করো তুমি হাইওয়ে দিয়ে ঢাকা থেকে চট্টগ্রাম যাচ্ছো (Main Pipeline)। মাঝপথে কুমিল্লায় তুমি দেখলে একটা সাইনবোর্ড: “যদি আপনার ক্ষুধা লাগে (Condition), তবে এই সার্ভিস রোডে (UseWhen Branch) যান।” তুমি সার্ভিস রোডে গেলে, রেস্টুরেন্টে খেলে (Middleware Execution), এবং খাওয়া শেষ করে তুমি আবার সেই মূল হাইওয়েতেই (Main Pipeline) ফিরে আসলে! যদি তোমার ক্ষুধা না লাগতো, তুমি সোজা হাইওয়ে দিয়েই চলে যেতে।


৪. C# Best Practices (প্রফেশনাল টিপস)

  1. Don’t overcomplicate the condition: UseWhen-এর প্রথম প্যারামিটারে (Condition) খুব ভারী বা সময়সাপেক্ষ কাজ (যেমন ডাটাবেজ কোয়েরি) করা উচিত নয়। এটি শুধুমাত্র Request Object (Headers, Query String, Path) চেক করার জন্য ব্যবহার করা ভালো।
  2. Short-circuiting in UseWhen: তুমি চাইলে UseWhen ব্রাঞ্চের ভেতর থেকে await next() কল না করে রিকোয়েস্টকে টার্মিনেটও করতে পারো (যেমন: appBuilder.Run(...))। সেক্ষেত্রে রিকোয়েস্ট আর মূল পাইপলাইনে ফিরে আসবে না। এটি সাধারণত Authorization ফেইল হলে Error রেসপন্স পাঠানোর জন্য ব্যবহৃত হয়।
  3. MapWhen vs UseWhen: ডটনেটে MapWhen নামে আরেকটি মেথড আছে। UseWhen কাজ শেষ করে মূল পাইপলাইনে ফিরে আসে, কিন্তু MapWhen কখনোই মূল পাইপলাইনে ফেরে না (এটি টার্মিনেটিং ব্রাঞ্চ তৈরি করে)। এটি সম্পর্কে তুমি পরবর্তী লেকচারগুলোতে শিখবে।