হাসিব, চলো তোমার কোর্সের ৯৩ নম্বর লেকচারটি নিয়ে বিস্তারিত আলোচনা করি। আউটলাইন অনুযায়ী এটি (Section 8: Views - MVC Architecture Pattern) এর অংশ, যার শিরোনাম “Html.Raw”। আগের লেকচারে আমরা Local Functions দেখেছি, আর এর পরের টপিক হলো ViewData। এই লেকচারে মূলত Razor View-তে String এর ভেতরে থাকা HTML বা JavaScript কোডকে কীভাবে ব্রাউজারে এক্সিকিউট করানো যায় এবং এর Security রিস্ক কী, তা নিয়ে আলোচনা করা হয়েছে।

নিচে পুরো লেকচারটির বিস্তারিত ব্রেকডাউন দেওয়া হলো:

📝 Summary (সারসংক্ষেপ)

  • The Problem: Razor View বাই-ডিফল্ট যেকোনো String ভ্যারিয়েবলকে Sanitize বা HTML-Encode করে ফেলে। ফলে String-এর ভেতরে থাকা HTML বা JavaScript ট্যাগ ব্রাউজারে এক্সিকিউট না হয়ে সাধারণ টেক্সট হিসেবে প্রিন্ট হয়ে যায়।
  • The Solution: String-এর ভেতরে থাকা HTML বা JS কোডকে ব্রাউজারে সত্যিকার অর্থে এক্সিকিউট করতে চাইলে @Html.Raw() এক্সটেনশন মেথড ব্যবহার করতে হয়।
  • Security Risk: User Input-এর ওপর কখনোই Html.Raw() ব্যবহার করা উচিত নয়, কারণ এতে হ্যাকাররা Malicious code ইনজেক্ট করতে পারে (যাকে Cross-Site Scripting বা XSS Attack বলা হয়)।
  • Use Case: Controller থেকে পাঠানো কোনো Success/Error মেসেজ বা অ্যালার্ট দেখানোর জন্য এটি রিয়েল-ওয়ার্ল্ড প্রজেক্টে ব্যবহৃত হয়।

📌 The Problem: Razor Sanitization (HTML Encoding) [Priority: 10/10]

Why it happens? (কেন এমন হয়?) ধরে নাও, তুমি C#-এ একটি String ভ্যারিয়েবল তৈরি করেছ যার ভেতরে একটি JavaScript-এর ট্যাগ বা HTML-এর ট্যাগ আছে। তুমি যখন Razor View-তে সাধারণ Expression (যেমন- @alertMessage) দিয়ে সেটি প্রিন্ট করতে যাবে, তখন ASP.NET Core নিরাপত্তার স্বার্থে ওই কোডটিকে Sanitize করে ফেলে।

অর্থাৎ, সে এর < ব্র্যাকেটকে < তে রূপান্তর করে দেয় (যাকে HTML Encoding বলে)। এর ফলে ব্রাউজার এটিকে কোড হিসেবে না পড়ে সাধারণ প্লেইন টেক্সট হিসেবে স্ক্রিনে প্রিন্ট করে দেয়। এটি ASP.NET Core-এর একটি বিল্ট-ইন সিকিউরিটি ফিচার।


📌 The Solution: Using @Html.Raw() [Priority: 10/10]

যদি তুমি সত্যিই চাও যে তোমার String-এর ভেতরের HTML বা JavaScript কোডটি ব্রাউজারে এক্সিকিউট হোক (যেমন একটি Alert বক্স পপ-আপ করুক), তখন তোমাকে Razor-কে বলতে হবে যে “এই কোডটি নিরাপদ, তুমি এটিকে Sanitize কোরো না।” এই কাজটিই করে Html.Raw() মেথড।

🛠️ Code Implementation

লেকচারে দেখানো উদাহরণটি আমরা গুছিয়ে নিচে দেখছি। ইনস্ট্রাক্টর শুরুতে কোডটি @functions ব্লকে লিখেছিলেন, কিন্তু people কালেকশনের অ্যাক্সেস না পাওয়ায় পরে সেটি সাধারণ @{ … } কোড ব্লকে নিয়ে আসেন।

@{
    // একটি ডেমো কালেকশন (ধরে নিচ্ছি আগের লেকচারগুলোর মতো এখানে person ডাটা আছে)
    List<Person> people = new List<Person>
    {
        new Person { Name = "Hasib" },
        new Person { Name = "John" },
        new Person { Name = "Mary" }
    };
 
    // String Interpolation ($) ব্যবহার করে JavaScript কোড তৈরি করা হচ্ছে
    string alertMessage = $"<script>alert('{people.Count} people found');</script>";
}
 
<h3>User List</h3>
 
<!-- ❌ যদি এভাবে প্রিন্ট করো, তবে ব্রাউজারে শুধু টেক্সটটি লেখা উঠবে, অ্যালার্ট আসবে না -->
@* @alertMessage *@
 
<!-- ✅ Html.Raw ব্যবহার করলে ব্রাউজার কোডটিকে JavaScript হিসেবে এক্সিকিউট করবে -->
@Html.Raw(alertMessage)
 

