مطالب
اهمیت ارائه‌ی برنامه‌های دات نت به صورت release

یکی از مواردی که بعضی از همکاران هنگام ارائه برنامه‌های خود رعایت نمی‌کنند، تفاوت قائل نشدن بین حالت release و debug در زمان کامپایل پروژه، برای ارائه نهایی است.
هنگام استفاده از حالت release ، گزینه‌های بهینه سازی کامپایلر فعال شده و همچنین debug symbols از اسمبلی نهایی تولید شده حذف می‌گردد (بنابراین حجم اسمبلی نهایی نیز کمتر خواهد شد). لازم به ذکر است در حالت release ، میزان مصرف حافظه برنامه تولید شده نیز کمتر از حالت debug خواهد بود. گاهی از اوقات سرعت اجرای این دو حالت تا چندین برابر در بعضی از الگوریتم‌ها می‌توانند متفاوت باشند.
مطابق مستندات موجود، وجود debug symbols هیچگونه تاثیری بر روی کارآیی یک برنامه دات نت ندارند.
لازم به ذکر است که عمده بهینه‌سازی‌ها در دات نت توسط JIT compiler صورت می‌گیرد (تا 99 درصد) و نه توسط کامپایلر زبان مورد استفاده (به همین جهت است که عده‌ای اعتقاد دارند در نهایت و هنگام اجرا تفاوتی مابین زبان‌های مختلف دات نت وجود نخواهد داشت). بر روی JIT compiler نیز می‌توان تاثیر گذاشت و نحوه عملکرد آنرا تغییر داد (حتی بر روی یک اسمبلی کامپایل شده). برای مثال یک فایل ini کنار اسمبلی پروژه خود ایجاد کنید (xyz.ini که در اینجا xyz.exe نام فایل اجرایی برنامه است). محتویات این فایل می‌تواند به صورت زیر باشد:

[.NET Framework Debugging Control]
GenerateTrackingInfo=1
AllowOptimize=0

در اینجا می‌توان بهینه سازی را فعال و غیر فعال کرد و یا مطابق تنظیمات فوق برنامه را جهت دیباگ آماده نمود. (این روش با اسمبلی‌های ASP.Net کار نمی‌کند)
در دات نت فریم ورک 2 ، TrackingInfo مربوط به JIT compiler همواره تولید خواهد شد اما می‌توان بر روی بهینه سازی نهایی به صورت فوق نیز تاثیرگذار بود.

نکته:
اگر می‌خواهید هنگام مشاهده گزارش خطا، شماره سطر مورد نظر نیز در کدهای شما گوشزد ‌شود فایلهای pdb - program database تولید شده را هم ارائه دهید. حال شاید بخواهید هم برنامه را در حالت release ارائه دهید و هم pdb آن تولید شود، در این حالت باید خط فرمان کامپایل برنامه، با سوئیچ debug:pdbonly/ اجرا شود.
این مورد را در قسمت خواص پروژه، گزینه build و با کلیک بر روی دکمه advanced نیز می‌توان تنظیم نمود. (حالت پیش فرض release در VS.Net است)

خلاصه‌ی کلام: لطفا هنگام ارائه نهایی، گزینه release را از بالای صفحه در VS.Net انتخاب کنید. با تشکر!

مطالب
فعال سازی Multicore JIT
Multicore JIT یکی از قابلیت‌های کلیدی در دات نت 4.5 می‌باشد که در واقع راه حلی برای بهبود سرعت اجرای برنامه‌های دات نتی است. قبل از معرفی این قابلیت ابتدا اجازه دهید نحوه کامپایل یک برنامه دات نتی را بررسی کنیم.
انواع compilation
در حالت کلی دو نوع فرآیند کامپایل داریم:
  • Explicit
در این حالت دستورات قبل از اجرای برنامه به زبان ماشین تبدیل می‌شوند. به این نوع کامپایلرها AOT یا Ahead Of Time گفته می‌شود. این نوع از کامپایلرها برای اطمینان از اینکه CPU بتواند قبل از انجام تعاملی تمام خطوط کد را تشخیص دهد، طراحی شده اند.
  • Implicit
این نوع compilation به صورت دو مرحله ایی صورت می‌گیرد. در اولین قدم سورس کد توسط یک کامپایلر به یک زبان سطح میانی(IL) تبدیل می‌شود. در مرحله بعدی کد IL به دستورات زبان ماشین تبدیل می‌شوند. در دات نت فریم ورک به این کامپایلر JIT یا Just-In-Time گفته می‌شود.
در حالت دوم قابلیت جابجایی برنامه به آسانی امکان پذیر است، زیرا اولین قدم از فرآیند به اصطلاح platform agnostic می‌باشد، یعنی قابلیت اجرا بر روی گستره وسیعی از پلت فرم‌ها را دارد.

کامپایلر JIT
JIT بخشی از Common Language Runtime یا CLR می‌باشد. CLR در واقع وظیفه مدیریت اجرای تمام برنامه‌های دات نتی را برعهده دارد.

همانطور که در تصویر فوق مشاهده می‌کنید، سورس کد توسط کامپایلر دات نت به exe و یا dll کامپایل می‌شود. کامپایلر JIT تنها متدهایی را که در زمان اجرا(runtime) فراخوانی می‌شوند را کامپایل می‌کند. در دات نت فریم ورک سه نوع JIT Compilation داریم:

