نظرات مطالب
افزونه فارسی به پارسی برای word 2007
با درود و سپاس
وحید جان همه چیز روبراه است اما در زمان نصب افزونه در پایان نصب یکدفعه note pad باز شده و متنی را نمایش می‌دهد که بدلیل داشتن عبارات اج تی تی پی و غیره نمی‌توان آنها را در اینجا درج نمود.
البته من کلمات را جدا جدا نوشتم تا بتوان این عبارت را در اینجا درج کنم و در ضمن این افزونه در لیست add-in وجود ندارد و در Event viewer نیز خطایی نیست. وهنگامی که سعی کردم از طریق add آنرا نصب کنم باز هم همان صفحه Note Pad در پایان کار نمایش داده شد.

با سپاس

با سپاس.
مطالب
آشنایی با ساختار IIS قسمت اول
در مقاله قبل در مورد نحوه ذخیره سازی در حافظه نوشتیم و به user mode و kernel mode اشاراتی کردیم که می‌توانید به آن رجوع کنید.
در این سری مقالات قصد داریم به بررسی اجزا و روند کاری موجود در IIS بپردازیم که چگونه IIS کار می‌کند و شامل چه بخش هایی می‌شود. مطمئنا آشنایی با این بخش‌ها در روند شناسایی رفتارهای وب اپلیکیشن‌ها و واکنش‌های سرور، کمک زیادی به ما خواهد کرد. در اینجا نسخه IIS7 را به عنوان مرجع در نظر گرفته‌ایم.
وب سرور IIS در عبارت مخفف Internet information services به معنی سرویس‌های اطلاعاتی اینترنت می‌باشد. IIS شامل کامپوننت‌های زیادی است که هر کدام ازآن‌ها کار خاصی را انجام میدهند؛ برای مثال گوش دادن به درخواست‌های ارسال شده به سرور، مدیریت فرآیندها Process و خواندن فایل‌های پیکربندی Configuration؛ این اجزا شامل protocol listener ،Http.sys و WSA و .. می‌شوند.
Protocol Listeners
این پروتکل‌ها به درخواست‌های رسیده گوش کرده و آن‌ها را مورد پردازش قرار می‌دهند و پاسخی را به درخواست کننده، ارسال می‌کنند. هر listener بر اساس نوع پروتکل متفاوت هست. به عنوان مثال کلاینتی، درخواست صفحه‌ای را می‌کند و http listener که به آن Http.sys می‌گویند به آن پاسخ می‌دهد. به طور پیش فرض http.sys به درخواست‌های http و https گوش فرا می‌دهد، این کامپوننت از IIS6 اضافه شده است ولی در نسخه 7 از SSL نیز پشتیبانی می‌کند.
Http.sys یا Hypertext transfer protocol stack
کار این واحد در سه مرحله دریافت درخواست، ارسال آن به واحد پردازش IIS و ارسال پاسخ به کلاینت است؛ قبل از نسخه 6 از Winsock یا windows socket api  که یک کامپوننت user-mod بود استفاده می‌شد ولی Http.sys یک کامپوننت Kernel-mod هست.

