এই লেকচারে শিখানো হয়েছে কীভাবে Program.cs থেকে মিডলওয়্যারের কোড সরিয়ে একটি আলাদা রিইউজেবল (Reusable) ক্লাসে নিয়ে যাওয়া যায়। এর জন্য IMiddleware ইন্টারফেস ব্যবহার করা, সার্ভিস হিসেবে রেজিস্টার করা এবং ডিপেন্ডেন্সি ইনজেকশন (DI) এর মাধ্যমে পাইপলাইনে যুক্ত করার পুরো প্রসেস এখানে কভার করা হয়েছে।


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

ক) কেন কাস্টম মিডলওয়্যার ক্লাস দরকার?

সব কোড যদি Program.cs-এ থাকে, তবে ফাইলটি মেইনটেইন করা অসম্ভব হয়ে পড়ে। আলাদা ক্লাস তৈরি করলে:

  • কোড পরিষ্কার থাকে (Clean Code)।
  • একই লজিক অন্য প্রজেক্টে বা অন্য জায়গায় সহজে ব্যবহার করা যায় (Reusability)।
  • ইউনিট টেস্টিং করা সহজ হয়।

খ) ক্লাসের গঠন ও IMiddleware ইন্টারফেস

একটি ক্লাসকে মিডলওয়্যার হিসেবে গণ্য করতে হলে তাকে IMiddleware ইন্টারফেসটি ইমপ্লিমেন্ট করতে হয়।

  • এই ইন্টারফেসটি আমাদের InvokeAsync মেথডটি লিখতে বাধ্য করে।
  • এই মেথডটি দুটি প্যারামিটার নেয়: HttpContext context এবং RequestDelegate next

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

ধরা যাক, আমরা MyCustomMiddleware.cs নামে একটি ফাইল তৈরি করছি।

**ফাইল: CustomMiddleware/MyCustomMiddleware.cs**

using Microsoft.AspNetCore.Http;
using System.Threading.Tasks;
 
namespace MiddlewareExample.CustomMiddleware
{
    // IMiddleware ইন্টারফেস ইমপ্লিমেন্ট করতে হবে
    public class MyCustomMiddleware : IMiddleware
    {
        public async Task InvokeAsync(HttpContext context, RequestDelegate next)
        {
            // ১. "Before" Logic: পরবর্তী মিডলওয়্যারে যাওয়ার আগে যা ঘটবে
            await context.Response.WriteAsync("My Custom Middleware Starts...\n");
 
            // ২. পরবর্তী মিডলওয়্যারকে কল করা
            await next(context);
 
            // ৩. "After" Logic: পরবর্তী মিডলওয়্যার থেকে ফিরে আসার পর যা ঘটবে
            await context.Response.WriteAsync("My Custom Middleware Ends...\n");
        }
    }
}
 

ঘ) মিডলওয়্যার রেজিস্টার করা (Dependency Injection)

কাস্টম মিডলওয়্যার সরাসরি ব্যবহার করা যায় না। আগে তাকে builder.Services এ অ্যাড করতে হয়।

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

using MiddlewareExample.CustomMiddleware;
 
var builder = WebApplication.CreateBuilder(args);
 
// কাস্টম মিডলওয়্যারকে সার্ভিস হিসেবে রেজিস্টার করা (Transient হিসেবে)
builder.Services.AddTransient<MyCustomMiddleware>();
 
var app = builder.Build();
 
// ১. প্রথম মিডলওয়্যার (Inline)
app.Use(async (context, next) => {
    await context.Response.WriteAsync("Middleware 1 Starts...\n");
    await next();
    await context.Response.WriteAsync("Middleware 1 Ends...\n");
});
 
// ২. কাস্টম মিডলওয়্যার ক্লাস ব্যবহার (UseMiddleware ব্যবহার করতে হয়)
app.UseMiddleware<MyCustomMiddleware>();
 
