হ্যালো হাসিব! আজকের লেকচারে আমরা শিখবো কীভাবে CsvHelper প্যাকেজ ব্যবহার করে CSV ফাইলের ডাটাকে কাস্টমাইজ (Customize) করা যায়।
আগের লেকচারে আমরা ডিফল্ট মেথড (WriteRecords) ব্যবহার করেছিলাম, যা সবগুলো প্রপার্টি নিজে থেকেই লিখে দিত। কিন্তু রিয়েল-ওয়ার্ল্ড রিকোয়ারমেন্টে অনেক সময় নির্দিষ্ট কিছু কলাম হাইড করতে হয় বা ডেট ফরম্যাট চেঞ্জ করতে হয়। এই লেকচারটি মূলত সেই সমস্যারই ম্যানুয়াল সমাধান নিয়ে।
চলো লেকচারটির একটি কুইক সামারি এবং বিস্তারিত আলোচনা শুরু করি।
📝 Lecture Summary at a Glance
- The Problem:
WriteRecords()ব্যবহার করলে কোন কলাম আগে যাবে বা কার ফরম্যাট কেমন হবে, তা কন্ট্রোল করা যায় না। - The Solution: কাস্টমাইজেশনের জন্য
WriteField()মেথড ব্যবহার করে একটি একটি করে ভ্যালু নিজে হাতে ফাইলে লিখতে হয়। - Configuration:
CsvConfigurationঅবজেক্ট তৈরি করে কালচার (যেমনCultureInfo.InvariantCulture) সেট করতে হয়। - The Workflow: প্রথমে হেডারগুলো
WriteField()দিয়ে লিখতে হয়, এরপরNextRecord()কল করে প্রতিটি রো-এর জন্য লুপ চালিয়ে ডাটা লিখতে হয়। - The Flush Error: লুপের ভেতরে ডাটা লেখার পর অবশ্যই
Flush()কল করতে হবে, নতুবা ডাটাMemoryStream-এ সেভ না হয়ে ফাইল ফাঁকা আসবে।
🧠 Comprehensive Breakdown & Deep Dive
১. CsvConfiguration সেটআপ করা [Importance: 8/10]
- The “Why”: CsvWriter-কে বলতে হয় যে ডাটা কোন কালচার বা ল্যাঙ্গুয়েজের স্ট্যান্ডার্ড অনুযায়ী ফরম্যাট হবে (যেমন ডেট বা ডেসিমাল পয়েন্ট)।
💻 Code Implementation:
using CsvHelper;
using CsvHelper.Configuration;
using System.Globalization;
using System.IO;
var csvConfiguration = new CsvConfiguration(CultureInfo.InvariantCulture)
{
// এখানে তুমি চাইলে কাস্টমাইজেশন করতে পারো, যেমন:
// HasHeaderRecord = true,
// Delimiter = ","
};
var memoryStream = new MemoryStream();
var streamWriter = new StreamWriter(memoryStream, leaveOpen: true);
var csvWriter = new CsvWriter(streamWriter, csvConfiguration);
২. Manually Writing Headers (হেডার তৈরি করা) [Importance: 9/10]
- The “Why”: তুমি যদি চাও যে CSV ফাইলে
PersonIdবাAddressকলাম থাকবে না, তাহলে তোমাকে নিজে হাতে শুধু প্রয়োজনীয় কলামগুলোর নাম লিখতে হবে। - The
nameoftrick: হার্ডকোড করে স্ট্রিং ("PersonName") না লিখেnameof(PersonResponse.PersonName)ব্যবহার করা বেস্ট প্র্যাকটিস। এতে ভবিষ্যতে প্রপার্টির নাম চেঞ্জ করলে এখানেও অটোমেটিক আপডেট হয়ে যাবে।
💻 Code Implementation:
// ১. হেডার কলামগুলো নিজে হাতে লেখা
csvWriter.WriteField(nameof(PersonResponse.PersonName));
csvWriter.WriteField(nameof(PersonResponse.Email));
csvWriter.WriteField(nameof(PersonResponse.DateOfBirth));
csvWriter.WriteField(nameof(PersonResponse.Country));
// ২. হেডার লেখা শেষ হলে পরের লাইনে যাওয়া
csvWriter.NextRecord();
৩. Manually Writing Records (ডাটা তৈরি করা) [Importance: 10/10]
- The “Why”: হেডারের সিরিয়াল অনুযায়ী এখন ডাটাগুলোকে লুপের মাধ্যমে লিখতে হবে। এখানে তুমি চাইলে কাস্টম ফরম্যাটিং (যেমন ডেট ফরম্যাট
yyyy-MM-dd) অ্যাপ্লাই করতে পারো।
💻 Code Implementation:
foreach (var person in personResponses)
{
csvWriter.WriteField(person.PersonName);
csvWriter.WriteField(person.Email);
// DateOfBirth null কিনা চেক করে কাস্টম ফরম্যাটে লেখা
if (person.DateOfBirth.HasValue)
{
csvWriter.WriteField(person.DateOfBirth.Value.ToString("yyyy-MM-dd"));
}
else
{
csvWriter.WriteField(""); // null থাকলে ফাঁকা রাখা
}
csvWriter.WriteField(person.Country);
// এক লাইনের ডাটা লেখা শেষ হলে পরের লাইনে যাওয়া
csvWriter.NextRecord();
// ডাটা বাফার থেকে MemoryStream-এ ফ্লাশ করা (এটি না দিলে ফাইল ফাঁকা আসবে!)
csvWriter.Flush();
}
// স্ট্রিম পজিশন শুরুতে আনা
memoryStream.Position = 0;
return memoryStream;
🚀 Modern .NET 10 Updates & Architecture Best Practices
The Reality Check (Is this the best way?):
হাসিব, লেকচারার যে ম্যানুয়াল লুপ এবং WriteField() পদ্ধতি দেখিয়েছেন, তা খুবই আদিম (primitive) এবং ক্লিন আর্কিটেকচারের পরিপন্থী। তোমার মডেলে যদি ২০টি প্রপার্টি থাকে, তবে তোমাকে ম্যানুয়ালি ২০ বার WriteField() লিখতে হবে। কোনো একটির সিরিয়াল ভুল হলে পুরো ডাটা উলটপালট হয়ে যাবে!
✅ The Smart Alternative (ClassMap):
আধুনিক CsvHelper ডেভেলপমেন্টে Class Mapping ব্যবহার করা হয়। এটি লেকচারের ম্যানুয়াল পদ্ধতির চেয়ে বহুগুণ বেশি ক্লিন এবং প্রফেশনাল। তোমাকে লুপ চালিয়ে ফিল্ড লিখতে হবে না!
💻 Pro Tip Implementation (Clean Architecture):
১. প্রথমে একটি ম্যাপার ক্লাস তৈরি করো:
using CsvHelper.Configuration;
public class PersonResponseMap : ClassMap<PersonResponse>
{
public PersonResponseMap()
{
// শুধু যে কলামগুলো চাও সেগুলো ম্যাপ করো (বাকিগুলো ইগনোর হবে)
Map(p => p.PersonName).Name("Name"); // হেডারের নাম কাস্টমাইজ করা
Map(p => p.Email).Name("Email Address");
// DateOfBirth এর ফরম্যাট এখান থেকেই কন্ট্রোল করা যায়!
Map(p => p.DateOfBirth).Name("DOB").TypeConverterOption.Format("yyyy-MM-dd");
Map(p => p.Country).Name("Country");
}
}
২. এবার তোমার Service মেথডে এই ম্যাপারটি রেজিস্টার করে দাও:
var csvWriter = new CsvWriter(streamWriter, CultureInfo.InvariantCulture, leaveOpen: true);
// ম্যাপার ক্লাসটি রেজিস্টার করা হলো
csvWriter.Context.RegisterClassMap<PersonResponseMap>();
// ম্যাজিক! লুপ ছাড়াই সে ম্যাপার অনুযায়ী কাস্টম হেডার ও ডাটা লিখে দেবে!
await csvWriter.WriteRecordsAsync(personResponses);
await csvWriter.FlushAsync();
memoryStream.Position = 0;
return memoryStream;
এই ClassMap পদ্ধতিটি ব্যবহার করলে তোমার কোড অনেক বেশি মেনটেইনেবল হবে এবং ভুলের পরিমাণ শূন্যে নেমে আসবে।
পরবর্তী লেকচারে এক্সেল (Excel) ফাইল তৈরি করার টপিক নিয়ে আলোচনা হবে। তুমি রেডি হলে সেই ট্রান্সক্রিপ্টটি দিতে পারো!