Normal JIT Compilation   

در این نوع کامپایل، متدها در زمان فراخوانی در زمان اجرا کامپایل می‌شوند. بعد از اجرا، متد داخل حافظه ذخیره می‌شود. به متدهای ذخیره شده در حافظه jitted گفته می‌شود. دیگر نیازی به کامپایل متد jit شده نیست. در فراخوانی بعدی، متد مستقیماً از حافظه کش در دسترس خواهد بود.

Econo JIT Compilation 

این نوع کامپایل شبیه به حالت Normal JIT است با این تفاوت که متدها بلافاصله بعد از اجرا از حافظه حذف می‌شوند.

Pre-JIT Compilation 

یکی دیگر از حالت‌های کامپایل برنامه‌های دات نتی Pre-JIT Compilation می باشد. در این حالت به جای متدهای مورد استفاده، کل اسمبلی کامپایل می‌شود. در دات نت می‌توان اینکار را توسط Ngen.exe یا (Native Image Generator) انجام داد. تمام دستورالعمل‌های CIL قبل از اجرا به کد محلی(Native Code) کامپایل می‌شوند. در این حالت runtime می‌تواند از native images به جای کامپایلر JIT استفاده کند. این نوع کامپایل عملیات تولید کد را در زمان اجرای برنامه به زمان Installation منتقل می‌کند، در اینصورت برنامه نیاز به یک Installer برای اینکار دارد.

Multicore JIT

در دات نت فریم ورک 4.5 یک راه حل جایگزین دیگر برای بهینه سازی و بهبود سرعت اجرای برنامه‌های دات نت وجود دارد. همانطور که عنوان شد Ngen.exe برای در دسترس بودن نیاز به Installer برای برنامه دارد. توسط Multicore JIT متدها بر روی دو هسته به صورت موازی کامپایل می‌شوند، در اینصورت می‌توانید تا 50 درصد از JIT Time صرفه جویی کنید.

Multicore JIT همچنین می‌تواند باعث بهبود سرعت در برنامه‌های WPF شود. در نمودار زیر می‌توانید حالت‌های استفاده و عدم استفاده از Multicore JIT را در سه برنامه WPF نوشته شده مشاهده کنید.

Multicore JIT در عمل

Multicore JIT از دو مد عملیاتی استفاده می‌کند: مد ثبت(Recording mode)، مد بازپخش(Playback mode)

در حالت ثبت کامپایلر JIT هر متدی که نیاز به کامپایل داشته باشد را رکورد می‌کند. بعد از اینکه CLR تعیین کند که اجرای برنامه به اتمام رسیده است، تمام متدهایی که اجرا شده اند را به صورت یک پروفایل بر روی دیسک ذخیره می‌کند.

هنگامیکه Multicore JIT فعال می‌شود، با اولین اجرای برنامه، حالت ثبت مورد استفاده قرار می‌گیرد. در اجراهای بعدی، از حالت بازپخش استفاده می‌شود. حالت بازپخش پروفایل را از طریق دیسک بارگیری کرده، و قبل از اینکه این اطلاعات توسط ترد اصلی مورد استفاده قرار گیرد، از آنها برای تفسیر (کامپایل) متدها در پیش‌زمینه استفاده می‌کند. 

در نتیجه، ترد اصلی به کامپایل دیگری نیاز ندارد، در این حالت سرعت اجرای برنامه بیشتر می‌شود. حالت‌های ثبت و بازپخش تنها برای کامپیوترهایی با چندین هسته فعال می‌باشند.

استفاده از Multicore JIT

در برنامه‌های 4.5 ASP.NET و 5 Silverlight به صورت پیش فرض این ویژگی فعال می‌باشد. ازآنجائیکه این برنامه‌ها hosted application هستند؛ در نتیجه فضای مناسبی برای ذخیره سازی پروفایل در این نوع برنامه‌ها موجود می‌باشد. اما برای برنامه‌های Desktop این ویژگی باید فعال شود. برای اینکار کافی است دو خط زیر را به نقطه شروع برنامه تان اضافه کنید:

public App() 
{
    ProfileOptimization.SetProfileRoot(@"C:\MyAppFolder");
    ProfileOptimization.StartProfile("Startup.Profile");
}

توسط متد SetProfileRoot می‌توانیم مسیر ذخیره سازی پروفایل JIT را مشخص کنیم. در خط بعدی نیز توسط متد StartProfile نام پروفایل را برای فعال سازی Multicore JIT تعیین می‌کنیم. در این حالت در اولین اجرای برنامه پروفایلی وجود ندارد، Multicore JIT در حالت ثبت عمل می‌کند و پروفایل را در مسیر تعیین شده ایجاد می‌کند. در دومین بار اجرای برنامه CRL پروفایل را از اجرای قبلی برنامه بارگذاری می‌کند؛ در این حالت Multicore JIT به صورت بازپخش عمل می‌کند.

همانطور که عنوان شد در برنامه‌های ASP.NET 4.5 و Silverlight 5 قابلیت Multicore JIT به صورت پیش فرض فعال می‌باشد. برای غیر فعال سازی آن می‌توانید با تغییر فلگ profileGuidedOptimizations به None اینکار را انجام دهید:

