হ্যালো হাসিব! তুমি এখন Section 12: Dependency Injection-এর প্রথম লেকচার “Services - Part 1” (Lecture 128)-এ আছো। এই সেকশনটি পুরো ASP.NET Core-এর সবচেয়ে গুরুত্বপূর্ণ এবং হার্ট (Heart) বলা যায়।

আজকের লেকচারে আমরা শিখবো Service (বা Business Layer) কী, কেন Controller-এর ভেতরে বিজনেস লজিক লেখা উচিত নয় এবং কীভাবে একটি আলাদা Class Library প্রজেক্ট তৈরি করে Service বানাতে হয়।

চলো, এই লেকচারটি বিস্তারিতভাবে ডিকোড করি।


সারসংক্ষেপ (Quick Revision List)

  • Business Logic কী: ইনস্যুরেন্সের প্রিমিয়াম ক্যালকুলেট করা, বয়স চেক করা, বা ডাটাবেসে ডাটা সেভ করার আগে যে ভ্যালিডেশন বা ক্যালকুলেশনগুলো করা হয়, তাকেই Business Logic বলে।
  • কেন Controller-এ লজিক লিখবো না: Controller-এর কাজ শুধু ক্লায়েন্টের রিকোয়েস্ট রিসিভ করা এবং রেসপন্স পাঠানো। Controller-এ লজিক লিখলে কোড বিশাল হয়ে যায়, টেস্ট করা কঠিন হয় এবং পুনরায় ব্যবহার (Reuse) করা যায় না।
  • Service Layer কী: এটি Presentation Layer (Controller/View) এবং Data Layer (Database)-এর মাঝখানের একটি লেয়ার, যেখানে সমস্ত বিজনেস লজিক লেখা হয়।
  • Best Practice: Service ক্লাসগুলোকে ওয়েব প্রজেক্টের ভেতরে না রেখে, একটি আলাদা Class Library প্রজেক্টে রাখা উচিত। এতে কোড অন্যান্য প্রজেক্টেও (যেমন: Mobile App API) রিইউজ করা যায়।
  • Naming Convention: প্রাইভেট ফিল্ডের নামের আগে আন্ডারস্কোর (_) দিতে হয় (যেমন: _cities)। Service ক্লাসের নামের শেষে Service শব্দটি যুক্ত করতে হয় (যেমন: CitiesService)।

Comprehensive Breakdown

১. Business Logic কী? [Priority: 10/10]

লেকচারার খুব সুন্দর একটি উদাহরণ দিয়েছেন। ধরো তুমি একটি ইনস্যুরেন্স (Insurance) অ্যাপ্লিকেশন বানাচ্ছো। ইউজারের বয়স অনুযায়ী তার ইনস্যুরেন্স প্রিমিয়াম কত হবে, সেই হিসাব করাটা কোনো UI (HTML)-এর কাজ নয়, আবার ডাটাবেসের কাজও নয়। এই ক্যালকুলেশনের কাজটাই হলো Business Logic

  • Validation (বয়স ১৮ এর নিচে কি না)
  • Calculation (প্রিমিয়াম অ্যামাউন্ট কত)
  • Data Layer-কে কল করা (হিসাব শেষে ডাটাবেসে সেভ করতে বলা) এই সব কাজই Business Logic-এর অংশ।

২. Controller vs Service Layer [Priority: 10/10]

নতুন ডেভেলপাররা প্রায়ই একটি ভুল করে— তারা Controller-এর অ্যাকশন মেথডের ভেতরেই সব if-else, ডাটাবেস কোয়েরি বা লজিক লিখে ফেলে। এটি একটি Bad Practice

Controller-এ লজিক কেন লিখবো না?

  1. Fat Controller: Controller-এর কোড অনেক বড় হয়ে যায়, যা পড়া এবং ডিবাগ করা কঠিন।
  2. Hard to Test: Controller-কে Unit Test করা খুব ঝামেলার।
  3. Low Reusability: একই লজিক যদি অন্য কোনো Controller-এ লাগে, তখন কোড কপি-পেস্ট করতে হয়।

The Right Way: Presentation Layer (Controller/View) শুধু রিকোয়েস্ট রিসিভ করবে এবং Service-কে ডাকবে। Service তার লজিক শেষ করে ডাটাবেস (Data Access Layer)-কে ডাকবে।

৩. Project Setup এবং Class Library তৈরি [Priority: 10/10]

লেকচারার একটি নতুন ASP.NET Core Empty প্রজেক্ট তৈরি করেছেন, যার নাম দিয়েছেন DIExample। এরপর তিনি Service-এর জন্য একটি আলাদা প্রজেক্ট বানিয়েছেন।

