سایت pluralsight ویدیوهای آموزشی بسیار با کیفیتی را در مورد مباحث مختلف دات نت تا بحال تهیه کرده و تقریبا هر موضوع جدیدی هم که اضافه میشود، بلافاصله یک سری جدید را تهیه میکنند. مدرسین انتخابی هم عموما افراد نامدار و باسوادی هستند.
پروژهای رو در سایت کدپلکس شروع کردم جهت تهیه زیرنویس فارسی برای این ویدیوها:
این کار نسبت به کار تهیه زیرنویسهای فارسی موجود برای فیلمهای انگلیسی کار سختتری است به چند دلیل:
- اسکریپت آمادهای وجود ندارد. کار شنیداری است.
- زمانبندی آمادهای وجود ندارد.
- مباحث تخصصی است.
- مدرس از ثانیه اول ویدیو تا ثانیه آخر آن حرف میزند!
برای مثال جهت تهیه زیرنویسهای فارسی فیلمهای انگلیسی عموما به سایتهایی مانند subscene.com مراجعه میشود. یک زیرنویس یا به قولی اسکریپت آماده یافت شده و شروع به ترجمه میشود. متن آماده است. زمانبندی آماده است و فقط کار ترجمه باقی میماند.
اما در مورد ویدیوهای آموزشی انگلیسی خیر. به همین جهت در این زمینه کار آنچنانی تابحال صورت نگرفته.
کار زمانبری است. فعلا رکورد من برای هر سه دقیقه ویدیوی آموزشی که مدرس از ثانیه اول تا آخر آن حرف میزند، 40 دقیقه کار تهیه زیر نویس فارسی زمانبندی شده است.
سری جدیدی رو که شروع کردم تحت عنوان «Building Windows 8 Metro Apps in C# and XAML» در سایت pluralsight ارائه شده.
فعلا قسمت اول آن زیرنویس دار شده و از اینجا قابل دریافت است. برای مشاهده آنها برنامه با کیفیت و رایگان KMPlayer توصیه میشود.
لیست ویدیوهای قسمت اول آن به شرح زیر است:
Building Windows 8 Metro Apps in C# and XAML
Overview 00:50:41
This modules provides an overview of how to develop Windows 8 Metro style applications in C# and XAML.
Introduction
XAML and Codebehind
Asynchronous APIs
Demo: Asynchronous APIs
Files and Networking
Demo: Requesting Capabilities
Integrating with Windows 8
WinRT and .NET
Summary
کلمه سی شارپ در این قسمت کمی غلط انداز است. بیشتر بحث و توضیح است تا کد نویسی. بنابراین برای عموم قابل استفاده است. خصوصا نگاهی دارد به تازههای ویندوز 8 از دیدگاه برنامه نویسها مانند سطوح دسترسی برنامههای مترو، معرفی Charms ، نحوه به اشتراک گذاری اطلاعات در بین برنامههای مترو نصب شده، برای مثال جایی که دیگر Clipboard سابق وجود ندارد و مواردی از این دست.
5 قسمت دیگر این مبحث باقیمانده که هر زمان تکمیل شد، خبرش رو خواهید شنید و تقریبا از این پس این سایت به همین ترتیب جلو خواهد رفت. فکر میکنم اینطوری مفیدتر باشد. هر از چندگاهی یک مبحث جدید زیرنویس دار شده را میتوانید مشاهده کنید.
اگر علاقمند بودید میتونید در این پروژه شرکت کنید و یک موضوع جدید و مستقل را برای تهیه زیرنویس شروع کنید. یا حداقل اگر پس از مشاهده این سری آماده شده، اصلاحی را انجام دادید، میتونید اون رو برای اعمال در اینجا ارسال کنید.
یکی از API های کاربردی و جدید در دنیای وب، BroadcastChannel است که امکان ارسال اطلاعات بین windowها ، Tabها و iframeهای مختلف را که در یک دامنه هستند، فراهم میکند. برای
مثال اگر شما در مرورگری در پنجرههای مختلف یک سایت را باز کرده باشید،
با تغییر در یکی از این پنجرهها، قادر خواهید بود سایر پنجرها را هم مطلع کنید تا در
صورت نیاز، مجددا بارگذاری شوند.
چرا از این API استفاده کنیم؟
یکی از
وب سایتهای مورد علاقهی خود را در مرورگر باز کنید. مثلا یوتیوب و لاگین کنید. حالا در
پنجرهی جدیدی، همین وب سایت را مجددا باز کرده و لاگین کنید. حالا در یکی از پنجرهها، از یوتیوب Logout کنید. خب شما حالا در یکی از پنجرهها لاگین هستید و در یکی دیگر Logout کردهاید. حالا
پنجرههای مرورگر شما دارای دو وضعیت متفاوت هستند. Logged-in در برابر Logged-out و این گاهی باعث دردسر خواهد شد.
این وضعیت حتی میتواند باعث خطرهای امنیتی نیز بشود. تصور کنید که کاربری در یک فضای عمومی مثل یک کافی شاپ وارد سایت شما شدهاست و داشبرد مخصوص به خود را باز کردهاست. بنا به دلایلی کاربر قصد ترک محل را کرده و طبیعتا از برنامه شما Logout خواهد کرد . در این حالت اگر این کاربر برنامه شما را در صفحات مختلف مرورگر باز کرده باشد و لاگین نیز کرده باشد، هر کسی که بعد از او قصد استفاده از این کامپیوتر را داشته باشد ، میتواند به اطلاعات کاربر مورد نظر در آن صفحات دسترسی پیدا کند؛ چه این اطلاعات روی صفحه باشد و چه مثلا اطلاعات یک JWT token. چون کاربر فراموش کرده در صفحات دیگر هم Logout کند.
کد نویسی BroadcastChannel API
در نگاه اول، استفاده از این API ممکن است سخت به نظر برسد؛ ولی در واقع خیلی راحت است. برای نمونه قطعه کد زیر را درنظر بگیرید:
<!DOCTYPE html> <body> <!-- The title will change to greet the user --> <h1 id="title">Hey</h1> <input id="name-field" placeholder="Enter Your Name"/> </body> <script> var bc = new BroadcastChannel('gator_channel'); (()=>{ const title = document.getElementById('title'); const nameField = document.getElementById('name-field'); const setTitle = (userName) => { title.innerHTML = 'Hey ' + userName; } bc.onmessage = (messageEvent) => { // If our broadcast message is 'update_title' then get the new title from localStorage if (messageEvent.data === 'update_title') { // localStorage is domain specific so when it changes in one window it changes in the other setTitle(localStorage.getItem('title')); } } // When the page loads check if the title is in our localStorage if (localStorage.getItem('title')) { setTitle(localStorage.getItem('title')); } else { setTitle('please tell us your name'); } nameField.onchange = (e) => { const inputValue = e.target.value; // In the localStorage we set title to the user's input localStorage.setItem('title', inputValue); // Update the title on the current page setTitle(inputValue); // Tell the other pages to update the title bc.postMessage('update_title'); } })() </script>
این کد شامل یک Input باکس و یک title است. وقتی کاربر نام خود را در Input باکس وارد میکند، برنامه آن را در Localstorage با کلیدی به نام userName ذخیره میکند و بعد title صفحه جاری را به سلام + userName تغییر میدهد. مثلا اگر کاربر در Input باکس، عبارت بابک را وارد کند، title صفحه به سلام بابک تغییر داده میشود.
بدون BroadcastChannel، چنانچه کاربر در پنجرههای مختلف مرورگر، برنامه را باز کرده باشد، تغییری در Title آن صفحات داده نخواهد شد؛ مگر اینکه مجددا توسط کاربر بارگذاری شود.
در کد فوق ما یک وهله از BroadcastChannel را به نام gator_channel ایجاد کردهایم و بعد onmessage را مساوی متدی با یک آرگومان جهت دریافت پیام قرار دادهایم. در این متد چک شده که اگر نام پیام، مساوی update_title باشد، متغیر ذخیره شدهی در LocalStorage خوانده شود.
هربار که متد postMessage ، از BroadcastChannel را فراخوانی میکنیم، این متد، باعث اجرای متد onmessage در سایر پنجرهها میشود. پس اگر در پنجرهی جاری در Input باکس، کلمه فرهاد را بنویسیم، متد bc.postMessage('update_title') در پنجره جاری اجرا شده و باعث اجرای متد onmessage در سایر پنجرههایی که سایتمان در آن باز است میشود.
این API در چه حالتهایی کار میکند
برخلاف سایر APIها مثل window.postMessage، شما لازم نیست چیزی در مورد اینکه چند تا صفحه از سایتتان بر روی مرورگر جاری باز شده را بدانید. (توجه کنید که روی عبارت «مرورگر جاری» تاکید میکنم. چون اگر برنامه روی دو مرورگر مثلا Chrome و Firefox به صورت همزمان باز باشد، این API فقط روی صفحات باز مرورگر جاری فراخوانی خواهد شد و نه مرورگر دوم؛ توضیحات بیشتر در ادامه داده شده است)
BroadcastChannel فقط روی مرورگر جاری و صفحاتی از یک دامنه، اجرا خواهد شد. این به این معنا است که شما میتوانید پیامهایتان را از دامنه مثلا : https://alligator.io به دامنه https://alligator.io/js/broadcast_channels ارسال کنید. تنها نکتهای که لازم است تا رعایت شود این است که آبجکت BroadcastChannel در هر دو صفحه، از یک نام برای channel استفاده کرده باشند:
const bc = new BroadcastChannel('alligator_channel'); bc.onmessage = (eventMessage) => { // do something different on each page }
در حالتهای زیر این API کار نخواهد کرد:
هاستهای متفاوت:
https://alligator.io
https://www.aligator.io
پورتهای متفاوت:
https://alligator.io
https://alligator.io :8080
پروتکلهای متفاوت:
https://alligator.io
http://alligator.io
و یا برای مثال اگر مثلا در مرورگر Chrome یکی از صفحات به صورت Incognito باز شده باشد.
سازگاری این API با مرورگرهای مختلف
با توجه به اطلاعات سایت caniuse.com، این API در 75.6% مرورگرها پشتیبانی میشود. ولی مرورگرهای Safari و Internet Explorer از این API پشتیبانی نمیکنند. همچنین امکان استفاده از این API توسط کتابخانه sysend.js نیز فراهم شدهاست.
چه نوع پیامهایی را میتوانید به کمک این API ارسال کنید
- تمامی تایپها (Boolean,Null, Undefined,Number,BigInt, String) به غیر از symbol
- آبجکتهای Boolean و String
- Dates
- Regular Expressions
- Blobs
- Files, File Lists
- Array Buffer, ArrayBufferViews
- ImageBitmaps, ImageDates
- Arrays,Objects,Maps and Sets
قطعه کد زیر، بجای string، یک object را ارسال میکند:
bc.onmessage = (messageEvent) => { const data = messageEvent.data // If our broadcast message is 'update_title' then get the new title from localStorage switch (data.type) { case 'update_title': if (data.title){ setTitle(data.title); } else setTitle(localStorage.getItem('title')); break default: console.log('we received a message') } }; // ... Skipping Code bc.postMessage({type: 'update_title', title: inputValue});
چه کارهایی را میتوانید به کمک این API انجام دهید
چیزهای زیادی را میتوان مجسم کرد. محتملترین گزینه، به اشتراک گذاری state جاری برنامه است. برای مثال اگه از کتابخانههای flux یا redux برای مدیریت state برنامه استفاده میکنید، به کمک این API میتوانید state جاری را در تمامی صفحات باز برنامه، بروز رسانی کنید. حتی میتوانید به چیزی شبیه به machine state فکر کنید.
یا مثلا آخرین وضعیت سبد خرید کالای مشتری و یا موجودی کالاها، در یک سایت خرید آنلاین. همچنین به اشتراک گذاری فایلهای حجیم مثل عکس و غیره جهت جلوگیری از دانلود مجدد آنها در سایر صفحات.
به کمک دستور ()bc.close در هر زمانی میتوانید channel باز شده را ببندید و مجددا بسته به وضعیت برنامه، آن را باز کنید.
زیرنویسهای فارسی قسمت پنجم «Building Windows 8 Metro Apps in C# and XAML» را از اینجا و یا اینجا میتونید دریافت کنید.
لیست سرفصلهای قسمت پنجم به شرح زیر است:
Application Model 00:59:50
Metro and WinRT introduce some significant changes to the world in which applications execute.
This module describes the implications for developers.
Introduction
Application Lifecycle
Demo: Application Lifecycle
Managing State
Demo: Saving State
Splash Screens
Launching Applications
Application Manifest
Packaging
Summary
این قسمت به جزئیات نحوه اجرای برنامههای مترو میپردازد. اگر با IIS کار کرده باشید، سیکل اجرایی برنامههای مترو ویندوز 8، همانند سیکل اجرایی برنامههای ASP.NET شده است! ویندوز مختار است برنامه شما را پس از مدتی بیکاری (البته این مدت در اینجا فقط 5 ثانیه است!)، معلق کرده یا حتی خاتمه دهد و تمام اینها هم از دید کاربر نهایی مخفی است. مانند زمانیکه یک برنامه ASP.NET پس از مدتی بیکاری، توسط IIS خاتمه مییابد (از حافظه خارج میشود) و پس از مدتی با رسیدن یک درخواست جدید، یک پروسه جدید برای اجرای آن ایجاد شده و مجددا سایت شروع به کار خواهد کرد؛ اینجا هم در دنیای مترو تقریبا به همین نحو با یک برنامه رفتار میشود.
یک نکته جالب دیگر هم در برنامههای مترو وجود دارد: ترد اصلی برنامه از ترد رابط کاربری جدا شده است. برای مثال سازنده کلاس App برنامه در یک ترد و رابط کاربری برنامه در ترد مجزای دیگری اجرا میشوند.
به علاوه روشهای متفاوتی هم برای اجرای برنامههای مترو درنظر گرفته شده. دیگر فقط حالت کلیک بر روی یک برنامه سبب اجرای آن نمیشود. میتوان بر اساس اتصال یک سخت افزار خاص به سیستم یا حتی یک جستجو هم سبب اجرای برنامهای شد. برای مثال میتوانید برنامه خود را طوری طراحی کنید که نتیجهی جستجویی را در سیستم نمایش دهد.
سیستم بسته بندی برنامههای مترو نیز بسیار شبیه به فایلهای XAP برنامههای سیلورلایت است که همه چیز داخل یک فایل قرار داده میشود؛ از فایلهای تنظیمات برنامه تا فایلهای کامپایل شده و منابع مورد نیاز. البته در اینجا نامش به appx تغییر یافته است به علاوه یک فایل cer که حاوی مجوز دیجیتال اجباری توزیع برنامههای مترو در فروشگاه ویندوز است.
آموزش سیلورلایت 4 - قسمتهای 21 تا 27
http://www.multiupload.com/
فایل را منتقل کنید. چندین mirror از آن حاصل خواهد شد.
جدول تفاوت مجوزهای سورس باز با یکدیگر
ذخیره کردن رشته اتصالی به دیتابیس، به صورت یک رشته مشخص در کدهای برنامه، کاری است مزموم. زیرا پس از هر بار تغییر این مورد، نیاز خواهد بود تا تمامی سورسها تغییر کنند و اگر از حالت web application استفاده کرده باشید، مجبور خواهید شد یکبار دیگر برنامه را کامپایل و دایرکتوری bin روی سرور را به روز کنید. به همین جهت، استاندارد برنامههای ASP.Net این است که این رشته اتصالی را در فایل web.config ذخیره کنیم تا با هر بار تغییر پارامترهای مختلف آن (مثلا تغییر نام سرور، یا تعویض ماهیانه پسوردها)، مجبور به کامپایل مجدد برنامه نشویم. شبیه به همین مورد در برنامههای PHP هم رایج است و عموما این مشخصات در فایل config.php و یا با اسامی شبیه به این صورت میگیرد.
در ASP.Net 1.x قسمت خاصی برای کانکشن استرینگ وجود نداشت اما از ASP.Net 2 به بعد ، قسمت ویژهای مخصوص این کار در فایل web.config در نظر گرفته شده است.
خیلی هم خوب! اما این تجربه تلخ کاری را (که یکبار برای من رخ داد) هم همواره در نظر داشته باشید:
امکان خوانده شدن محتوای فایل کانفیگ، توسط همسایه شما در همان هاست اشتراکی که الان از آن دارید استفاده میکنید. عموما هاستهای اینترنتی اشتراکی هستند و نه dedicated و نه فقط مختص به شما. از یک سرور برای سرویس دهی به 100 ها سایت استفاده میشود. یکبار در یکی از سایتها دیدم که فایل machine.config سرور را هم محض نمونه خوانده بودند چه برسد به فایل متنی کانفیگ شما! یا تصور کنید که وب سرور هک شود. عموما اس کیوال سرور بر روی سرور دیگری قرار دارد. به همین جهت رمزنگاری این رشته باز هم ضریب امنیت بیشتری را به همراه خواهد داشت.
به همین منظور رمزنگاری قسمت کانکشن استرینگ فایل وب کانفیگ الزامی است، چون آنهایی که به دنبال اطلاعاتی اینگونه هستند دقیقا میدانند باید به کجا مراجعه کنند.
راه حلها:
الف) از وب کانفیگ برای اینکار استفاده نکنید. یک فایل class library درست کنید (یک dll مجزا) و ارجاعی از این فایل را به پروژه خود اضافه کنید و از رشته اتصالی قرار گرفته در آن استفاده کنید. این فایل را هم میتوان با روشهای obfuscation محافظت کرد تا امنیت اطلاعات داخل آنرا تا حد قابل قبولی بالا برد. همچنین میتوان برای این فایل کتابخانه، امضای دیجیتال درنظر گرفت. زیرا امضای دیجیتال سبب میشود تا تغییر فایل dll رشته اتصالی، با یک کپی و paste معمولی قابل انجام نباشد (تمامی dll ها و اسمبلیهای دیگری که ارجاعی از آنرا در خود دارند باید یکبار دیگر هم کامپایل و به سرور منتقل شوند). این یک نوع اطمینان خاطر است اما در بلند مدت شاید تکرار اینکار خسته کننده باشد.
ب)استفاده از روش استاندارد رمزنگاری قسمتهای مختلف کانکشن استرینگ فایل web.config
برای مشاهده نحوه انجام اینکار با برنامه نویسی به این مقاله مراجعه نمائید.
مزیت: نیازی به کد نویسی برای رمزگشایی و استفاده از آن نیست و اینکار به صورت خودکار توسط ASP.Net انجام میشود.
ایراد:فایل حاصل قابل انتقال نیست. چون رمزنگاری بر اساس کلیدهای منحصربفرد سرور شما ایجاد میشوند، این فایل از یک سرور به سرور دیگر قابل انتقال و استفاده نخواهد بود. یعنی اگر بر روی کامپیوتر برنامه نویسی شما اینکار صورت گرفت، برنامه در سرور کار نخواهد کرد. البته شاید ایراد آنچنانی نباشد و فقط باید یکبار دیگر روی هاست نیز این کار را تکرار کرد. اما باید درنظر داشت که همسایه محترم شما نیز میتواند بر روی همان هاست به سادگی فایل شما را رمزگشایی کند! بنابراین نباید اصلا به این روش در هاستهای اشتراکی دل خوش کرد.
ج)بکارگیری روشهای غیراستاندارد رمزنگاری
منظور از غیراستاندارد، حالتهای دیگر استاندارد رمزنگاری و رمزگشایی نسبت به روش استاندارد ارائه شده توسط مایکروسافت است (که همه از آن مطلع هستند). به شخصه از این روش در هاستها استفاده میکنم. (مثلا، البته با کمی تغییر و پیچ و تاب بیشتر)
الگوریتمهای رمزنگاری و رمزگشایی در یک فایل dll به برنامه اضافه میشوند (بنابراین این فایل قرار نیست تغییر کند). رشته رمزنگاری شده در فایل web.config قرار میگیرد. بدیهی است در هر بار اتصال به دیتابیس این رشته باید رمزگشایی شود اما سربار آن بسیار کم است و اصلا مشهود نیست. در هر حال این هزینهای است که باید پرداخت شود. بدست آوردن ساده کانکشن استرینگ یعنی امکان پاک کردن سریع کل اطلاعات شما.
د)اگر سرور dedicated است حتما از روش windows authentication استفاده کنید
برای مثال یک سرور dedicated مخصوص کار ویژهای تهیه کرده اید یا در شبکه اینترانت یک شرکت برنامه شما نصب شده است.
روش اعتبار سنجی از نوع ویندوزی برای اتصال به اس کیوال سرور نسبت به حالت sql server authentication امن تر است، زیرا نیازی نیست تا در وب کانفیگ نام کاربری یا پسوردی را مشخص نمائید و همچنین در این حالت پسوردها در شبکه منتقل نمیشوند (در حالت sql server authentication اینطور نیست). اما عموما در هاستهای اشتراکی برای ساده تر کردن کار ، از این روش استفاده نمیکنند.
بنابراین در اینجا حتی اگر شخصی به رشته اتصالی شما دسترسی پیدا کند، کار خاصی را نمیتواند انجام دهد چون هیچگونه نام کاربری یا پسوردی در آن لحاظ نشده است.
در این روش به صورت پیش فرض از اکانت ASP.Net استفاده میشود. یعنی تمام برنامهها محدود به یک اکانت خواهند شد.
برای تغییر این مورد دو کار را میتوان انجام داد : استفاده از impersonation یا مطالعه قسمت بعد (ه)
توصیه: از روش impersonation به دلیل اینکه باید نام کاربری و کلمه عبور را باز هم به صورت واضحی ذکر نمود اجتناب کنید.
ه)ایجاد application pool مجزا به ازای هر برنامه ASP.Net در ویندوزهای سرور
Application pool که برای اولین بار در ویندوز سرور 2003 معرفی شده جهت ایزوله کردن برنامههای ASP.Net بکار برده میشود. به این صورت میشود برای هر pool یک اکانت ویندوزی مجزا تعریف کرد. حال میتوان به این اکانت در اس کیوال سرور دسترسی داد. به این صورت برنامههای مختلف تحت یک اکانت واحد (یوزر asp.net) کار نکرده (میتوانند هم کار کنند، اما امکان تعریف identity جدید برای کاربر آن در IIS وجود دارد) و ضریب امنیتی بالاتری را تجربه خواهید کرد (در تکمیل روش (د))
کار با DropzoneJS در ASP.net MVC
در قسمت اول بررسی نحوه برنامه نویسی افزونه outlook ، در مورد استفاده از regular expressions اندکی توضیح داده شد. امروز مثالی دیگر از همین دست را بررسی خواهیم کرد.
چند روز قبل یک ایمیل تبلیغاتی به دست من رسید که فرد ارسال کننده انبوهی از ایمیلها را در قسمت To قرار داده بود (بجای قسمت BCC (رونوشت مخفی)).
خوب، برای جدا کردن انبوهی از ایمیلهای مخلوط با سایر متون چه باید کرد؟ چند ساعت وقت گذاشت و تک تک آنها را به صورت دستی جدا کرد؟ (برای ذخیره سازی در یک دیتابیس برای مثال :) )
یا برای مثال برنامههای download manager توانایی استخراج لینکهای موجود در یک متن کپی شده در حافظه را دارند. آنها به چه صورتی عمل میکنند؟ چگونه میتوانند لینکها را با دقتی بالا و بسیار سریع از لابلای متن موجود تشخیص دهند؟
بهینهترین و سریعترین راه برای این نوع جستجوها استفاده از کتابخانه regular expressions (عبارات با قاعده) در دات نت فریم ورک است. اگر نیاز به یک برگه تقلب (!) در این زمینه داشتید میتوانید به اینجا مراجعه کنید. همچنین در همان سایت، کاربران بسیاری را خواهید یافت که الگوهای ابداعی خود را با دیگران به اشتراگ میگذارند.
برای مثال فرض کنید فایلی را که حاوی مخلوطی از متن و ایمیل است را در یک رشته بارگذاری کردهاید. نحوه استخراج ایمیلهای موجود با استفاده از این امکانات به صورت زیر خواهد بود:
using System.IO;
using System.Text.RegularExpressions;
using System.Text;
class CRegEx
{
/// <summary>
/// استخراج ایمیلهای یک فایل متنی و ذخیره آن در فایلی جدید
/// </summary>
/// <param name="inFilePath">فایل ورودی</param>
/// <param name="outFilePath">فایل خروجی</param>
public static void ExtractEmails(string inFilePath, string outFilePath)
{
string data = File.ReadAllText(inFilePath); //خواندن فایل متنی
//ایجاد شیء عبارت با قاعده بر اساس الگوی تشخیص ایمیلها
Regex emailRegex = new Regex(@"\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*",
RegexOptions.IgnoreCase);
//پیدا کردن گروه تطابق یافته با الگوی ما
MatchCollection emailMatches = emailRegex.Matches(data);
//ایجاد شیء استرینگ بیلدر برای ذخیره سازی سریع اطلاعات دریافتی
StringBuilder sb = new StringBuilder();
//ذخیره ایمیلهای استخراج شده
foreach (Match emailMatch in emailMatches)
{
sb.AppendLine(emailMatch.Value);
}
//ذخیره کردن اطلاعات استخراج شده در فایلی جدید
File.WriteAllText(outFilePath, sb.ToString());
}
}
چند نکته را باید در اینجا در نظر داشت. حتما آدرسهای اضافه شده را با استفاده از عبارات باقاعده یکبار پیش از اضافه شدن بررسی نمائید (Regex.IsMatch). در صورتیکه یکی از ایمیلها فرمت غیراستانداردی داشته باشد کل کار برگشت خواهد خورد.
و همچنین باید دقت داشت که برای این موضوع حد نصاب وجود دارد. بر روی یکی از میل سرورهای یک هاست ایرانی تست کردم، حداکثر 100 رونوشت مخفی را بیشتر قبول نمیکرد. بنابراین هر بار میشود 100 ایمیل را به صورت یکجا ارسال کرد (که باز هم از روش استفاده از حلقهای که 100 بار ایمیل میزند بسیار بهتر است و هاست دار به علت ایجاد بار اضافی شدید بر روی سرور با شما تماس نخواهد گرفت)