<?xml version="1.0" encoding="utf-8" ?> 
<configuration>
 <!-- ... -->
 <system.web> 
 <compilation profileGuidedOptimizations="None" /> 
 <!-- ... --> 
 </system.web> 
</configuration>
مطالب
آشنایی با CLR: قسمت ششم
در مقاله قبلی مبحث کامپایلر JIT را آغاز کردیم. در این قسمت قصد داریم مبحث کارآیی CLR و مباحث دیباگینگ را پیش بکشیم.
از آنجا که یک کد مدیریت نشده، مبحث کارهای JIT را ندارد، ولی CLR مجبور است وقتی را برای آن بگذارد، به نظر می‌رسد ما با یک نقص کوچک در کارآیی روبرو هستیم. گفتیم که جیت کدها را در حافظه‌ی پویا ذخیره می‌کند. به همین خاطر با terminate شدن یا خاتمه دادن به برنامه، این کدها از بین می‌روند یا اینکه اگر دو نمونه از برنامه را اجرا کنیم، هر کدام جداگانه کد را تولید می‌کنند و هر کدام برای خودشان حافظه‌ای بر خواهند داشت و اگر مقایسه‌ای با کدهای مدیریت نشده داشته باشید، در مورد مصرف حافظه یک مشکل ایجاد می‌کند. همچنین JIT در حین تبدیل به کدهای بومی یک بهینه سازی روی کد هم انجام میدهد که این بهینه سازی وقتی را به خود اختصاص می‌دهد ولی همین بهینه سازی کد موجب کارآیی بهتر برنامه می‌گردد.
در زبان سی شارپ دو سوئیچ وجود دارند که بر بهینه سازی کد تاثیر گذار هستند؛ سوئیچ‌های debug و optimize. در جدول زیر تاثیر هر یک از سوئیچ‌ها را بر کیفیت کد IL و JIT در تبدیل به کد بومی را نشان میدهد.

موقعیکه از دستور -optimize استفاده می‌شود، کد IL تولید شده شامل تعداد زیادی از دستورات بدون دستورالعمل No Operation یا به اختصار NOP و پرش‌های شاخه‌ای به خط کد بعدی می‌باشد. این دستور العمل‌ها ما را قادر میسازند تا ویژگی edit & Continue را برای دیباگ کردن و یک سری دستورالعمل‌ها را برای کدنویسی راحت‌تر برای دیباگ کردن و ایجاد break point‌ها داشته باشیم.

موقعی که کد IL بهینه شده تولید شود، این خصوصیات اضافه حذف خواهند شد و دنبال کردن خط به خط کد، کار سختی می‌شود. ولی در عوض فایل نهایی exe یا dll، کوچکتر خواهد شد. بهینه سازی IL توسط JIT حذف خواهد شد و برای کسانی که دوست دارند کدهای IL را تحلیل و آنالیز کنند، خواندنش ساده‌تر و آسان‌تر خواهد بود.