// ৩. টার্মিনেটিং মিডলওয়্যার
app.Run(async (context) => {
    await context.Response.WriteAsync("Hello from Middleware 3 (Terminating)\n");
});
 
app.Run();
 

ঙ) এক্সিকিউশন ফ্লো (কিভাবে কাজ করে)

১. রিকোয়েস্ট আসলে প্রথমে Middleware 1 এর ‘Before’ অংশ চলে। ২. তারপর MyCustomMiddleware এর InvokeAsync শুরু হয়। ৩. সেখান থেকে next(context) কল হলে Middleware 3 (Terminating) চলে। ৪. সব শেষে উল্টো পথে ফিরে আসার সময় MyCustomMiddleware এর ‘After’ অংশ এবং শেষে Middleware 1 এর ‘After’ অংশ শেষ হয়।


৩. Added Context (Gaps Filled)

  • কেন AddTransient?: IMiddleware ইন্টারফেস ব্যবহার করলে ডটনেট কোর সেটাকে ডিফল্টভাবে ইনজেক্ট করতে পারে না। তাই সার্ভিস কন্টেইনারে এটাকে বলে দিতে হয়। Transient মানে হলো প্রতিবার রিকোয়েস্টের সময় এই ক্লাসের একটি নতুন অবজেক্ট তৈরি হবে।
  • Use vs UseMiddleware: সাধারণ ল্যামডা ফাংশনের জন্য আমরা app.Use ব্যবহার করি, কিন্তু পুরো ক্লাসের জন্য app.UseMiddleware<T> ব্যবহার করা বাধ্যতামূলক।
  • অর্ডার (Order) কেন গুরুত্বপূর্ণ?: পাইপলাইনে তুমি যেভাবে কোড লিখবে (Sequence), মিডলওয়্যার ঠিক সেই সিরিয়ালেই কাজ করবে। যদি তুমি app.Run এর নিচে UseMiddleware দাও, তবে সেটা কখনোই এক্সিকিউট হবে না কারণ app.Run পাইপলাইন শর্ট-সার্কিট করে দেয়।

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

  1. আলাদা ফোল্ডার: সবসময় কাস্টম মিডলওয়্যারগুলোকে Middlewares বা CustomMiddleware নামক আলাদা ফোল্ডারে রাখো।
  2. Extension Method (পরবর্তী লেকচারের টপিক): সরাসরি app.UseMiddleware<ClassName>() কল না করে একটি এক্সটেনশন মেথড তৈরি করা ভালো (যেমন: app.UseMyCustomMiddleware()), এতে Program.cs দেখতে অনেক সুন্দর লাগে।
  3. Single Responsibility: একটি মিডলওয়্যারে অনেক কাজ না করে ছোট ছোট আলাদা মিডলওয়্যার তৈরি করো (যেমন: একটি লগিং এর জন্য, অন্যটি অথেন্টিকেশন এর জন্য)।
  4. Async/Await: মিডলওয়্যারে সবসময় async এবং await ব্যবহার করবে যাতে থ্রেড ব্লক না হয় এবং পারফরম্যান্স ভালো থাকে।

হাসিব, এখানে বিশেষ গুরুত্ব দিবে:

  • Priority 1: IMiddleware ইন্টারফেস এবং InvokeAsync মেথডের সিগনেচার মনে রাখা।
  • Priority 2: Program.cs-এ AddTransient দিয়ে সার্ভিস রেজিস্টার করা (নয়তো এরর দিবে)।

পুরো বিষয়টি কি পরিষ্কার হয়েছে? কোথাও কোনো কনফিউশন থাকলে বলো! এরপর আমরা শিখবো কীভাবে এটাকে আরও সহজ করতে Extension Method ব্যবহার করা যায়।

তুমি কি চাও আমি এই মিডলওয়্যারের এক্সিকিউশন ফ্লো নিয়ে একটি টেবিল তৈরি করে দেই?