Step A: Class Library তৈরি করা (The Best Practice) Service ক্লাসগুলোকে DIExample প্রজেক্টের ভেতরেও রাখা যেত, কিন্তু তিনি তা করেননি। তিনি সলিউশনের আন্ডারে একটি নতুন Class Library তৈরি করেছেন।

  • Why? কারণ Service-কে আলাদা প্রজেক্টে রাখলে তুমি চাইলে পরবর্তীতে ওই একই Service অন্য কোনো প্রজেক্টে (যেমন: Desktop App বা Mobile API) রেফারেন্স হিসেবে ব্যবহার করতে পারবে।
  • How:
  1. Solution-এর উপর Right Click -> Add -> New Project
  2. সার্চ করো: Class Library (অবশ্যই .NET Framework নয়, শুধু Class Library যা C# এবং .NET/ .NET Standard সাপোর্ট করে)।
  3. প্রজেক্টের নাম দাও Services এবং .NET ভার্সন সেম রাখো।

৪. Service Class তৈরি করা (Implementation) [Priority: 10/10]

এবার Services প্রজেক্টের ভেতরে আমরা আমাদের প্রথম Service Class তৈরি করবো, যা কিছু শহরের নাম রিটার্ন করবে (আপাতত ডাটাবেসের বদলে হার্ডকোডেড লিস্ট ব্যবহার করা হয়েছে)।

Naming Convention Rules:

  1. Class Name: ক্লাসের নামের শেষে Service লিখতে হবে। যেমন City এর প্লুরাল Cities + Service = CitiesService.cs
  2. Private Fields: প্রাইভেট ভ্যারিয়েবলের নামের শুরুতে _ (underscore) দিতে হবে। যেমন _cities। এটি গ্লোবাল স্ট্যান্ডার্ড।

Code Implementation (Services/CitiesService.cs):

using System.Collections.Generic;
 
namespace Services
{
    public class CitiesService
    {
        // ১. Private field (Prefix with underscore)
        private List<string> _cities;
 
        // ২. Constructor-এর ভেতরে ডাটা ইনিশিয়ালাইজ করা (Mock Data)
        public CitiesService()
        {
            _cities = new List<string>()
            {
                "London",
                "Paris",
                "New York",
                "Tokyo",
                "Rome"
            };
        }
 
        // ৩. Public Method (Controller এই মেথডকে কল করবে)
        public List<string> GetCities()
        {
            return _cities; // লিস্ট রিটার্ন করে দিবে
        }
    }
}
 
  • (নোট: রিয়েল-ওয়ার্ল্ড প্রজেক্টে Constructor-এ হার্ডকোডেড ডাটা থাকে না, সেখানে Data Access Layer বা Entity Framework-কে কল করা হয়। যেহেতু আমরা এখনো ডাটাবেস শিখিনি, তাই Mock Data ব্যবহার করা হয়েছে)।

VS / VS Code Shortcuts

  • Create Constructor: ক্লাসের ভেতরে ctor লিখে Tab + Tab চাপলে অটোমেটিক কনস্ট্রাক্টর তৈরি হয়ে যায়।
  • Add Project Reference (VS Code): টার্মিনালে dotnet add reference ../Services/Services.csproj লিখলে মূল প্রজেক্টে Services প্রজেক্টের রেফারেন্স অ্যাড হয়ে যাবে।

Best Practices & .NET 10 Context

Best Practices for Services:

  1. Strict Layer Separation: Controller কখনোই সরাসরি ডাটাবেসের (DbContext) সাথে কথা বলবে না। Controller কথা বলবে Service-এর সাথে, আর Service কথা বলবে Database-এর সাথে।
  2. Meaningful Method Names: মেথডের নামগুলো এমন হওয়া উচিত যা পড়লেই কাজ বোঝা যায়। যেমন: GetCities, CalculatePremium, CreateUser

.NET 10 Context: ASP.NET Core 10-এ Service Layer বা Class Library বানানোর কনসেপ্ট .NET 6/7/8-এর মতোই হুবহু এক।

তবে আধুনিক C# 12/13 (যা .NET 8, 9 এবং 10 এ ব্যবহৃত হচ্ছে)-তে আমরা Field initialization-কে কনস্ট্রাক্টরের বদলে সরাসরি ফিল্ড লেভেলেই করে ফেলি (Target-typed new expression & Collection Expression):

// Modern .NET 10 style
namespace Services; // File-scoped namespace
 
public class CitiesService
{
    // C# 12 Collection Expression '[]'
    private readonly List<string> _cities = ["London", "Paris", "New York", "Tokyo", "Rome"];
 
    public List<string> GetCities()
    {
        return _cities;
    }
}
 

(এখানে readonly কি-ওয়ার্ড ব্যবহার করা বেস্ট প্র্যাকটিস, কারণ লিস্টটি একবার ইনিশিয়ালাইজ হওয়ার পর আর রি-অ্যাসাইন হওয়ার দরকার নেই)।

হাসিব, Service Layer এবং Class Library-এর এই বেসিক কনসেপ্ট কি ক্লিয়ার হয়েছে? তুমি রেডি থাকলে আমরা “Services - Part 2”-তে মুভ করতে পারি, যেখানে আমরা এই Service-কে Controller-এর সাথে কানেক্ট করবো!