نکته‌ی بعدی اینکه موقعیکه شما از سوئیچ (/debug(+/full/pdbonly استفاده می‌کنید، یک فایل PDB  یا Program Database ایجاد می‌شود. این فایل به دیباگرها کمک می‌کند تا متغیرهای محلی را شناسایی و به کدهای IL متصل شوند. کلمه‌ی full بدین معنی است که JIT می‌تواند دستورات بومی را ردیابی کند تا مبداء آن کد را پیدا کند. سبب می‌شود که ویژوال استودیو به یک دیباگر متصل شده تا در حین اجرای پروسه، آن را دیباگ کند. در صورتی که این سوئیچ را استفاده نکنید، به طور پیش فرض پروسه اجرا و مصرف حافظه کمتر می‌شود. اگر شما پروسه‌ای را اجرا کنید که دیباگر به آن متصل شود، به طور اجباری JIT مجبور به انجام عملیات ردیابی خواهد شد؛ مگر اینکه گزینه‌ی suppress jit  optimization on module load را غیرفعال کرده باشید.
موقعیکه در ویژوال استودیو دو حالت دیباگ و ریلیز را انتخاب می‌کنید، در واقع تنظیمات زیر را اجرا می‌کنید:

//debug

/optimize­ 
/debug:full

//=======================

//Release

/optimize+
/debug:pdbonly
احتمالا موارد بالا به شما می‌گویند که یک سیستم مبتنی بر CLR مشکلات زیادی دارد که یکی از آن‌ها، زمان‌بر بودن انجام عملیات فرآیند پردازش است و دیگری مصرف زیاد حافظه و عدم اشترک حافظه که در مورد کامپایل جیت به آن اشاره کردیم. ولی در بند بعدی قصد داریم نظرتان را عوض کنم.

اگر خیلی شک دارید که واقعا یک برنامه‌ی CLR کارآیی یک برنامه را پایین می‌آورد، بهتر هست به بررسی کارآیی چند برنامه غیر آزمایشی noTrial که حتی خود مایکروسافت آن برنامه‌ها را ایجاد کرده است بپردازید و آن‌ها را با یک برنامه‌ی unmanaged مقایسه کنید. قطعا باعث تعجب شما خواهد شد. این نکته دلایل زیادی دارد که در زیر تعدادی از آن‌ها را بررسی می‌کنیم.
اینکه CLR در محیط اجرا قصد کمپایل دارد، باعث آشنایی کامپایلر با محیط اجرا می‌گردد. از این رو تصمیماتی را که می‌گیرد، می‌تواند به کارآیی یک برنامه کمک کند. در صورتیکه یک برنامه‌ی unmanaged که قبلا کمپایل شده و با محیط‌های متفاوتی که روی آن‌ها اجرا میشود، هیچ آشنایی ندارد و نمیتواند از آن محیط‌ها حداکثر بهره‌وری لازم را به عمل آورد.
برای آشنایی با این ویژگی‌ها توجه شما را به نکات ذیل جلب می‌کنم:

یک.  JIT می‌تواند با نوع پردازنده آشنا شود که آیا این پردازنده از نسل پنتیوم 4 است یا نسل Core i. به همین علت می‌تواند از این مزیت استفاده کرده و دستورات اختصاصی آن‌ها را به کار گیرد، تا برنامه با performance بالاتری اجرا گردد. در صورتی که unmanaged باید حتما دستورات را در پایین‌ترین سطح ممکن و عمومی اجرا کند؛ در صورتیکه شاید یک دستور اختصاصی در یک سی پی یو خاص، در یک عملیات موجب 4 برابر، اجرای سریعتر شود.

دو.  JIT میتواند بررسی هایی را که برابر false هستند، تشخیص دهد. برای فهم بهتر، کد زیر را در نظر بگیرید:
if (numberOfCPUs > 1) {
...
}

کد بالا در صورتیکه پردازنده تک هسته‌ای باشد یک کد بلا استفاده است که جیت باید وقتی را برای کامپایل آن اختصاص دهد؛ در صورتیکه JIT باهوش‌تر از این حرفاست و در کدی که تولید می‌کند، این دستورات حذف خواهند شد و باعث کوچکتر شدن کد و اجرای سریعتر می‌گردد.

سه. مورد بعدی که هنوز پیاده سازی نشده، ولی احتمال اجرای آن در آینده است، این است که یک کد می‌تواند جهت تصحیح بعضی موارد چون مسائل مربوط به دیباگ کردن و مرتب سازی‌های مجدد، عمل کامپایل را مجددا برای یک کد اعمال نماید.
دلایل بالا تنها قسمت کوچکی است که به ما اثبات می‌کند که چرا CLR می‌تواند کارآیی بهتری را نسبت به زبان‌های unmanaged امروزی داشته باشد. همچنین قول‌هایی از سازندگان برای بهبود کیفیت هر چه بیشتر این سیستم‌ها به گوش می‌رسد.

کارآیی بالاتر
اگر برنامه‌ای توسط شما بررسی شد و دیدید که نتایج مورد نیاز در مورد performance را نشان نمی‌دهد، می‌توانید از ابزار کمکی که مایکروسافت در بسته‌های فریمورک دات نت قرار داده است استفاده کنید. نام این ابزار Ngen.exe است و وظیفه‌ی آن این است که وقتی برنامه بر روی یک سیستم برای اولین مرتبه اجرا می‌گردد، کد همه‌ی اسمبلی‌ها را تبدیل کرده و آن‌ها روی دیسک ذخیره می‌کند. بدین ترتیب در دفعات بعدی اجرا، JIT بررسی می‌کند که آیا کد کامپایل شده‌ی اسمبلی از قبل موجود است یا خیر. در صورت وجود، عملیات کامپایل به کد بومی لغو شده و از کد ذخیره شده استفاده خواهد کرد.
نکته‌ای که باید در حین استفاده از این ابزار به آن دقت کنید این است که کد در محیط‌های واقعی اجرا چندان بهینه نیست. بعدا در مورد این ابزار به تفصیل صحبت می‌کنیم.

system.runtime.profileoptimization
کلاس بالا سبب می‌شود که CLR در یک فایل ثبت کند که چه متدهایی در حین اجرای برنامه کمپایل شوند تا در آینده در حین آغاز اجرای برنامه کامپایلر JIT بتواند همزمان این متدها را در ترد دیگری کامپایل کند. اگر برنامه‌ی شما روی یک پردازنده‌ی چند هسته‌ای اجرا می‌شود، در نتیجه اجرای سریعتری خواهید داشت. به این دلیل که چندین متد به طور همزمان در حال کمپایل شدن هستند و همزمان با آماده سازی برنامه برای اجرا اتفاق می‌افتد؛ به جای اینکه عمل کمپایل همزمان با تعامل کاربر با برنامه باشد.

مطالب
کامپایل خودکار یک پروژه برای دو فریم ورک
فرض کنید می‌خواهید زمانیکه دکمه‌ی build در VS.NET فشرده شد، دو نسخه‌ی دات نت 4 و دات نت 4.5، از پروژه‌ی شما در پوشه‌های مجزایی کامپایل شده و قرار گیرند. در ادامه نحوه‌ی انجام این‌کار را بررسی خواهیم کرد.


پروژه نمونه
تنظیمات ذیل را بر روی یک پروژه از نوع class library دات نت 4 در VS 2013 اعمال خواهیم کرد.


ویرایش فایل پروژه برنامه

برای اینکه تنظیمات کامپایل خودکار مخصوص دات نت 4.5 را نیز به این پروژه دات نت 4 اضافه کنیم، نیاز است فایل csproj آن‌را مستقیما ویرایش نمائیم. این تغییرات شامل مراحل ذیل هستند:
الف) تعریف متغیر Framework
  <PropertyGroup>
    <!-- ...-->
    <Framework Condition=" '$(Framework)' == '' ">NET40</Framework>
  </PropertyGroup>
به ابتدای فایل csproj در قسمت PropertyGroup آن یک متغیر جدید را به نام Framework اضافه کنید. از این متغیر در شرط‌های کامپایل استفاده خواهد شد.


ب) ویرایش مسیر خروجی تنظیمات کامپایل فعلی
  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
    <!-- ...-->
    <OutputPath>bin\$(Configuration)\$(Framework)\</OutputPath>
  </PropertyGroup>