Http.sys مزایای زیر را به همراه دارد:

  • صف درخواست مد کرنل: به خاطر اینکه کرنل مستقیما درخواست‌ها را به پروسه‌های مربوطه میفرستد و اگر پروسه موجود نباشد، درخواست را در صف گذاشته تا بعدا پروسه مورد نظر آن را از صف بیرون بکشد.
  • برای درخواست‌ها یک پیش پردازش و همچنین اعمال فیلترهای امنیتی اعمال می‌گردد. 
  • عملیات کش کردن تماما در محیط کرنل مد صورت می‌گیرد؛ بدون اینکه به حالت یوزرمد سوییچ کند. مد کرنل دسترسی بسیار راحت و مستقیمی را برای استفاده از منابع دارد و لازم نیست مانند مد کاربر به لایه‌های زیرین، درخواست کاری را بدهد؛ چرا که خود مستقیما وارد عمل می‌شود و برداشته شدن واسط در سر راه، موجب افزایش عمل caching می‌شود. همچنین دسترسی به کش باعث می‌شود که مستقیما پاسخ از کش به کاربر برسد و توابع پردازشی در حافظه بارگذاری نشوند. البته این کش کردن محدودیت هایی را هم به همراه دارد:
    1. کش کرنل به صورت پیش فرض بر روی صفحات ایستا فعال شده است؛ نه برای صفحاتی با محتوای پویا که البته این مورد قابل تغییر است که نحوه این تغییر را پایینتر توضیح خواهیم داد.
    2. اگر آدرس درخواستی شامل کوئری باشد صفحه کش نخواهد شد:    http://www.site.info/postarchive.htm?id=25 
    3. برای پاسخ ازمکانیزم‌های فشرده سازی پویا استفاده شده باشد مثل gzip کش نخواهد شد
    4. صفحه درخواست شده صفحه اصلی سایت باشد کش نخواهد شد :   http://www.dotnettip.info ولی اگر درخواست بدین صورت باشه http://www.domain.com/default.htm  کش خواهد کرد.
    5. درخواست به صورت ناشناس anonymous نباشد  و نیاز به authentication داشته باشد کش نخواهد شد (یعنی در هدر شامل گزینه authorization می‌باشد).
    6. درخواست باید از نوع نسخه http1 به بعد باشد.
    7. اگر درخواست شامل Entity-body باشد کش نخواهد کرد.
    8. درخواست شامل If-Range/Range header باشد کش نمی‌شود.
    9. کل حجم response بییشتر از اندازه تعیین شده باشد کش نخواهد گردید، این اندازه در کلید ریجستری UriMaxUriBytes قرار دارد. اطلاعات بیشتر
    10. اندازه هدر بیشتر از اندازه تعیین شده باشد که عموما اندازه تعیین شده یک کیلو بایت است.
    11. کش پر باشد، کش انجام نخواهد گرفت.
    برای فعال سازی کش کرنل راهنمای زیر را دنبال کنید:
    گزینه output cache را در IIS، فعال کنید و سپس گزینه Add را بزنید. کادر add cache rule که باز شود، از شما میخواهد یکی از دو نوع کش مد کاربر و مد کرنل را انتخاب کنید و  مشخص کنید چه نوع فایل‌هایی (مثلا aspx) از این قوانین پیروری کنند و مکانیزم کش کردن به سه روش جلوگیری از کش کردن، کش زمان دار و کش بر اساس آخرین تغییر فایل انجام گردد.


    برای تعیین مقدار سایز کش response که در بالا اشاره کردیم می‌توانید در همان پنجره، گزینه edit feature settings را انتخاب کنید.


    این قسمت از مطلب که به نقل از مقاله  آقای Karol Jarkovsky در این آدرس است یک سری تست هایی با نرم افزار(Web Capacity Analysis Tool (WCAT  گرفته است که به نتایج زیر دست پیدا کرده است:
    Kernel Cache Disabled    4 clients/160 threads/30 sec      257 req/sec
    Kernel Cache Enabled     4 clients/160 threads/30 sec      553 req/sec 
    همانطور که می‌بینید نتیجه فعال سازی کش کرنل پاسخ به بیش از دو برابر درخواست در حالت غیرفعال آن است که یک عدد فوق العاده به حساب میاد.
    برای اینکه خودتان هم تست کرده باشید در این آدرس  برنامه را دانلود کنید و به دنبال فایل request.cfg بگردید و از صحت پارامترهای server و url اطمینان پیدا کنید. در گام بعدی 5 پنجره خط فرمان باز کرده و در یکی از آن‌ها دستور netsh http show cachestate را بنویسید تا تمامی وروردی‌های entry که در کش کرنل ذخیره شده اند لیست شوند. البته در اولین تست کش را غیرفعال کنید و به این ترتیب نباید چیزی نمایش داده شود. در همان پنجره فرمان wcctl –a localhost –c config.cfg –s request.cfg  را زده تا کنترلر برنامه در وضعیت listening قرار بگیرد. در 4 پنجره دیگر فرمان wcclient localhost از شاخه کلاینت را نوشته تا تست آغاز شود. بعد از انجام تست به شاخه نصب کنترلر WCAT رفته و فایل log را بخوانید و اگر دوباره دستور نمایش کش کرنل را بزنید باید خالی باشد. حالا کش را فعال کنید و دوباره عملیات تست را از سر بگیرید و اگر دستور netsh را ارسال کنید باید کش کرنل دارای ورودی باشد.
    برای تغییرات در سطح http.sys می‌توانید از ریجستری کمک بگیرید. در اینجا تعداد زیادی از تنظیمات ذخیره شده در ریجستری برای http.sys لیست شده است.
    مطالب
    یکپارچه سازی TortoiseSVN و YouTrack
    پیش نیاز
    اگر در مورد TortoiseSVN و سورس کنترل اطلاعات پایه ندارید، کتاب  مدیریت فایلهای یک پروژه نرم افزاری با استفاده از Subversion  آقای نصیری را مطالعه کنید و همچنین سیستم پیگیری خطای  YouTrack را نگاهی بیاندازید (البته اگر اطلاعی ندارید).

    مقدمه
    هنگام کار روی یک پروژه، باگ ها، وظیفه‌ها و موضوعاتی به شما واگذار می‌شود که باید انها را انجام دهید. هنگام commit کردن تغییرات، برای مشخص شدن اینکه تغییرات مربوط به کدام Bug-Id بوده است بود است باید سیستم Bug/Issue Tracker رو با سورس کنترل یکپارچه کنیم. 

    یکپارچه سازی TortoiseSVN و YouTrack
    1- روی یک نسخه کاری پروژه راست کلیک، از منوی TortoiseSVN گزینه Properties را انتخاب کنید.

    گزینه Properties در TortoiseSVN

    2- از پنجر باز شده دکمه New، گزینه Other را انتخاب کنید. در پنجره باز شده از منوی کشویی مربوط به Property Name، مقادیر خصلت‌های زیر را تنظیم کنید:
    bugtraq:url : آدرس YouTrack Sever که به این صورت وارد می‌شود: %http://localhost:8080/issue/%BUGID
    bugtraq:message : درو اقع الگویی پیامی هست که برای نگهداری Bug-Id استفاده می‌شود و باید شامل کلمه %BUGID% باشد. مثلا: %Issue: %BUGID
    bugtraq:number : مقدار این خصلت را false وارد کنید؛ چون Bug-Idهای‌های YouTrack می‌توانند شامل عدد و حروف باشند.

    دیالوگ Propeties


    بعد از اینکه این سه خصلت را مقداردهی کرید، تغییرات را Commit کنید. همانطور که می‌بینید یک Textbox (بالا، سمت راست) اضافه شده که محل وارد کردن Bug-Id مربوط به تغییرات است. از این پس، می‌توانید Bug-Id یا Issue-Id‌های مربوط به هر تغییرات را در آن Textbox وارد کنید.


    همچنین تغییرات در پلاگین AnkhSVN در ویژال استودیو نیز اعمال می‌شود:


    اکنون، در متن commitها شماره Bud-Id نیز ذکر شده است.


    نکته 1: اگر YouTrack روی یک سرور نصب هست، بجای localhost نام کامپیوتر سرور یا آی پی آن را وارد کنید. پورت 8080 نیز بصورت پیش فرض است و اگر هنگام نصب آن را تغییر داده اید، اینجا نیز آنرا تغییر دهید.
    نکته 2: خصلت bugtraq:message یک الگوی پیام از شما می‌گیرد؛ یعنی الگو را تحت هر شکلی می‌توان وارد کرد. بعنوان مثال الگو را به این شکل وارد کنید: "برای مشاهده جزئیات بیشتر به Bug-Id شماره %BUGID% مراجعه کنید."
    نکته 3: اگر خصلت bugtraq:number مقدارش true باشد، برای وارد کردن Bug-Id فقط از عدد می‌توانید استفاده کنید. بصورت پیش فرض مقدار این خصلت true است.
    نکته 4: می‌توانید این تنظیمات را در یک فایل Export کنید و در بقیه پروژه ها، با یک مرحله و بسادگی آنرا Import کنید.
    خصلت‌های دیگری نیز می‌توان برروی مخزن کد اعمال کرد که از حوزه این مقاله خارج است. همچنین تنظمیات اختیاری جانبی دیگری نیز برای یکپارچه سازی وجود دارند. برای دیدن این تنظمیات روی نسخه کاری راست کلیک، از منوی TortoiseSVN گزینه Properties را انتخاب کنید و از پنجره باز شده روی دکمه New و گزینه ( Bugtraq (Issue tracker integration  را انتخاب کنید.

    برای اطلاعات بیشتر در مورد این تنظیمات، داکیومنت یکپارچه سازی با سیستم‌های Bug tracking / Issue Tracking  را مطالعه کنید. 
    مطالب
    استفاده از Flash Uploader در ASP.NET MVC
    چندسال قبل یک کنترل آپلود فایل در برنامه‌های ASP.NET Web forms در سایت Code projects منتشر شد که من در چند پروژه از آن استفاده کردم.
    در ادامه نحوه سازگار سازی این مجموعه را با ASP.NET MVC مرور خواهیم کرد:

    الف) سورس‌های اصلی Flash کنترل ارسال فایل‌ها
    اگر علاقمند به تغییر اطلاعاتی در فایل فلش نهایی هستید به پوشه OriginalFlashSource پروژه پیوست شده مراجعه کنید. در اینجا برای مثال یک سری از برچسب‌های آن فارسی شده‌اند و کامپایل مجدد.


    ب) مزیت استفاده از Flash uploader
    با استفاده از Flash uploader امکان انتخاب چندین فایل با هم وجود دارد. همچنین در صفحه دیالوگ انتخاب فایل‌ها دقیقا می‌توان پسوند فایل‌های مورد نظر را نیز تعیین کرد. این دو مورد در حالت ارسال معمولی فایل‌ها به سرور و استفاده از امکانات معمولی HTML وجود ندارند. به علاوه امکان نمایش درصد پیشرفت آپلود فایل‌ها و همچنین حذف کلی لیست و حذف یک آیتم از لیست را هم درنظر بگیرید.



    ج) معادل کنترل Web forms را در ASP.NET MVC به شکل زیر می‌توان تهیه کرد:

    @helper AddFlashUploader(
                    string uploadUrl,
                    string queryParameters,
                    string flashUrl,
                    int totalUploadSizeLimit = 0,
                    int uploadFileSizeLimit = 0,
                    string fileTypes = "",
                    string fileTypeDescription = "",
                    string onUploadComplete = "")
        {      
            onUploadComplete = string.IsNullOrEmpty(onUploadComplete) ? "" : "completeFunction=" + onUploadComplete;
            queryParameters = Server.UrlEncode(queryParameters);        
            fileTypes = string.IsNullOrEmpty(fileTypes) ? "" : "&fileTypes=" + Server.UrlEncode(fileTypes);
            fileTypeDescription = string.IsNullOrEmpty(fileTypeDescription) ? "" : "&fileTypeDescription=" + Server.UrlEncode(fileTypeDescription);
            var totalUploadSizeLimitData = totalUploadSizeLimit > 0 ? "&totalUploadSize=" + totalUploadSizeLimit : "";
            var uploadFileSizeLimitData = uploadFileSizeLimit > 0 ? "&fileSizeLimit=" + uploadFileSizeLimit : "";
            var flashVars = onUploadComplete + fileTypes + fileTypeDescription + totalUploadSizeLimitData + uploadFileSizeLimitData + "&uploadPage=" + uploadUrl + "?" + queryParameters;
        <object classid="clsid:d27cdb6e-ae6d-11cf-96b8-444553540000" codebase="http://fpdownload.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=9,0,0,0"
            width="575" height="375" id="fileUpload" align="middle">
            <param name="allowScriptAccess" value="sameDomain" />
            <param name="movie" value="@flashUrl" />
            <param name="quality" value="high" />
            <param name="wmode" value="transparent">
            <param name=FlashVars value="@flashVars">
            <embed src="@flashUrl"
                   FlashVars="@flashVars" 
                   quality="high" 
                   wmode="transparent" 
                   width="575" 
                   height="375" 
                   name="fileUpload" 
                   align="middle" 
                   allowScriptAccess="sameDomain" 
                   type="application/x-shockwave-flash" 
                   pluginspage="http://www.macromedia.com/go/getflashplayer" />
        </object>                        
    }
    این اطلاعات در فایلی به نام FlashUploadHelper.cshtml در پوشه App_Code قرار خواهند گرفت.


    د) نحوه استفاده از HTML helper فوق:

    @{
        ViewBag.Title = "Index";
        var uploadUrl = Url.Action("Uploader", "Home");
        var flashUrl = Url.Content("~/Content/FlashUpload/FlashFileUpload.swf");
    }
    <h2>
        Flash Uploader</h2>
    <div style="background: #E0EBEF;">
        @FlashUploadHelper.AddFlashUploader(
                    uploadUrl: uploadUrl,
                    queryParameters: "User=Vahid&Id=تست",
                    flashUrl: flashUrl,
                    fileTypeDescription: "Images",
                    fileTypes: "*.gif; *.png; *.jpg; *.jpeg",
                    uploadFileSizeLimit: 0,
                    totalUploadSizeLimit: 0,
                    onUploadComplete: "alert('انجام شد');")
    </div>
    با کدهای کنترلری معادل:
    using System.Collections.Generic;
    using System.IO;
    using System.Web;
    using System.Web.Mvc;
    
    namespace MvcFlashUpload.Controllers
    {
        public class HomeController : Controller
        {
            public ActionResult Index()
            {
                return View();
            }
    
            public ActionResult Uploader(string User, string Id, IEnumerable<HttpPostedFileBase> FileData)
            {
                var queryParameter1 = User;
                var queryParameter2 = Id;
                // ...
    
                foreach (var file in FileData)
                {
                    if (file.ContentLength > 0)
                    {
                        var fileName = Path.GetFileName(file.FileName);
                        var path = Path.Combine(Server.MapPath("~/App_Data/Uploads"), fileName);
                        file.SaveAs(path);
                    }
                }
    
                return Content(" ");
            }
        }
    }

    توضیحات:
    در اینجا uploadUrl، مسیر اکشن متدی است که قرار است اطلاعات فایل‌ها را دریافت کند. queryParameters اختیاری است. اگر تعریف شود تعدادی کوئری استرینگ دلخواه را می‌تواند به متد Uploader ارسال کند. برای نمونه در اینجا User و Id ارسال شده‌اند یا هر نوع کوئری استرینگ دیگری که مدنظر است.
    flashUrl مسیر فایل SWF را مشخص می‌کند. در اینجا فایل FlashFileUpload.swfدر پوشه Content/FlashUpload قرار گرفته است.
    fileTypeDescription برچسبی است که نوع فایل‌های قابل انتخاب را به کاربر نمایش می‌دهد و fileTypes نوع‌های مجاز قابل ارسال را دقیقا مشخص می‌کند.
    پارامترهای uploadFileSizeLimit و totalUploadSizeLimit در صورتیکه مساوی صفر وارد شوند، به معنای عدم محدودیت اندازه در فایل‌ها و جمع حجم ارسالی در هر بار است.
    استفاده از پارامتر onUploadComplete اختیاری است. در اینجا می‌توان پس از پایان عملیات از طریق جاوا اسکریپت عملیاتی را انجام داد. برای مثال اگر خواستید کاربر را به صفحه خاصی هدایت کنید، window.locationرا مقدار دهی نمائید.
    در متد Uploader کنترلر فوق، پارامترهای User و id اختیاری بوده و بر اساس queryParameters متد FlashUploadHelper.AddFlashUploader مشخص می‌شوند. اما نام FileData نباید تغییری کند؛ از این لحاظ که دقیقا همین نام در فایل فلش، مورد استفاده قرار گرفته است.
    در اکشن متد دریافت فایل‌ها، لیستی از فایل‌های ارسالی به سرور دریافت شده و سپس بر این اساس می‌توان آن‌ها را در مکانی مشخص ذخیره نمود.


    دریافت پروژه
    MvcFlashUploader.zip
    مطالب
    مدیریت پیشرفته‌ی حالت در React با Redux و Mobx - قسمت ششم - MobX چیست؟
    پیش از بحث در مورد «مدیریت حالت»، باید با مفهوم «حالت» آشنا شد. «حالت» در اینجا همان لایه‌ی داده‌های برنامه است. زمانیکه بحث React و کتابخانه‌های مدیریت حالت آن مطرح می‌شود، می‌توان گفت حالت، شیءای است حاوی اطلاعاتی که برنامه با آن سر و کار دارد. برای مثال اگر برنامه‌ای قرار است لیستی از موارد را نمایش دهد، حالت برنامه، حاوی اشیاء متناظری خواهد بود. حالت، بر روی نحوه‌ی رفتار و رندر کامپوننت‌های React تاثیر می‌گذارد. بنابراین مدیریت حالت، روشی است برای ردیابی و مدیریت داده‌های مورد استفاده‌ی در برنامه و تقریبا تمام برنامه‌ها به نحوی نیاز به آن‌را خواهند داشت.
    داشتن یک کتابخانه‌ی مدیریت حالت برای برنامه‌های React بسیار مفید است؛ خصوصا اگر این برنامه پیچیده باشد و برای مثال در آن نیاز به اشتراک گذاری داده‌ها، بین دو کامپوننت یا بیشتر که در یک رده سلسه مراتبی قرار نمی‌گیرند، وجود داشته باشد. اما حتی اگر از یک کتابخانه‌ی مدیریت حالت استفاده شود، شاید راه حلی را که ارائه می‌کند آنچنان تمیز و قابل انتظار نباشد. با MobX می‌توان از ساختارهای پیچیده‌ی شیءگرا به سادگی استفاده کرد (mutation مستقیم اشیاء در آن مجاز است) و همچنین برای کار با آن به همراه React، نیاز به کدهای کمتری است نسبت به Redux. در اینجا از مفاهیم Reactive programming استفاده می‌شود؛ اما سعی می‌کند پیچیدگی‌های آن‌را مخفی کند. در نام MobX، حرف X به Reactive بودن آن اشاره می‌کند (مانند RxJS) و ob آن از observable گرفته شده‌است. M هم به حرف ابتدای نام شرکتی اشاره می‌کند که این کتابخانه را ایجاد کرده‌است.


    خواص محاسبه شده در جاوا اسکریپت

    برای کار با MobX، نیاز است تا ابتدا با یکسری از مفاهیم آن آشنا شد؛ مانند خواص محاسبه شده (computed properties). برای مثال در اینجا یک کلاس متداول جاوا اسکریپتی را داریم:
    class Person {
        constructor(firstName, lastName) {
           this.firstName = firstName;
           this.lastName = lastName;
        }
    
        fullName() {
          return `${this.firstName} ${this.lastName}`;
        }
    }
    که در آن از طریق سازنده، دو پارامتر نام و نام خانوادگی دریافت شده و سپس به دو خاصیت جدید، نسبت داده شده‌اند. اکنون برای محاسبه‌ی نام کامل، که حاصل جمع این دو است، می‌توان متد fullName را به این کلاس اضافه کرد. روش کار با آن نیز به صورت زیر است:
    const person = new Person('Vahid', 'N');
    person.firstName; // 'Vahid'
    person.lastName; // 'N'
    person.fullName; // function fullName() {…}
    اگر بر اساس متغیر person که بیانگر وهله‌ای از شیء Person است، سعی در خواندن مقادیر خواص شیء ایجاد شده کنیم، آن‌ها را دریافت خواهیم کرد. اما ذکر person.fullName (بدون هیچ () در مقابل آن)، تنها اشاره‌گری را به آن متد بازگشت می‌دهد و نه نام کامل را که البته یکی از ویژگی‌های جالب جاوا اسکریپت است و امکان ارسال آن‌را به سایر متدها، به صورت پارامتر میسر می‌کند.
    در ES6 برای اینکه تنها با ذکر person.fullName بدون هیچ پرانتزی در مقابل آن بتوان به مقدار کامل fullName رسید، می‌توان از روش زیر و با ذکر واژه‌ی کلیدی get، در پیش از نام متد، استفاده کرد:
    class Person {
        constructor(firstName, lastName) {
           this.firstName = firstName;
           this.lastName = lastName;
        }
    
        get fullName() {
          return `${this.firstName} ${this.lastName}`;
        }
    }
    در اینجا هرچند fullName هنوز یک متد است، اما اینبار فراخوانی person.fullName، حاصل جمع دو خاصیت را بازگشت می‌دهد و نه اشاره‌گری به آن متد را.
    اگر شبیه به همین قطعه کد را بخواهیم در ES5 پیاده سازی کنیم، روش آن به صورت زیر است:
    function Person(firstName, lastName) {
       this.firstName = firstName;
       this.lastName = lastName;
    }
    
    Object.defineProperty(Person.prototype, 'fullName', {
       get: function () {
          return this.firstName + ' ' + this.lastName;
       }
    });
    به این ترتیب می‌توان یک خاصیت محاسبه شده‌ی ویژه‌ی ES5 را تعریف کرد.

    اکنون فرض کنید قسمتی از state برنامه‌ی React، قرار است خاصیت ویژه‌ی fullName را نمایش دهد. برای اینکه UI برنامه با تغییرات نام و نام خانوادگی، متوجه تغییرات fullName که یک خاصیت محاسباتی است، شود و آن‌را رندر مجدد کند، باید در طی یک حلقه‌ی بی‌نهایت، مدام آن‌را فراخوانی کند و نتیجه‌ی جدید را با نتیجه‌ی قبلی محاسبه کرده و تغییرات را نمایش دهد. اینجا است که MobX یک چنین پیاده سازی‌هایی را به کمک مفهوم decorators، ساده می‌کند.


    Decorators در جاوا اسکریپت

    تزئین کننده‌ها یا decorators در سایر زبان‌های برنامه نویسی نیز وجود دارند؛ اما پیاده سازی آن‌ها در جاوا اسکریپت هنوز در مرحله‌ی آزمایشی است. Decorators در جاوا اسکریپت چیزی نیستند بجز بیان زیبای higher-order functions.
    higher-order functions، توابعی هستند که توابع دیگر را با ارائه‌ی قابلیت‌های بیشتری، محصور می‌کنند. به همین جهت هر کاری را که بتوان با تزئین کننده‌ها انجام داد، همان را با توابع معمولی جاوا اسکریپتی نیز می‌توان انجام داد. یک نمونه از این higher-order functions را در سری جاری تحت عنوان higher-order components با متد connect کتابخانه‌ی react-redux مشاهده کرده‌ایم. متد connect، متدی است که متدهای نگاشت state به props و نگاشت dispatch به props را دریافت کرده و سپس یک کامپوننت را نیز دریافت می‌کند و آن‌را به صورت محصور شده‌ای ارائه می‌دهد تا بجای کامپوننت اصلی مورد استفاده قرار گیرد؛ به یک چنین کامپوننت‌هایی، higher-order components گفته می‌شود.

    برای تعریف تزئین کننده‌ها، به نحوه‌ی پیاده سازی Object.defineProperty در مثال فوق دقت کنید:
    Object.defineProperty(Person.prototype, 'fullName', {
        enumerable: false,
        writable: false,
        get: function () {
          return this.firstName + ' ' + this.lastName;
        }
    });
    در اینجا Person.prototype یک target است. ثابت fullName، یک کلید است. سایر خواص ذکر شده، مانند enumerable، writable و get، تحت عنوان Descriptor شناخته می‌شوند.
    در ذیل روش تعریف یک تزئین کننده را مشاهده می‌کنید که دقیقا از یک چنین الگویی پیروی می‌کند:
    function decoratorName(target, key, descriptor) {
     // …
    }
    برای مثال در اینجا روش پیاده سازی تزئین کننده‌ی readonly را ملاحظه می‌کنید:
    function readonly(target, key, descriptor) {
       descriptor.writable = false;
       return descriptor;
    }
    سپس روش اعمال آن به یک خاصیت محاسباتی در کلاس Person به صورت زیر است:
    class Person {
        constructor(firstName, lastName) {
           this.firstName = firstName;
           this.lastName = lastName;
        }
    
        @readonly get fullName() {
          return `${this.firstName} ${this.lastName}`;
        }
    }
    ذکر یک تزئین کننده با @ شروع می‌شود. سپس متد fullName را دریافت کرده و نگارش جدیدی از آن‌را بازگشت می‌دهد؛ بطوریکه readonly باشد.


    مثال‌هایی از تزئین کننده‌ها

    برای نمونه می‌توان تزئین کننده‌ی bindThis@ را طراحی کرد تا کار bind شیء this را به متدهای کامپوننت‌های React انجام دهد و یا کتابخانه‌ای به نام core-decorators وجود دارد که به صورت زیر نصب می‌شود:
    > npm install core-decorators
    و به همراه این تزئین کننده‌ها می‌باشد:
    @autobind
    @deprecate
    @readonly
    @memoize
    @debounce
    @profile
    برای مثال autobind آن، همان کار bind شیء this را انجام می‌دهد. deprecate جهت نمایش یک اخطار، در کنسول توسعه دهندگان مرورگر، جهت گوشزد کردن منسوخ بودن قسمتی از برنامه، استفاده می‌شود.

    نمونه‌ی دیگری از این کتابخانه‌ها lodash-decorators است که تعدادی دیگر از تزئین کننده‌ها را ارائه می‌کند.


    MobX چگونه کار می‌کند؟

    انجام یکسری از کارها با Redux مشکل است؛ برای مثال تغییر دادن یک شیء تو در توی پیچیده که شامل تهیه‌ی یک کپی از آن، اعمال تغییرات و غیره‌است. اما با MobX می‌توان با اشیاء جاوا اسکریپتی به همان صورتی که هستند کار کرد. برای مثال آرایه‌ای را با متدهای push و pop تغییر داد (mutation اشیاء مجاز است) و یا خواص اشیاء را به صورت مستقیم ویرایش کرد، در این حالت MobX اعلام می‌کند که ... من می‌دانم که چه تغییری صورت گرفته‌است. بنابراین سبب رندر مجدد UI خواهم شد.


    ایجاد یک برنامه‌ی خالی React برای آزمایش MobX

    در اینجا برای بررسی MobX، یک پروژه‌ی جدید React را ایجاد می‌کنیم:
    > create-react-app state-management-with-mobx-part1
    > cd state-management-with-mobx-part1
    > npm start
    در ادامه کتابخانه‌ی mobx را نیز نصب می‌کنیم. برای این منظور پس از باز کردن پوشه‌ی اصلی برنامه توسط VSCode، دکمه‌های ctrl+` را فشرده (ctrl+back-tick) و دستور زیر را در ترمینال ظاهر شده وارد کنید:
    > npm install --save mobx
    البته برای کار با MobX، الزاما نیازی به طی مراحل فوق نیست؛ ولی چون این قالب، یک محیط آماده‌ی کار با ES6 را فراهم می‌کند، به سادگی می‌توان فایل index.js آن‌را خالی کرد و سپس شروع به کدنویسی و آزمایش MobX نمود.


    مثالی از MobX، مستقل از React

    در اینجا نیز همانند روشی که در بررسی Redux در پیش گرفتیم، ابتدا MobX را به صورت کاملا مستقل از React، با یک مثال بررسی می‌کنیم و سپس در قسمت‌های بعد آن‌را به React متصل می‌کنیم. برای این منظور ابتدا فایل src\index.js را به صورت زیر تغییر می‌دهیم:
    import { autorun, observable } from "mobx";
    
    import React from "react";
    import ReactDOM from "react-dom";
    
    ReactDOM.render(
      <div>
        <input type="text" id="text-input" />
        <div id="text-display"></div>
        <div id="text-display-uppercase"></div>
      </div>,
      document.getElementById("root")
    );
    
    const input = document.getElementById("text-input");
    const textDisplay = document.getElementById("text-display");
    const loudDisplay = document.getElementById("text-display-uppercase");
    
    console.log({ observable, autorun, input, textDisplay, loudDisplay });
    در اینجا یک text-box، به همراه دو div، در صفحه رندر خواهند شد که قرار است با ورود اطلاعاتی در text-box، یکی از آن‌ها (text-display) این اطلاعات را به صورت معمولی و دیگری (text-display-uppercase) آن‌را به صورت uppercase نمایش دهد. روش کار انجام شده هم مستقل از React است و به صورت مستقیم، با استفاده از DOM API و document.getElementById عمل شده‌است. همچنین در ابتدای این فایل، دو import را از کتابخانه‌ی mobx مشاهده می‌کنید.
    - با استفاده از observable می‌خواهیم تغییرات یک شیء جاوا اسکریپتی را تحت نظر قرار داده و هر زمانیکه تغییری در شیء رخ داد، از آن مطلع شویم.
    برای مثال شیء ساده‌ی جاوا اسکریپتی زیر را در نظر بگیرید:
    {
      value: "Hello world!",
      get uppercase() {
        return this.value.toUpperCase();
      }
    }
    این شیء دارای دو خاصیت است که یکی معمولی و دیگری به صورت یک خاصیت محاسباتی، تعریف شده‌است. مشکلی که با این شیء وجود دارد این است که اگر مقدار خاصیت value آن تغییر کند، از آن مطلع نخواهیم شد تا پس از آن برای مثال در مورد رندر مجدد DOM، تصمیم گیری شود. چون از دیدگاه React، مقدار ارجاع به این شیء با تغییر خواص آن، تغییری نمی‌کند. به همین جهت اگر نحوه‌ی مقایسه، بر اساس مقایسه‌ی ارجاعات به اشیاء باشد (strict === reference check)، چون شیء تغییر یافته نیز به همان شیء اصلی اشاره می‌کند، بنابراین دارای ارجاع یکسانی خواهند بود و سبب رندر مجدد DOM نمی‌شوند.
    به همین جهت اینبار شیء فوق را توسط یک observable ارائه می‌دهیم، تا بتوانیم به تغییرات خواص آن گوش فرا دهیم:
    const text = observable({
      value: "Hello world!",
      get uppercase() {
        return this.value.toUpperCase();
      }
    });
    در ادامه یک EventListener را به text-box تعریف شده اضافه کرده و در رخ‌داد keyup آن، سبب تغییر خاصیت value شیء text فوق، بر اساس مقدار تایپ شده می‌شویم:
    input.addEventListener("keyup", event => {
       text.value = event.target.value;
    });
    اکنون چون شیء text، یک observable است، هر زمانیکه که خاصیتی از آن تغییر می‌کند، می‌خواهیم بر اساس آن، DOM را به صورت دستی به روز رسانی کنیم. برای اینکار نیاز به متد autorun دریافتی از mobx خواهیم داشت:
    autorun(() => {
       textDisplay.textContent = text.value;
       loudDisplay.textContent = text.uppercase;
    });
    هر زمانیکه شیء observable ای که داخل متد autorun تحت نظر قرار گرفته شده، تغییر کند، سبب اجرای callback method ارسالی به آن خواهد شد. برای مثال در اینجا چون text.value را به event.target.value متصل کرده‌ایم، هربار که کلیدی فشرده می‌شود، سبب بروز تغییری در خاصیت value خواهد شد. در نتیجه‌ی آن، autorun اجرا شده و مقادیر درج شده‌ی در divهای صفحه را بر اساس خواص value و uppercase شیء text، تغییر می‌دهد:

    برای آزمایش آن، برنامه را اجرا کرده و متنی را داخل textbox وارد کنید:


    نکته‌ی جالب اینجا است که هرچند فقط خاصیت value را تغییر داده‌ایم (تغییر مستقیم خواص یک شیء؛ بدون نیاز به ساخت یک clone از آن)، اما خاصیت محاسباتی uppercase نیز به روز رسانی شده‌است.

    زمانیکه mobx را به یک برنامه‌ی React متصل می‌کنیم، قسمت autorun، از دید ما مخفی خواهد بود. در این حالت فقط یک شیء معمولی جاوا اسکریپتی را مستقیما تغییر می‌دهیم و ... در نتیجه‌ی آن رندر مجدد UI صورت خواهد گرفت.


    یک observable چگونه کار می‌کند؟

    در اینجا یک شبه‌کد را که بیانگر نحوه‌ی عملکرد یک observable است، مشاهده می‌کنید:
    const onChange = (oldValue, newValue) => {
      // Tell MobX that this value has changed.
    }
    
    const observable = (value) => {
      return {
        get() { return value; },
        set(newValue) {
          onChange(this.get(), newValue);
          value = newValue;
        }
      }
    }
    یک observable هنگامیکه شی‌ءای را در بر می‌گیرد. هر زمانیکه مقدار جدیدی را به خاصیتی از آن نسبت دادیم، سبب فراخوانی متد onChange شده و به این صورت است که کتابخانه‌ی MobX متوجه تغییرات می‌گردد و بر اساس آن امکان ردیابی تغییرات را میسر می‌کند.


    کدهای کامل این قسمت را می‌توانید از اینجا دریافت کنید: state-management-with-mobx-part1.zip
    مطالب
    ایجاد قسمت‌های Toggle در سایت با jQuery
    البته قبلش بگم که عنوان بهتری به ذهنم نرسید.
    بسیاری از مواقع پیش می‌آید که در سایت خود بخواهیم کادری داشته باشیم که با کلیک بروی آن ظاهر و با کلیک دوباره بروی آن محو شود. مانند تصویر زیر

    سپس با کلیک بروی قسمت مشخص شده از تصویر بالا تصویر مانند زیر ظاهر شود.

    در این نوشته قصد داریم کادری به این صورت حالا به هر منظوری طراحی نماییم.

    برای کار سه قسمت کد داریم:

    1. کدهای طراحی قسمت مورد نظر در صفحه وب
    2. نوشتن کدهای CSS مربوطه
    3. نوشتن کدهای jQuery

    در مرحله اول ابتدا صفحه وب خود را به نحو زیر ایجاد می‌نماییم.

    <!DOCTYPE html>
    <html xmlns="http://www.w3.org/1999/xhtml">
    <head>
        <title>کادر لغزان با jQuery</title>
        <script src="Scripts/jquery-1.7.1.min.js"></script>
        <link href="CSS/site.css" rel="stylesheet" />
    </head>
    <body>
        <div id="loginPanel">
            <div style="height: auto;" id="login">
                <div>
                    <div>
                        <br />
                        محتویات دلخواه خود را در این قسمت قرار دهید
                    </div>
                </div>
                <div><a href="#" id="closeLogin"></a></div>
            </div>
            <div id="container">
                <div id="top">
                    <!-- login -->
                    <ul>
                        <li>&nbsp;</li>
                        <li><a id="toggleLogin" href="#">پانل باز شو</a></li>
                    </ul>
                    <!-- / login -->
                </div>
                <!-- / top -->
    
            </div>
        </div>
        <div id="main">
            محتویات سایت در این قسمت قرار می‌گیرد
        </div>
        </body>
    </html>
    در صفحه ایجاد شده قسمتی را برای نگهداری پانل مورد نظر قرار دادیم و در div با نام loginContent مواردی را که می‌خواهیم در پانل مربوطه نمایش داده شود، قرار می‌دهیم،  <"div id="loginPanel> نگهدارنده کل قسمت مربوطه (کادر لغزان می‌باشد)، و قسمت <"div id="container> قسمتی است که دکمه یا عنوان مورد نظر برای باز شدن یا بستن کادر استفاده می‌شود.
    در مرحله دوم کدهای CSS بخش‌های مورد نظر (جهت رنگ و تصاویر و شکل و شمایل کادر مورد نظر) را مانند زیر ایجاد می‌کنیم.
    body {
         margin:0; 
         padding:0; 
         width:100%; 
         background: #e9e9e9 url(images/header_bg.gif) top repeat-x;
         direction: rtl;
    }
    html {
         padding:0; 
         margin:0;
    }
    
    #main {margin-top: 100px;}
    
    #loginPanel {
        margin: 0px; 
        position: absolute; 
        overflow: hidden; 
        height: auto;
        z-index: 3000;
        width: 100%;
        top: 0px;
        color: #fff;
    }
    #top {
        background: url(images/login_top.jpg) repeat-x 0 0;
        height: 38px;
        position: relative;
    }
    #top ul.login {
        display: block;
        position: relative;
        float: right;
        clear: right;
        height: 38px;
        width: auto;
        margin: 0;
        right: 150px;
        color: white;
        text-align: center;
        background: url(images/login_r.png) no-repeat right 0;
        padding-right: 45px;
    }
    #top ul.login li.left {
        background: url(images/login_l.png) no-repeat left 0;
        height: 38px;
        width: 45px;
        padding: 0;
        margin: 0;
        display: block;
        float: left;
    }
    #top ul.login li {
        text-align: left;
        padding: 0 6px;
        display: block;
        float: left;
        height: 38px;
        background: url(images/login_m.jpg) repeat-x 0 0;
    }
    #top ul.login li a {
        color: #fff;
        text-decoration: none;
    }
    #top ul.login li a:hover {
        color: #ff0000;
        text-decoration: none;
    }
    #login {
        width: 100%;
        color: white;
        background: #1E1E1E;
        overflow: hidden;
        position: relative;
        z-index: 3;
        height: 0px;
    }
    #login a {
        text-decoration: none;
        color: #fff;
    }
    #login a:hover {
        color: white;
        text-decoration: none;
    }
    #login .loginContent {
        width: 900px;
        height: 80px;
        margin: 0 auto;
        padding-top: 25px;
        text-align: right;
    }
    #login .loginClose {
        display: block;
        position: absolute;
        right: 15px;
        top: 10px;
        width: 70px;
        text-align: left;
    }
    #login .loginClose a {
        display: block;
        width: 100%;
        height: 20px;
        background: url(images/button_close.jpg) no-repeat right 0;
        padding-right: 10px;
        border: none;
        color: white;
    }
    #login .loginClose a:hover {
        background: url(images/button_close.jpg) no-repeat right -20px;
    }
    .cen { text-align: center;}
    .w_100p{ width: 100%;}
    خوب تا اینجای کار فقط کادر با قالب مورد نظر ایجاد شد، برای اینکه عمل مورد نظر انجام شود با استفاده از تکنیک‌های jQuery به صورت زیر کار را به پایان می‌رسانیم. در انتهای صفحه اسکریپت زیر را قبل از قسمت <body/> می‌نویسیم.
     <script type="text/javascript">
            $(document).ready(function () {
                $("#login").hide(0);
                $("#toggleLogin").click(function () {
                    $("#login").slideToggle("slow");
                });
                $("#closeLogin").click(function () {
                    $("#login").slideUp("slow");
                });
            });
        </script>
    با نوشتن این اسکریپت بعد از لود صفحه مورد نظر ابتدا کادر ما مخفی می‌شود، سپس برای دکمه (یا هر المانی که می‌خواهیم با کلیک روی آن کادر بسته یا باز شود) کد کلیک می‌نویسیم که با کلیک بروی آن عمل اسلاید (باز یا بسته شدن) رخ دهد. در نهایت در رویداد کلیک لینک close تعیین می‌کنیم که کادر به آرامی  بسته شود.
    مثال کامل از ^ قابل دانلود است
    لینک‌های کمکی جهت آشنایی بیشتر با توابع استفاده شده:




    مطالب
    آشنایی با CLR: قسمت شانزدهم
    در مقاله قبلی بحث Assembly Linker را باز کردیم و یاد گرفتیم که چگونه می‌توان با استفاده از آن ماژول‌های مختلف را به یک اسمبلی اضافه کرد. در این قسمت از این سلسله مقالات  قصد داریم فایل‌های منابع (Resource) مانند مواد چندرسانه‌ای، چند زبانه و .. را به آن اضافه کنیم. یک اسمبلی حتی میتواند تنها Resource باشد.

    برای اضافه کردن یک فایل به عنوان منبع، از سوئیچ [embed[resource استفاده می‌شود. این سوئیچ محتوای هر نوع فایلی را که به آن پاس شود، به فایل PE اجرایی انتقال داده و جدول ManifestResourceDef را به روز می‌کند تا سیستم از وجود آن آگاه شود.
    سوئیچ [link[Resource هم برای الحاق کردن یک فایل به اسمبلی به کار می‌رود و دو جدول ManifestResourceDef و  FileDef را جهت معرفی منبع جدید و شناسایی فایل اسمبلی که حاوی این منبع است، به روز می‌کند. در این حالت فایل منبع embed نشده و باید در کنار پروژه منتشر شود.
    csc هم قابلیت‌های مشابهی را با استفاده از سوئیچ‌های resource/ و link/ دارد و به روز رسانی و دیگر اطلاعات تکمیلی آن مشابه موارد بالاست.

    شما حتی می‌توانید منابع یک فایل win32 را خیلی راحت و آسان به اسمبلی معرفی کنید. شما به آسانی می‌توانید مسیر یک فایل res. را با استفاده از سوئیچ win32res/ در al یا csc مشخص کنید. یا برای embed کردن آیکن یک برنامه win32 از سوئیچ win32icon/ مسیر یک فایل ICO را مشخص کنید. در ویژوال استودیو این‌کار به صورت ویژوالی در پنجره تنظمیات پروژه و برگه‌ی Application امکان پذیر است. دلیل اصلی که آیکن برنامه‌ها به صورت embed ذخیره می‌شوند این است که این آیکن برای فایل اجرایی یک برنامه‌ی مدیریت شده هم به کار می‌رود.

    فایل‌های اسمبلی Win32 شامل یک فایل مانیفست اطلاعاتی هستند که به طور خودکار توسط کمپایلر سی شارپ تولید می‌گردند. با استفاده از سوئیچ nowin32manifest/ میتوان از ایجاد این نوع فایل جلوگیری کرد. این اطلاعات به طور پیش فرض شبیه زیر است:
    <?xml version="1.0" encoding="UTF­8" standalone="yes"?>
    <assembly xmlns="urn:schemas­microsoft­com:asm.v1" manifestVersion="1.0">
    <assemblyIdentity version="1.0.0.0" name="MyApplication.app" />
    <trustInfo xmlns="urn:schemas­microsoft­com:asm.v2">
    <security>
    <requestedPrivileges xmlns="urn:schemas­microsoft­com:asm.v3">
    <requestedExecutionLevel level="asInvoker" uiAccess="false"/>
    </requestedPrivileges>
    </security>
    </trustInfo>
    </assembly>
    موقعیکه AL یا CSC یک فایل نهایی PE را ایجاد می‌کند، یک منبع نسخه بندی شده با استاندارد win32 نیز به آن Embed می‌شود که با راست کلیک روی فایل و انتخاب گزینه‌ی Properties و برگه‌ی Details این اطلاعات نمایش می‌یابد. در کدنویسی این اپلیکیشن هم می‌توانید از طریق فضای نام system.Diagnostics.FileVersionInfo و متد ایستای آن GetVersionInfo که پارامتر ورودی آن مسیر فایل اسمبلی است هم به این اطلاعات، در حین اجرای برنامه دست پیدا کنید.

    موقعیکه شما یک اسمبلی می‌سازید باید فیلدهای منبع نسخه بندی را هم ذکر کنید. اینکار توسط خصوصیت‌ها (Attributes) در سطح کد انجام می‌گیرد. این خصوصیات شامل موارد زیر هستند که در فضای نام Reflection قرار گرفته‌اند.
    using System.Reflection;
    
    // FileDescription version information:
    [assembly: AssemblyTitle("MultiFileLibrary.dll")]
    
    // Comments version information:
    [assembly: AssemblyDescription("This assembly contains MultiFileLibrary's types")]
    
    // CompanyName version information:
    [assembly: AssemblyCompany("Wintellect")]
    
    // ProductName version information:
    [assembly: AssemblyProduct("Wintellect (R) MultiFileLibrary's Type Library")]
    
    // LegalCopyright version information:
    [assembly: AssemblyCopyright("Copyright (c) Wintellect 2013")]
    
    // LegalTrademarks version information:
    [assembly:AssemblyTrademark("MultiFileLibrary is a registered trademark of Wintellect")]
    
    // AssemblyVersion version information:
    [assembly: AssemblyVersion("3.0.0.0")]
    
    // FILEVERSION/FileVersion version information:
    [assembly: AssemblyFileVersion("1.0.0.0")]
    
    // PRODUCTVERSION/ProductVersion version information:
    [assembly: AssemblyInformationalVersion("2.0.0.0")]
    
    // Set the Language field (discussed later in the "Culture" section)
    [assembly:AssemblyCulture("")]

    جدول زیر اطلاعاتی در مورد سوئیچ‌های AL جهت مقداردهی این فیلدهای نسخه بندی دارد (کامپایلر سی شارپ این سوئیچ‌ها را ندارد و بهتر است از طریق همان خصوصیات در کدها اقدام کنید). بعضی از اطلاعات زیر با استفاده از سوئیچ‌ها قابل تغییر نیستند؛ چرا که این مقادیر یا ثابت هستند یا اینکه طبق شرایطی از بین چند مقدار ثابت، یکی از آن‌ها انتخاب می‌شود.

    نسخه منبع  سوئیچ AL.exe  توصیف خصوصیت یا سوئیچ مربوطه
     FILEVERSION  fileversion/  System.Reflection.AssemblyFileVersionAttribute.
     PRODUCTVERSION  productversion/  System.Reflection.
    AssemblyInformationalVersionAttribute
     FILEFLAGSMASK  -  Always set to VS_FFI_FILEFLAGSMASK (defined in WinVer.h as
    0x0000003F).
     FILEFLAGS  - همیشه صفر است
     FILEOS  -  در حال حاضر همیشه VOS__WINDOWS32
    است
    FILETYPE
    target/
    Set to VFT_APP if /target:exe or /target:winexe is specified;
    set to VFT_DLL if /target:library is specified.

     FILESUBTYPE -

     Always set to VFT2_UNKNOWN. (This field has no meaning for VFT_APP
    and VFT_DLL.)
     AssemblyVersion version/  System.Reflection.AssemblyVersionAttribute
     Comments  description/  System.Reflection.AssemblyDescriptionAttribute
     CompanyName  company/  System.Reflection.AssemblyCompanyAttribute
     FileDescription title/  System.Reflection.AssemblyTitleAttribute
     FileVersion  version/  System.Reflection.AssemblyFileVersionAttribute
     InternalName  out/  ذکر نام فایل خروجی بدون پسوند.
     LegalCopyright  copyright/  System.Reflection.AssemblyCopyrightAttribute
     LegalTrademarks  trademark/  System.Reflection.AssemblyTrademarkAttribute
     OriginalFilename  out  ذکر نام فایل خروجی بدون پسوند.
     PrivateBuild  -  همیشه خالی است.
     ProductName  product  System.Reflection.AssemblyProductAttribute
     ProductVersion  productversion  System.Reflection.
    AssemblyInformationalVersionAttribute
     SpecialBuild  -  همیشه خالی است.
    موقعیکه شما یک پروژه‌ی سی شارپ را ایجاد می‌کنید، فایلی به نام AssebmlyInfo.cs در دایرکتوری Properties پروژه ایجاد می‌شود. این فایل شامل تمامی خصوصیت‌های نسخه بندی که در بالا ذکر شد، به‌علاوه یک سری خصوصیات دیگری که در آینده توضیح خواهیم داد، می‌باشد.
    شما برای ویرایش این فایل می‌توانید به راحتی آن را باز کرده و اطلاعات داخل آن را تغییر دهید. ویژوال استودیو نیز برای ویرایش این فایل، امکانات GUI را نیز فراهم کرده است. برای استفاده از این امکان، پنجره‌ی properties را در سطح Solution باز کرده و در تب Application روی Assembly Information کلیک کنید.