কিভাবে কাজ করছে?

  • এখানে alertMessage ভ্যারিয়েবলে একটি JavaScript alert() ফাংশন স্টোর করা হয়েছে।
  • Html.Raw(alertMessage) কল করার ফলে Razor এটিকে Sanitize করবে না।
  • ব্রাউজার যখন পেজটি লোড করবে, তখন সে সত্যিকারের একটি ট্যাগ পাবে এবং স্ক্রিনে “3 people found” লেখা একটি অ্যালার্ট বক্স পপ-আপ করবে।

📌 Security Warning: The Dangers of Html.Raw() [Priority: 10/10]

লেকচারের শেষের দিকে ইনস্ট্রাক্টর অত্যন্ত গুরুত্বপূর্ণ একটি সিকিউরিটি ওয়ার্নিং দিয়েছেন। রিয়েল-ওয়ার্ল্ড প্রজেক্টে Html.Raw() ব্যবহারের ক্ষেত্রে চরম সতর্কতা অবলম্বন করতে হবে।

Why? (সমস্যা কোথায়?) যদি তুমি ইউজারের কাছ থেকে কোনো ইনপুট নাও (যেমন- কমেন্ট বক্স বা ফর্মের ডেটা) এবং সেটি সরাসরি @Html.Raw() দিয়ে প্রিন্ট করো, তবে সিস্টেম বড় ধরনের ঝুঁকিতে পড়বে।

একজন হ্যাকার ইনপুট বক্সে সাধারণ কমেন্ট না লিখে এমন একটি JavaScript কোড লিখে দিতে পারে:

তুমি যদি এই ইনপুটটি Html.Raw() দিয়ে রেন্ডার করো, তবে যে ইউজারই ওই পেজটি ভিজিট করবে, তার ব্রাউজারের কুকি (Cookie) এবং সেশন ডেটা চুরি হয়ে হ্যাকারের কাছে চলে যাবে। এই ধরনের অ্যাটাককে Cross-Site Scripting (XSS) বলা হয়।

Golden Rule:

  • শুধুমাত্র তোমার নিজের লেখা (Developer-generated) স্ট্যাটিক কোড বা লজিকের ওপর Html.Raw() ব্যবহার করবে।
  • User Input-এর ওপর কখনোই, কোনো অবস্থাতেই Html.Raw() ব্যবহার করবে না।

📌 Real World Use Cases [Priority: 7/10]

রিয়েল-ওয়ার্ল্ড অ্যাপ্লিকেশনে আমরা সাধারণত Controller থেকে View-তে Validation error message, Success message বা Toast notification (যেমন- SweetAlert2) দেখানোর জন্য এটি ব্যবহার করি। Controller একটি HTML ফরমেটেড String পাঠায় এবং View-তে আমরা সেটি Html.Raw() দিয়ে রেন্ডার করি।


⭐ Best Practices & Modern .NET 10 Context

যদিও Html.Raw() কাজ করে, তবে আধুনিক .NET 10 বা MVC প্রজেক্টে C# এর ভেতর থেকে HTML/JavaScript জেনারেট করাকে একটি “Bad Practice” বা Anti-pattern হিসেবে ধরা হয়। Separation of Concerns (SoC) অনুযায়ী, C# এর কাজ ডেটা প্রসেস করা, আর HTML/JS জেনারেট করার দায়িত্ব View এর।

Best Practice 1: Separate JS from C# (The Modern Way) C# String-এর ভেতর JavaScript না লিখে, Controller বা C# ব্লক থেকে ডেটা ViewBag বা data- অ্যাট্রিবিউট দিয়ে পাস করা উচিত এবং View-এর একদম নিচে আসল ট্যাগে সেটি পড়া উচিত।

Controller.cs / Razor Code Block:

@{
    // C# শুধু ডেটা প্রোভাইড করবে, কোনো HTML/JS লিখবে না
    int totalUsers = people.Count; 
}
 

View (.cshtml):

<!-- HTML 5 data-attribute এর মাধ্যমে ডেটা স্টোর করা -->
<div id="userData" data-user-count="@totalUsers"></div>
 
<!-- View এর ভেতরে ক্লিন JavaScript লেখা -->
<script>
    // JS দিয়ে ডেটা রিড করা এবং অ্যালার্ট দেওয়া
    const count = document.getElementById("userData").getAttribute("data-user-count");
    if(count > 0) {
        alert(`${count} people found`);
    }
</script>
 

Best Practice 2: Using IHtmlContent (If you must build HTML in backend) যদি Controller থেকে HTML বানিয়ে পাঠাতেই হয়, তবে সাধারণ string এর বদলে IHtmlContent বা HtmlString ব্যবহার করা আধুনিক এবং নিরাপদ প্র্যাকটিস।

// Controller.cs
public IActionResult Index()
{
    // এটি Razor View-তে গেলে বাই-ডিফল্ট Raw HTML হিসেবে রেন্ডার হবে। Html.Raw() দরকার হবে না।
    ViewBag.Notification = new HtmlString("<strong>Registration Successful!</strong>");
    return View();
}
 

Index.cshtml:

@* Html.Raw() এর প্রয়োজন নেই, কারণ ডেটা টাইপটি আগে থেকেই IHtmlContent *@
<div class="alert alert-success">
    @ViewBag.Notification
</div>