در حال حاضر حداقل تنظیمات کامپایل حالت debug، در فایل پروژه موجود است. مقدار OutputPath آن‌را به نحو فوق تغییر دهید تا خروجی نهایی را در پوشه‌ای مانند bin\Debug\NET40 ایجاد کند.
بدیهی است اگر حالت release هم وجود دارد، نیاز است مقدار OutputPath آن‌را نیز به همین ترتیب ویرایش کرد.


ج) افزودن تنظیمات کامپایل دات نت 4.5 به پروژه جاری
  <PropertyGroup Condition=" '$(Framework)' == 'NET45' And '$(Configuration)|$(Platform)' == 'Debug|AnyCPU'">
    <TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
    <PlatformTarget>AnyCPU</PlatformTarget>
    <DebugSymbols>true</DebugSymbols>
    <DebugType>full</DebugType>
    <Optimize>false</Optimize>
    <OutputPath>bin\$(Configuration)\$(Framework)\</OutputPath>
    <DefineConstants>DEBUG;TRACE;NET45</DefineConstants>
    <ErrorReport>prompt</ErrorReport>
    <WarningLevel>4</WarningLevel>
  </PropertyGroup>

  <PropertyGroup Condition=" '$(Framework)' == 'NET45' And '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
    <TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
    <PlatformTarget>AnyCPU</PlatformTarget>
    <DebugType>pdbonly</DebugType>
    <Optimize>true</Optimize>
    <OutputPath>bin\$(Configuration)\$(Framework)\</OutputPath>
    <DefineConstants>TRACE;NET45</DefineConstants>
    <ErrorReport>prompt</ErrorReport>
    <WarningLevel>4</WarningLevel>
  </PropertyGroup>
در اینجا تنظیمات حالت debug و release مخصوص دات نت 4.5 را مشاهده می‌کنید. برای نگارش‌های دیگر، تنها کافی است مقدار TargetFrameworkVersion را ویرایش کنید.
همچنین اگر به DefineConstants آن دقت کنید، مقدار NET45 نیز به آن اضافه شده‌است. این مورد سبب می‌شود که بتوانید در پروژه‌ی جاری، شرطی‌هایی را ایجاد کنید که کدهای آن فقط در حین کامپایل برای دات نت 4.5 به خروجی اسمبلی نهایی اضافه شوند:
 #if NET45
public class ExtensionAttribute : Attribute { }
#endif


د) افزودن تنظیمات پس از build
در انتهای فایل csproj قسمت AfterBuild به صورت کامنت شده موجود است. آن‌را به نحو ذیل تغییر دهید:
  <Target Name="AfterBuild">
    <Message Text="Enter After Build TargetFrameworkVersion:$(TargetFrameworkVersion) Framework:$(Framework)" Importance="high" />
    <MSBuild Condition=" '$(Framework)' != 'NET45'" Projects="$(MSBuildProjectFile)" Properties="Framework=NET45" RunEachTargetSeparately="true" />
    <Message Text="Exiting After Build TargetFrameworkVersion:$(TargetFrameworkVersion) Framework:$(Framework)" Importance="high" />
  </Target>
این تنظیم سبب می‌شود تا کامپایل مخصوص دات نت 4.5 نیز به صورت خودکار فعال گردد و خروجی آن در مسیر bin\Debug\NET45 به صورت جداگانه‌ای قرار گیرد.



برای آزمایش بیشتر، فایل csproj نهایی را از اینجا می‌توانید دریافت کنید:
DualTargetFrameworks.zip
 
نظرات مطالب
ASP.NET MVC #16
- با debug=false هم انجام میشه. برنامه رو خارج از ویژوال استودیو اجرا کنید. بحث دیباگ کد در VS.NET با مدیریت خطا توسط ASP.NET متفاوت است. debug=false برنامه ASP.NET رو تبدیل به حالت Release می‌کنه اما به این معنا نیست که مکانیزم‌های ASP.NET رو کلا از کار می‌اندازه. مصرف حافظه برنامه کمتر میشه. debug symbols از اسمبلی نهایی حذف خواهند شد. کامپایلر روی کد نهایی بهینه سازی‌هایی در جهت بالابردن سرعت انجام می‌ده.
- در MVC اگر از فیلتر Handle Error استفاده بشه application_error فراخوانی نخواهد شد. به علاوه با وجود ELMAH ضرورتی به استفاده از Handle error و application_error نیست. توضیح دادم در متن فوق. 
ضمن اینکه دیباگ کار شخصی افراد نیاز به بودن پروژه آن‌ها و بررسی آن(ها در یک انجمن مرتبط یا توسط یک مشاور) دارد. این جملات مبهم و کلی «من یه کاری یه جایی کردم، یکی یه چیزی گفت، برای من کار نکرد» ارزش یا امکان بررسی ندارند.
-
custom errors قرار گرفته در ریشه سایت بر روی کل سایت اعمال می‌شود (و تمام برنامه‌هایی که در زیر پوشه‌های آن هستند). در فایل‌های کانفیگ ASP.NET مباحث ارث بری وجود دارند. برای لغو آن یکی از راه‌ها استفاده از تگ location است، مثلا:
<location path="MyAreaName">
  <system.web>
    <customErrors mode="On" defaultRedirect="/MyAreaName/error" />
  </system.web>    
</location>

اشتراک‌ها
JIT compiler آزمایشی جدید دات نت
تیم دات نت در حال تهیه یک JIT compiler جدید است که برای دنیای X64 بهینه سازی شده‌است و همچنین از تکنیک‌های جدید کامپایلر ++VC استفاده می‌کند.
JIT compiler آزمایشی جدید دات نت
مطالب
روش‌هایی برای بهبود قابلیت دیباگ بسته‌های NuGet
عموما بسته‌های نیوگت تولید شده، قابلیت دیباگ ضعیفی را دارند. برای بالابردن بهبود تجربه‌ی کاربری آن‌ها می‌توان توزیع فایل‌های PDB و فعالسازی قابلیت Source Link را به آن‌ها اضافه کرد.


فعالسازی توزیع فایل‌های PDB به همراه بسته‌های NuGet

وجود فایل‌های PDB، برای اجرای برنامه‌ها ضرورتی ندارند؛ اما اگر ارائه شوند، به کمک آن‌ها می‌توان گزارش‌های استثناءهای بسیار کاملتری را به همراه نام فایل و شماره سطرهای مرتبط موجود در Exception.StackTrace، مشاهده کرد.
پیشتر توسعه دهندگان بسته‌های NuGet، فایل‌های PDB را خودشان با تعریف یک سری include در فایل مشخصات بسته، به فایل نهایی تولیدی اضافه می‌کردند. اما این روزها با ارائه‌ی «NuGet.org Symbol Server»، دیگر افزودن فایل‌های PDB به بسته‌های nupkg توصیه نمی‌شود. چون حجم نهایی و زمان بازیابی بسته‌ها را بیش از اندازه افزایش می‌دهند؛ خصوصا اگر مصرف کننده‌ای قصد دیباگ آن‌ها را نداشته باشد.
راه حل جدید توصیه شده، ارائه‌ی فایل‌های ویژه‌ی snupkg. در کنار بسته‌های nupkg. معمولی است که حاوی فایل‌های PDB متناظر با بسته‌ی اصلی NuGet هستند.

برای فعالسازی آن‌ها در پروژه‌های NET Core. بسته‌های نیوگت خود تنها کافی است دو تنظیم زیر را به فایل csproj اضافه کنید:
<PropertyGroup>
  <IncludeSymbols>true</IncludeSymbols>
  <SymbolPackageFormat>snupkg</SymbolPackageFormat>
</PropertyGroup>
در این حالت پس از ساخت بسته‌ی نیوگت توسط دستور «dotnet pack -c release»، دو فایل با پسوندهای snupkg و nupkg تولید می‌شوند که باید هر دو را به سایت NuGet ارسال کرد.

در سمت مصرف کننده، IDE شما باید برای کار با این Symbol Server تنظیم شده باشد.


فعالسازی تولید Source Link

وجود PDBها جهت دیباگ بسته‌های ارائه شده بسیار مفیدند؛ اما اگر بر روی کدهای نهایی بهینه سازی صورت گرفته باشد، ممکن است اطلاعات دیباگ آن‌ها با کد اصلی تطابق پیدا نکنند. برای بهبود این وضعیت و ارتقاء آن به یک سطح بالاتر، مفهوم source link ارائه شده‌است که مستقل است از نوع زبان و همچنین سورس کنترل.
کار سورس‌لینک، افزودن متادیتای سورس کنترل انتخابی، به بسته‌ی نهایی تولید شده‌است. به این صورت می‌توان سورس کامل و متناظر با قطعه کد بسته و کتابخانه‌ی ثالث در حال دیباگ را در IDE خود داشت و با آن به نحو متداولی کار کرد. یعنی سورس لینک، قابلیت «Step Into" the source code"» را مهیا می‌کند. متادیتای اضافه شده، دقیقا مشخص می‌کند که بسته‌ی تولیدی نهایی، متناظر با کدام commit سورس کنترل است. به این ترتیب دقیقا می‌توان به کدهای همان commit ای که بسته بر اساس آن کامپایل شده‌است، در IDE خود دسترسی یافت.
این قابلیت از Visual Studio 15.3 به بعد در اختیار کاربران آن است (گزینه‌ی Enable Source Server Support، در قسمت Debug/General آن باید فعال شود). همچنین Rider و VSCode نیز از آن پشتیبانی می‌کنند. برای Rider باید در قسمت Tools/External symbols، گزینه‌های Use sources from symbol files when available و Allow downloading symbols from remote locations را فعال کنید.
همچنین برای فعالسازی آن در فایل csproj بسته‌ی نیوگت خود می‌توانید تنظیمات زیر را اضافه کنید:
<PropertyGroup>
    <PublishRepositoryUrl>true</PublishRepositoryUrl>
    <EmbedUntrackedSources>true</EmbedUntrackedSources>
</PropertyGroup>
<ItemGroup>
  <PackageReference Include="Microsoft.SourceLink.GitHub" Version="1.0.0" PrivateAssets="All" />
</ItemGroup>
البته در اینجا پروایدر مخصوص GitHub را مشاهده می‌کنید (اگر مخزن کد بسته‌ی شما بر روی آن قرار دارد) و همچنین سایر پروایدرهای مخصوص سورس کنترل‌های دیگر مانند Azure DevOps/VSTS نیز برای آن تهیه شده‌اند.


روش فعالسازی Source Link در پروژه‌ی VSCode

اگر از VSCode استفاده می‌کنید، نیاز است تنظیمات زیر را به قسمت configurations فایل launch.json خود اضافه کنید تا قابلیت «Step Into" the source code"» بسته‌های نیوگتی که از SourceLink پشتیبانی می‌کنند، با فشردن دکمه‌ی F11 در حین دیباگ، فعال شود:
"justMyCode": false,
"symbolOptions": {
   "searchMicrosoftSymbolServer": true
},
"suppressJITOptimizations": true,
"env": {
   "COMPlus_ZapDisable": "1"
}
مطالب
چگونه نرم افزارهای تحت وب سریعتری داشته باشیم؟ قسمت ششم
قسمت پنجم 

17. پرهیز از استفاده نسخه debug
وقتی به ASP.NET مراجعه می‌کنید، توجه فرمایید که از چه نوع build برای محصول نهایی استفاده می‌کنید. وقتی از نسخه debug برنامه استفاده می‌کنید، بهبود دهنده‌های سطح کامپایلر عمل نکرده و کدشما در حالت بهینه اجرا نخواهد شد (کد شما همانگونه که هست اجرا می‌شود!).
برای مثال هنگامی که از نسخه release استفاده می‌کنید، کامپایلر c# به صورت خودکار از StringBuilder‌ها به جای تلفیق عادی رشته ها، از آرایه‌ها به جای لیست ها، از دستور switch/case به جای دستورات if/then/else، تلفیق شروط با یکدیگر و... استفاده کرده و کد شما را در حالت بهینه‌تری اجرا می‌کند. عدم استفاده از این نسخه شما را از این مزایا محروم می‌سازد و نرم افزار شما به کندی اجرا خواهد شد. البته ناگفته نماند این موضوع فقط باید برای محصول نهایی استفاده شود و جهت دیباگ کردن برنامه همچنان باید از نسخه debug استفاده نمایید.
توجه نمایید می‌توانید با استفاده از متغیرهای کامپایلر در کد خود بخشی از کد را مختص build خاصی از برنامه کنید. مثلا اگر برنامه در حال debug کامپایل شد، MiniProfiler را فعال کن در غیر این صورت غیر فعال باشد.
#if DEBUG
    //فعال کردن MiniProfiler
#endif

18.تنظیم دقیق لاگ‌های سیستم در محیط اجرا
وقتی محصول نهایی را آماده می‌کنید، فراموش نکنید که سطح لاگ گیری را در سطح مطلوبی قرار دهید تا بتوانید در صورت نیاز برنامه را اشکال زدایی کنید. البته زیاده روی در این مورد نیز می‌تواند مشکل زا باشد.
اکثر برنامه نویسان هنگامی که محصول نهایی را برای مشتری آماده می‌کنند، لاگ را غیر فعال می‌کنند تا کاربر سرعت بیشتری را تجربه کند. این سیاست غلط شما را از امکانات بی نظیر لاگ کردن (مانند وقابع نگاری امنیتی، رفع سریع مشکلات و...) محروم می‌سازد. بنابر این حتما سیستم لاگ خود را در زمان تولید محصول اصلی (و نصب بر روی سرور اصلی) در حالت متعادلی تنظیم نمایید. کمی تست و تجربه شما را در این امر یاری می‌کند.

19.مشخص کردن اندازه عکس
مشخص کردن اندازه عکس در تک img به صورت css یا attribute باعث می‌شود که همان اولین بار که صفحه رندر می‌شود، اندازه مورد نیاز عکس به آن اختصاص یابد تا در صورت دانلود سریعا جایگرین آن گردد. عدم مشخص کردن سایز عکس (طول و عرض) باعث رندر شدن مجدد تمامی المان‌های صفحه بعد از دانلود هر عکس از سرور می‌شود و منابع با ارزش cpu کاربر شما را به سادگی از بین می‌برد.
<img src="smiley.gif" alt="Smiley face" height="42" width="42">

مطالب
درست کردن فایل راهنمای CHM از توضیحات XML یک پروژه

تا حالا هیچ وقت برای شما این سؤال پیش اومده که این فایل‌های CHM راهنمای زیبایی که برای مثال به‌عنوان مستندات یک کتابخانه در دات نت ارائه می‌شوند با چه نرم‌افزار یا نرم‌افزارهایی تولید می‌شوند؟ یا اینکه به نظر یک یا چند نفر ساعت‌ها وقت می‌گذارند، صفحات HTML مربوطه را تولید می‌کنند و در آخر با استفاده از ابزارهای تولید فایل CHM ، فایل راهنما را نهایی می‌کنند؟
این فایل‌ها به صورت خودکار بر اساس XML code comments ارائه شده برای یک متد ، کلاس و امثال آن تولید می‌شوند. برای مثال به توضیحات زیر دقت بفرمائید:

/// <summary>
/// استخراج ایمیل‌های یک فایل متنی و ذخیره آن در فایلی جدید
/// </summary>
/// <param name="inFilePath">فایل ورودی</param>
/// <param name="outFilePath">فایل خروجی</param>
public static void ExtractEmails(string inFilePath, string outFilePath)

هر چند VS.Net‌ در ایجاد خوکار قالب اولیه این نوع کامنت‌ها بسیار خوب عمل می‌کند اما نکات پیشرفته‌تری نیز در این‌باره موجود هستند که در کیفیت فایل راهنمای تولید شده بر اساس این توضیحات بسیار مؤثرند. راهنمای کاملی در این‌باره را از اینجا می‌توانید دریافت کنید.
در ادامه نحوه تولید خودکار این نوع راهنماها را بررسی خواهیم کرد.

الف) نصب برنامه‌های مورد نیاز
برای ایجاد فایل chm از توضیحات xml ایی ارائه شده، ابتدا دو برنامه سورس باز زیر را دریافت و نصب کنید:
سپس نیاز به HTML Help 2.0 compiler خواهد بود. این کامپایلر به همراه SDK ویژوال استودیو ارائه می‌شود. بسته به نگارش VS مورد استفاده، نیاز است تا یکی از موارد زیر را دریافت و نصب کنید:
برنامه hxcomp.exe ذکر شده، عموما در مسیر زیر نصب خواهد شد:
%Program Files%\Common Files\Microsoft Shared\Help 2.0 Compiler\
ب) تنظیمات VS.Net
مرحله بعد به تنظیمات VS.Net مربوط می‌شود. به صفحه خواص پروژه مراجعه کنید و در برگه Build ، گزینه تولید XML documentation file را انتخاب کنید. سپس مجددا پروژه خود را کامپایل کنید.

ج) تنظیمات Sandcastle Help File Builder
یک پروژه جدید را در این برنامه آغاز کرده و سپس فایل اسمبلی و xml تولید شده آنرا انتخاب کنید. (بر روی دکمه add کلیک کرده و هر دو فایل exe یا dll مورد نظر را به همراه فایل xml آن که در قسمت ب تولید کردیم، انتخاب کنید. در صورت عدم انتخاب یکی از موارد فایل راهنما تولید نخواهد شد)
اکنون نوبت به تنظیمات پروژه می‌رسد.
در قسمت Build:
گزینه Help File Format را انتخاب کرده و سپس html help 2x را نیز تیک بزنید. (در صورت تمایل به تولید این نوع فرمت)
در قسمت Dependencies ، تمام اسمبلی‌هایی را که پروژه شما به آن وابسته است، اضافه کنید.
توسط گزینه Framework Version ، نگارشی از دات نت فریم ورک که اسمبلی شما بر اساس آن کامپایل شده است را انتخاب کنید.
در قسمت Help File:
Presentation Style را بر روی VS2005 قرار دهید. این‌کار اجباری نیست اما راهنمای حاصل زیباتر خواهد بود.
در قسمت Paths :
مسیرهای کامپایلرهای راهنما را مشخص کنید. بر روی سیستم من این مسیرها مطابق شکل زیر هستند:


اگر HTML Help Workshop بر روی سیستم شما نصب نبود، آنرا از این آدرس دریافت نمائید.

د) ساخت فایل راهنما
بر روی آیکون build در نوار ابزار برنامه کلیک کنید (و یا انتخاب گزینه documentation->build)

تا اینجا اگر هر دو نوع Help1xAndHelp2x را در قسمت build انتخاب کرده باشید، دو نوع راهنمای مستقل و همچنین قابل یکپارچه شدن با سیستم راهنمای VS.net را تولید کرده‌اید.



ه) یکپارچه سازی Help2x تولید شده با سیستم راهنمای VS.Net
پروژه جدیدی را در VS.Net از نوع Other Project Types > Extensibility > Help Integration Wizard ایجاد کنید. در مرحله اول، ایجاد setup و نوع VS را انتخاب کرده و در صفحه بعد فایل‌های Help2x خود را اضافه کنید (فایلهایی با پسوند hxs). دو مرحله آخر را مطابق نیازهای کاری خود تنظیم نموده و پروژه را در آخر build کنید. نصاب تولید شده فایل‌های راهنمای شما را با سیستم راهنمای VS.Net یکپارچه خواهد ساخت.

چند نکته:
1- جهت سفارشی سازی بیشتر راهنمای تولید شده می‌توان از ابزار سورس باز زیر نیز کمک گرفت:
http://www.codeplex.com/DocProject
2- افزونه‌ای رایگان برای VS.Net جهت سهولت تولید توضیحات XML در آدرس زیر قابل دریافت است:
http://www.roland-weigelt.de/ghostdoc