مطالب
#Defensive Code in C - قسمت اول

Defensive Coding به معنی است که شما با انجام یکسری کار‌ها و در نظر گرفتن یکسری زیر ساخت‌ها در توسعه‌ی نرم افزار خود، به اهداف ذیل دست پیدا کنید:

1. Quality (کیفیت)

2. Comprehensible (جامعیت)

3. Predictable  (قابلیت پیش بینی)

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

1. Clean Code

یکی از اهداف Defensive Coding که در ابتدای مقاله بحث شد جامعیت یا Comprehension بود. برای رسید به این هدف از مفهومی به نام Clean Code  استفاده می‌شود. Clean Code علاوه بر این مسئله، در پی ساده کردن ساختار بندی پشتیبانی و کاهش باگ‌های نرم افزار نیز هست. ویژگی‌های Clean Code در بالا با  توجه به شکل ذیل تشریح می‌شوند: 

· Easy to read

یک کد Clean  قابلیت خوانایی بالایی دارد. بسیاری از برنامه نویسان در سطوح مختلف با اهمیت این مسئله در توسعه نرم افزار آشنایی دارند. ولی بسیاری از همین برنامه نویسان این اصول را رعایت نمی‌کنند و سعی نمی‌کنند با اصول پیاده سازی آن در نرم افزارآشنا شوند.

اگر قابلیت خوانایی یک کد بالا باشد:

§ شما می‌توانید Pattern ‌های موجود در کد خود را که می‌توانید به عنوان نامزدهایی جهت Refactoring  هستند، تشخیص دهید.

§ برنامه نویسان دیگر به راحتی قصد و اهداف ( intent ) شما را از نوشتن یک کد خاص درک خواهند کرد و در طول زمان با خطا‌های زیادی روبرو نمی‌شوند.

§ توسعه‌ی راحت‌تر و در شرایط وجود فشار، ایجاد سریع یک قابلیت جدید در نرم افزار.

· Clear intent

یک کد Clear دارای اهداف روشن و قابل فهمی می‌باشد.

· Simple

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

· Minimal

کد باید به گونه‌ای باشد که تنها یک چیز را انجام داده و آن را به درستی انجام دهد. همچنین وابستگی بین اجزای کد باید در کمترین حد ممکن باشند.

· Thoughtful

یک کد Clean  کدی است که ساختار آن متفکرانه طراحی شده باشد. از نحوه‌ی طراحی یک کلاس گرفته تا layering و Tiering پروژه باید کاملا هوشمندانه و با توجه به پارامتر‌های موجود باشند. همچنین خطا‌های خطرناک و استثناء‌ها باید کاملا هندل شوند. 

همه‌ی ما با دیدن کد بالا سریعا مفهوم اسپاگتی کد به ذهنمان خطور می‌کند. تغییر، توسعه و پشتیبانی نرم افزارهایی که کد آنها به این صورت نوشته شده است، بسیار سخت و پر هزینه می‌باشد. در این حالت تغییر هر یک از اجزاء ممکن است بر سایر قسمت‌های دیگر تاثیرات مختلفی داشته باشد. راه کاری که در این حالت ارائه می‌شود، Refactoring می‌باشد. در این روش کد را به کلاس‌ها و متدهایی بر حسب عملکرد تقسیم خواهیم کرد. در نهایت کد تولید شده دارای کمترین تاثیر بر سایر قسمت‌ها خواهد بود. توجه داشته باشید که با انجام این کار، قدمی به سوی SOC یا Separation Of Concern برداشته‌اید.

1. Testable Code & Unit Test

یکی دیگر از اهداف Defensive Coding افزایش کیفیت یا Quality می‌باشد که برای رسیدن به این هدف از مفهوم Testable Code & Unit Test استفاده می‌شود. بسیاری از ویژگی‌های Testable Code و Clean Code با هم مشابه می‌باشند. برای مثال Refactor کردن هر متد به متد‌های کوچکتر، تست آن را ساده‌تر خواهند کرد. در نتیجه نوشتن کد‌های Testable ، با نوشتن کد‌های clean شروع می‌شود.

در این قسمت اشاره‌ای به Unit Test شده است؛ اما این مفهوم می‌تواند به یک مفهوم گسترده‌تر به نام  Automated Code testing، تعمیم داده شود. به این دلیل که تست فقط به Unit Testing محدود نمی‌شود و می‌تواند شامل سایر انواع تست‌ها مانند  integration test نیز باشد.

برای مثال شکل ذیل را در نظر بگیرید. در انتهای این سناریو یک Page جدید اضافه شده است. خوب؛ برای تست کد اضافه شده، مجبورید برنامه را اجرا کنید، login کنید، داده‌های مورد نظر را در فرم وارد کرده و در نهایت شرایط لازم را جهت تست، فراهم کنید تا بتوانید کد جدید را تست کنید. در این بین با خطایی مواجه می‌شوید. پس برنامه را متوقف می‌کنید و تغییرات لازم را اعمال می‌کنید. حال فرض کنید این خطا به این زودی‌ها رفع نشود. در این حالت باید فرآیند بالا را چندین و چند بار انجام دهید. نتیجه اینکه این روش بسیار زمان بر و پر هزینه خواهد بود. البته میزان هزینه و زمان رابطه‌ی نزدیکی با وسعت تغییرات دارند. برای رفع مسائلی از این دست مایکروسافت زیرساختی به نام MS Test ارائه داده است که می‌توان با آن سناریوهای تست متفاوتی را پیاده سازی و اجرا نمود. متاسفانه این مسئله در بسیار از جوامع توسعه نرم افزار رعایت نمی‌شود و در بسیاری از این جوامع، نیروی انسانی، این فرآیند و فرآیندهایی از این دست را انجام می‌دهند. درحالیکه چنین فرآیندهایی به راحتی توسط ابزارهای ارائه شده‌ی توسط شرکت‌های مختلف قابل مدیریت است.

 


1. Predictability

یکی دیگر از اهداف Defensive Coding، قابلیت پیش بینی یا Predictability می‌باشد. فرآیند تشخیص و پیش بینی خطا‌ها را Predictability می‌گویند. با درنظر گرفتن امکان وقوع خطاهای مختلف و تصمیم گرفتن در مورد اینکه در هنگام رخ دادن این خطا باید چه کاری صورت بگیرد، می‌توان در رسیدن به این هدف قدم بزرگی برداشت. 

برای رسیدن به این هدف باید اصل Trust but Verify را دنبال کنیم. برای مثال این اصل به ما می‌گوید که در هنگام تعریف متد‌های public باید یکسری موارد را در نظر بگیریم. یک متد باید از یکسری قرارداد‌ها پیروی کند. یک متد قرارداد می‌کند که یکسری پارامتر‌ها را با یک data type خاص به عنوان ورودی دریافت کند. قرارداد می‌کند که یک مقدار خاص با یک data type خاص را به عنوان نوع بازگشتی بازگرداند یا اینکه هیچ مقداری را باز نگرداند و در نهایت یک متد متعهد می‌شود که یکسری Exception ‌تعریف شده و پیش بینی شده را صادر کند. اما برای اینکه مطمئن شویم یک application واقعا قابل پیش بینی است و این اصل را به درستی پیاده سازی کرده است، اعتماد می‌کنیم اما Verify را هم انجام می‌دهیم. برای verify کردن باید پارامترها، دیتا‌های متغیر، مقادیر بازگشتی و استثناء‌ها به گونه‌ای بررسی شوند که مطمئن شویم انتظارت ما را برآورده کرده‌اند. 

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


مطالب
آشنایی با CLR: قسمت چهاردهم
در ادامه قسمت قبلی روش‌های زیادی جهت اضافه شدن یک ماژول به یک اسمبلی وجود دارند. اگر شما از کامپایلر سی‌شارپ برای ساخت یک فایل PE با جدول مانیفست استفاده می‌کنید، می‌توانید از سوئیچ AddModule/ استفاده کنید. برای اینکه بدانیم چگونه می‌توان یک اسمبلی چند فایله ساخت بیاید فرض کنیم که دو فایل سورس کد با مشخصات زیر داریم:
RUT.cs: این سورس شامل کدهایی است که به ندرت در برنامه استفاده می‌شود.
FUT.cs: این سورس شامل کدهایی است که به طور مکرر مورد استفاده قرار می‌گیرد.

ابتدا به صورت زیر کد سورسی را که به ندرت استفاده می‌شود، به عنوان یک ماژول جداگانه کامپایل می‌کنم:
csc /t:module RUT.cs
اجرای این خط سبب ایجاد یک فایل به نام RUT.netmodule می‌گردد که یک DLL استاندارد است؛ ولی CLR به تنهایی توانایی بارگیری آن را ندارد. دفعه‌ی بعد سورس کدی را که مکرر استفاده می‌شود، به صورت یک ماژول کامپایل می‌کنیم و از آنجائیکه این ماژول استفاده‌ی زیادی دارد، آن را نگهدارنده‌ی جدول مانیفست معرفی می‌کنیم و به این دلیل که این ماژول نماینده‌ی کل اسمبلی است، نام خروجی آن را به جای FUT.dll به MultiFileLibrary.dll تغییر می‌دهیم:
csc /out:MultiFileLibrary.dll /t:library /addmodule:RUT.netmodule FUT.cs
خط بالا به علت سوئیچ t:library\ فایل MultiFileLibrary.dll را ایجاد می‌کند. این فایل شامل جدول متادیتای مانیفست می‌شود و سوئیچ به آن می‌گوید که باید ماژول RUT.netmodule را جزئی از اسمبلی بداند. این سوئیچ به کامپایلر اعلام می‌کند که ارجاع این فایل در جدول FileDef  و ExportedTypesDef ثبت شود.
بعد از اتمام عملیات کامپایل، مطابق شکل زیر دو فایل ایجاد می‌شود که فایل سمت راست شامل جدول مانیفست است. فایل RUT.netmodule شامل کد IL و جداول متادیتاهای مربوط به خواص و رویدادها و مواردی از این قبیل است که در این ماژول یافت می‌شود. فایل بعدی MultiFileLibrary.dll هست که شامل کد IL کد FUT.CS می‌شوذ بعلاوه جداول متادیتا مثل ماژول قبلی و جدول متادیتای مانیفست که باعث می‌شود به عنوان یک اسمبلی شناخته شود.



البته توجه داشته باشید که جدول مانیفست ارجاعی به نوع‌های عمومی استخراج شده داخل فایل خودش ندارد، زیرا که در جداول اختصاصی خودش موجود است و در ذخیره سازی صرفه جویی می‌گردد.
بعد از اینکه MultiFileLibrary.dll ساخته شد، به منظور آزمایش کردن جداول متادیتا می‌توانید از ابزار ILDasm.exe استفاده کنید تا ارجاع به فایل RUT.netmodule به شما ثابت شود. آنچه در زیر می‌بینید نمایی از جداول FileDef و ExportedTypesDef است:
File #1 (26000001)
­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­
Token: 0x26000001
Name : RUT.netmodule
HashValue Blob : e6 e6 df 62 2c a1 2c 59 97 65 0f 21 44 10 15 96 f2 7e db c2
Flags : [ContainsMetaData] (00000000)


ExportedType #1 (27000001)
­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­­
Token: 0x27000001
Name: ARarelyUsedType
Implementation token: 0x26000001
TypeDef token: 0x02000002
Flags : [Public] [AutoLayout] [Class] [Sealed] [AnsiClass]
[BeforeFieldInit](00100101)
 
همانطور که در بالا می‌بینید فایل RUT.netmodule با شناسه‌ی (توکن) 0x26000001 به عنوان بخشی از اسمبلی شناخته می‌شود و به نوع کد IL آن اشاره می‌کند.

قابل توجه افراد کنجکاو: توکن‌های جداول متا، مقادیر 4 بایتی است که بایت پر ارزش آن اشاره می‌کند که برای یافتن آن باید به چه جدولی ارجاع کرد. مقادیر زیر این نکته را روشن می‌کند که هر کد ابتدایی به چه جدولی اشاره می‌کند:
 0x01
 TypeRef
 0x02
 TypeDef
 0x23
 AssemblyRef
 0x26
 File
file definition

 0x27
 ExportedType
برای دیدن لیست کاملی از این کدها فایل Corhdr.h را که به همراه فریم ورک دات نت نصب می‌شود، مطالعه فرمایید. سه بایت باقیمانده هم بر اساس جدولی که به آن ارجاع شده است مشخص می‌گردد؛ مثلا در مثال بالا کد 0x26000001  به اولین سطر جدول File اشاره می‌کند. برای اکثر جدول‌ها شماره گذاری سطرها از عدد 1 آغاز می‌شود نه صفر یا برای برای جداول TypeDef عموما از عدد 2 آغاز می‌شود. 

برای اجرای اسمبلی، کامپایلر نیاز دارد که همه‌ی فایل‌های اسمبلی، نصب شده و قابل دسترس باشند و در صورتیکه شما فایل RUT.netmodule را حذف کنید کامپایلر سی شارپ خطای زیر را صادر می‌کند:
fatal error CS0009: Metadata file 'C:\ MultiFileLibrary.dll' could not be opened—'Error importing module 'RUT.netmodule' of assembly 'C:\ MultiFileLibrary.dll'—The system cannot find the file specified'

و این خطا بدین معنی است که برای ساخت اسمبلی باید تمامی فایل‌ها حاضر و مهیا باشند. هر کد کلاینتی که اجرا می‌شود آن متد را صدا می‌زنند. موقعی که یک متد برای اولین بار فراخوانی می‌شود، CLR عملیات شناسایی جهت شناسایی ارجاعات آن در پارامترها، نوع خروجی متد و متغیرهای محلی آن اجرا می‌کند. سپس تلاش می‌کند تا فایل اسمبلی ارجاع شده را که شامل مانیفست هست، بار کند. اگر نوعی که لازم داریم در همین فایل متد وجود داشته باشد، اجرای عملیات را به سمت آن آغاز می‌کند ولی اگر جدول مانیفست ارجاع را به فایل دیگری بدهد، آن فایل در حافظه بار شده و سپس آن نوع را در دسترس قرار می‌دهد. 
خطوط بالا این نکته را روشن می‌کند که فایل‌های اسمبلی را تنها موقعی در حافظه بار میکند که ارجاعی از نوع موجود در آن صدا زده شده باشد؛ یعنی اینکه در زمان اجرای برنامه، لازم نیست که همه‌ی فایل‌ها حاضر و مهیا باشند.
مطالب
OpenCVSharp #4
کار با فیلترها در OpenCVSharp

فرض کنید قصد داریم یک چنین مثال زبان C را که در مورد کار با فیلترها در OpenCV است، به نمونه‌ی دات نتی آن تبدیل کنیم:
        #include <cv.h>
        #include <highgui.h>
        #include <stdio.h>
 
        int main (int argc, char **argv)
        {
          IplImage *src_img = 0, *dst_img;
          float data[] = { 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
            1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1
          };
          CvMat kernel = cvMat (1, 21, CV_32F, data);
 
          if (argc >= 2)
            src_img = cvLoadImage (argv[1], CV_LOAD_IMAGE_ANYDEPTH | CV_LOAD_IMAGE_ANYCOLOR);
          if (src_img == 0)
            exit (-1);
 
          dst_img = cvCreateImage (cvGetSize (src_img), src_img->depth, src_img->nChannels);
 
          cvNormalize (&kernel, &kernel, 1.0, 0, CV_L1);
          cvFilter2D (src_img, dst_img, &kernel, cvPoint (0, 0));
 
          cvNamedWindow ("Filter2D", CV_WINDOW_AUTOSIZE);
          cvShowImage ("Filter2D", dst_img);
          cvWaitKey (0);
 
          cvDestroyWindow ("Filter2D");
          cvReleaseImage (&src_img);
          cvReleaseImage (&dst_img);
 
          return 0;
        }
معادل OpenCVSharp آن به صورت ذیل خواهد بود:
using (var src = new IplImage(@"..\..\Images\Penguin.Png", LoadMode.AnyDepth | LoadMode.AnyColor))
using (var dst = new IplImage(src.Size, src.Depth, src.NChannels))
{
    float[] data = { 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 };
    var kernel = new CvMat(rows: 1, cols: 21, type: MatrixType.F32C1, elements: data);
 
    Cv.Normalize(src: kernel, dst: kernel, a: 1.0, b: 0, normType: NormType.L1);
    Cv.Filter2D(src, dst, kernel, anchor: new CvPoint(0, 0));
 
    using (new CvWindow("src", image: src))
    using (new CvWindow("dst", image: dst))
    {
        Cv.WaitKey(0);
    }
}
با این خروجی:


در قسمت‌های قبلی در مورد بارگذاری تصاویر، تهیه‌ی یک Clone از آن و همچنین ساخت یک پنجره به روش‌های مختلف و رها سازی خودکار منابع مرتبط، بیشتر بحث شد. در اینجا تصویر اصلی با همان عمق و وضوح تغییر نیافته‌ی آن بارگذاری می‌شود.
کار cvMat، آغاز یک ماتریس OpenCV است. پارامترهای آن، تعداد ردیف‌ها، ستون‌ها، نوع داده‌ی المان‌ها و داده‌های مرتبط را مشخص می‌کنند.
در این مثال آرایه‌ی data، یک فیلتر را تعریف می‌کند که در اینجا، حالت یک بردار را دارد تا یک ماتریس. برای تبدیل آن به ماتریس، از شیء CvMat استفاده خواهد شد که آن‌را تبدیل به ماتریسی با یک ردیف و 21 ستون خواهد کرد.
در اینجا از نام کرنل استفاده شده‌است. کرنل در OpenCV به معنای ماتریسی از داده‌ها با یک نقطه‌ی anchor (لنگر) است. این لنگر به صورت پیش فرض در میانه‌ی ماتریس قرار دارد (نقطه‌ی 1- , 1- ).


مرحله‌ی بعد، نرمال سازی این فیلتر است. تاثیر نرمال سازی اطلاعات را به این نحو می‌توان نمایش داد:
 double sum = 0;
foreach (var item in data)
{
     sum += Math.Abs(item);
}
Console.WriteLine(sum); // => .999999970197678
در اینجا پس از نرمال سازی، جمع عناصر بردار data، تقریبا مساوی 1 خواهد بود و تمام عناصر بردار data، به داده‌هایی بین یک و صفر، نگاشت خواهند شد.
اگر مرحله‌ی نرمال سازی اطلاعات را حذف کنیم، تصویر نهایی حاصل، چنین شکلی را پیدا می‌کند:


زیرا عملیات تغییر اندازه‌ی اطلاعات بردار صورت نگرفته‌است و داده‌های آن مطلوب متد cvFilter2D نیست.
و مرحله‌ی آخر، اجرای این بردار نرمال شده خطی، بر روی تصویر اصلی به کمک متد cvFilter2D است. این متد، تصویر مبدا را پس از تبدیلات ماتریسی، به تصویر مقصد تبدیل می‌کند. فرمول ریاضی اعمال شده‌ی در اینجا برای محاسبه‌ی نقاط تصویر خروجی به صورت زیر است:




فیلترهای توکار OpenCV

علاوه بر امکان طراحی فیلترهای سفارشی خطی مانند مثال فوق، کتابخانه‌ی OpenCV دارای تعدادی فیلتر توکار نیز می‌باشد که نمونه‌ای از آن‌را در مثال ذیل می‌توانید مشاهده کنید:
using (var src = new IplImage(@"..\..\Images\Car.jpg", LoadMode.AnyDepth | LoadMode.AnyColor))
{
    using (var dst = new IplImage(src.Size, src.Depth, src.NChannels))
    {
        using (new CvWindow("src", image: src))
        {
            Cv.Erode(src, dst);
            using (new CvWindow("Erode", image: dst))
            {
                Cv.Dilate(src, dst);
                using (new CvWindow("Dilate", image: dst))
                {
                    Cv.Not(src, dst);
                    using (new CvWindow("Invert", image: dst))
                    {
                        Cv.WaitKey(0);
                    }
                }
            }
        }
    }
}
با این خروجی



کدهای کامل این مثال را از اینجا می‌توانید دریافت کنید.
مطالب
Dependency Injection در Asp.Net WebApi (روش اول)
طی این پست با تزریق وابستگی‌ها در Asp.net MVC آشنا شدید. روش ذکر شده در آن برای کنترلرهای Web Api جوابگو نیست و باید از روش‌های دیگری برای این منظور استفاده نماییم.

نکته 1: برای پیاده سازی این مثال‌ها، Castle Windsor به عنوان IOC Container انتخاب شده است. بدیهی است می‌توانید از Ioc Container مورد نظر خود نیز بهره ببرید.
نکته 2: می‌توانید از مقاله [هاست سرویس‌های Web Api با استفاده از OWIN و TopShelf] جهت هاست سرویس‌های web Api خود استفاده نمایید.

روش اول

اگر قبلا در این زمینه جستجو کرده باشید، به احتمال زیاد با مفهوم IDependencyResolver بیگانه نیستید. درباره استفاده از این روش مقالات متعددی نوشته شده است؛ حتی در مثال‌های موجود در خود سایت MSDN نیز این روش را مرسوم دانسته و آن را به اشتراک می‌گذارند. جهت نمونه می‌توانید این پروژه را دانلود کرده و کد‌های آن را بررسی کنید.
در این روش، قدم اول، ساخت یک کلاس و پیاده سازی اینترفیس IDependencyResolver می‌باشد؛ به صورت زیر:
public class ApiDependencyResolver : IDependencyResolver
    {
        public ApiDependencyResolver(IWindsorContainer container)
        {
            Container = container;
        }

        public IWindsorContainer Container
        {
            get;
            private set;
        }

        public object GetService(Type serviceType)
        {
            try
            {
                return Container.Kernel.HasComponent(serviceType) ? Container.Resolve(serviceType) : null;
            }
            catch (Kernel.ComponentNotFoundException)
            {
                return null;
            }
        }

        public IEnumerable<object> GetServices(Type serviceType)
        {
            try
            {
                return Container.ResolveAll(serviceType).Cast<object>();
            }
            catch (Kernel.ComponentNotFoundException)
            {
                return Enumerable.Empty<object>();
            }
        }
        public IDependencyScope BeginScope()
        {
            return new SharedDependencyResolver(Container);
        }

        public void Dispose()
        {
            Container.Dispose();
        }
    }
اینترفیس IDependencyResolver از اینترفیس دیگری به نام IDependencyScope ارث می‌برد که دارای دو متد اصلی به نام‌های GetService و GetServices است که جهت وهله سازی کنترلرها استفاده می‌شوند. با فراخوانی این متد‌ها، نمونه‌ی ساخته شده توسط Container بازگشت داده خواهد شد.


کاربرد متد BeginScope چیست
؟

کنترلر‌ها به صورت (Per Request) بر اساس هر درخواست وهله سازی خواهند شد. جهت مدیریت چرخه‌ی عمر کنترلرها و منابع در اختیار آن‌ها، از متد BeginScope استفاده می‌شود. به این صورت که نمونه‌ی اصلی DependencyResolver در هنگام شروع برنامه به GlobalConfiguration پروژه Attach خواهد شد. سپس به ازای هر درخواست، جهت وهله سازی Controller‌ها، متد GetService از محدوده داخلی (منظور فراخوانی متد BeginScope است) باعث ایجاد نمونه و بعد از اتمام فرآیند، متد Dispose باعث آزاد سازی منابع موجود خواهد شد.
پیاده سازی متد BeginScope وابسته به IocContainer مورد استفاده شما است. در این جا  کلاس SharedDependencyResolver را به صورت زیر پیاده سازی کردم:
    public class SharedDependencyResolver : IDependencyScope
    {
        public SharedDependencyResolver(IWindsorContainer container)
        {
            Container = container;
            Scope = Container.BeginScope();
        }

        public IWindsorContainer Container
        {
            get;
            private set;
        }

        public IDisposable Scope
        {
            get;
            private set;
        }

        public object GetService(Type serviceType)
        {
            try
            {
                return Container.Kernel.HasComponent(serviceType) ? Container.Resolve(serviceType) : null;
            }
            catch (ComponentNotFoundException)
            {
                return null;
            }
        }

        public IEnumerable<object> GetServices(Type serviceType)
        {
            try
            {
                return Container.ResolveAll(serviceType).Cast<object>();
            }
            catch (ComponentNotFoundException)
            {
                return null;
            }
        }

        public void Dispose()
        {
            Scope.Dispose();
        }
    }
اگر از UnityContainer استفاده می‌کنید کافیست تکه کد زیر را جایگزین کلاس بالا نمایید:
public IDependencyScope BeginScope()
{
    var child = container.CreateChildContainer();
    return new ApiDependencyResolver(child);
}
برای جستجوی خودکار کنترلرها و  رجیستر کردن آن‌ها به برنامه Windsor امکانات جالبی را در اختیار ما قرار می‌دهد. ابتدا یک Installer ایجاد می‌کنیم:
public class KernelInstaller : IWindsorInstaller
    {
        public void Install(IWindsorContainer container, IConfigurationStore store)
        {          
           container.Register(Classes.FromThisAssembly().BasedOn<ApiController>().LifestyleTransient());         
            container.Kernel.Resolver.AddSubResolver(new CollectionResolver(container.Kernel, true));
        }
    }

در پایان در کلاس Startup نیز کافیست مراحل زیر را انجام دهید:
 »ابتدا Installer نوشته شده را به WindsorContainer معرفی نمایید.
»DependencyResolver  نوشته شده را  به HttpConfiguration معرفی کنید.
»عملیات Routing مورد نظر را ایجاد و سپس config مورد نظر را در اختیار appBuilder قرار دهید.
public class Startup
    {
        public void Configuration( IAppBuilder appBuilder )
        {
           var container = new WindsorContainer();
            container.Install(new KernelInstaller());

            var config = new HttpConfiguration
            {
                 DependencyResolver = new ApiDependencyResolver(container)
            };                  

            config.MapHttpAttributeRoutes();

            config.Routes.MapHttpRoute(
                name: "Default" ,
                routeTemplate: "{controller}/{action}/{name}" ,
                defaults: new { name = RouteParameter.Optional }                
            );

            config.EnsureInitialized();          
         
            appBuilder.UseWebApi( config );
        }
    }
نکته: این روش به دلیل استفاده از الگوی ServiceLocator و همچنین نداشتن Context درخواست ها  روشی منسوخ شده می‌باشد که طی این مقاله جناب نصیری به صورت کامل به این مبحث پرداخته اند.

مطالب
قالبی خودکار برای تهیه‌ی بسته‌های نیوگت
روش‌های زیادی برای تهیه‌ی یک بسته‌ی نیوگت وجود دارند، مانند استفاده از برنامه‌ی NuGet Package Explorer و یا تهیه‌ی یک فایل nuspec و تغییر مداوم جزئیات آن، به ازای هر نگارش جدید پروژه. در ادامه قصد داریم روش خودکار سازی این تغییرات را بررسی کنیم.


الف) تهیه فایل nuspec
NuGet قابلیت پذیرش متغیرهای خود تکمیل شونده‌ای را نیز دارد. فایل nuspec یا جزئیات بسته‌ی تولیدی نیوگت، در این حالت یک چنین شکلی را پیدا می‌کند:
<?xml version="1.0"?>
<package >
 <metadata>
  <id>$id$</id>
  <version>$version$</version>
  <title>$title$</title>
  <authors>$author$</authors>
  <owners>$author$</owners>
  <licenseUrl>https://site.com/prj/LICENSE</licenseUrl>
  <projectUrl>https://site.com/prj</projectUrl>
  <requireLicenseAcceptance>false</requireLicenseAcceptance>
  <description>$description$</description>
  <copyright>Copyright 2015 My Name</copyright>
 </metadata>
</package>
برای مثال اگر پروژه‌ی ما TestNuget نام دارد، فایلی به نام TestNuget.nuspec را با محتویات فوق برای آن تهیه خواهیم کرد. همانطور که مشاهده می‌کنید، در این فایل ویژه، هیچکدام از اطلاعات شماره نگارش پروژه، نام نویسنده و غیره، از پیش تعیین نشده‌اند. این اطلاعات، از فایل AssemblyInfo.cs پروژه، به صورت خودکار دریافت خواهند شد و نکته‌ی مهم آن، قرار گرفتن این فایل nuspec در پوشه‌ی اصلی پروژه است. از این جهت که برای کامپایل آن و تبدیل به یک بسته‌ی نیوگت، فایل nuget.exe را بر روی فایل پروژه‌ی اصلی برنامه اجرا خواهیم کرد و نه بر روی این فایل nuspec.
بنابراین تکمیل اطلاعات فایل AssemblyInfo.cs را فراموش نکنید. برای مثال اطلاعات AssemblyCompany آن، در قسمت authors فایل فوق جایگزین می‌شود.


ب) تهیه فایل NuGet.exe
فایل NuGet.exe را جهت کامپایل فایل فرضی TestNuget.nuspec نیاز داریم. می‌توان آن‌را از سایت کدپلکس تهیه کرد و یا تنها کافی است بر روی Solution موجود در VS.NET کلیک راست کرده و گزینه‌ی Enable NuGet Package Restrore را انتخاب کنیم. با اینکار به صورت خودکار پوشه‌ی ویژه‌ای به نام .nuget به همراه فایل NuGet.exe ایجاد می‌شود.


ج) کامپایل فایل nuspec
در همان پوشه‌ی جدید .nuget، یک فایل bat را با محتوای ذیل تهیه کنید:
 "%~dp0NuGet.exe" pack "..\TestNuGet\TestNuGet.csproj" -Prop Configuration=Release
copy "%~dp0*.nupkg" "%localappdata%\NuGet\Cache"
pause
در این مثال، مسیر TestNuGet\TestNuGet.csproj به محل قرارگیری فایل پروژه‌ی برنامه اشاره می‌کند. در اینجا فایل nuget.exe را بر روی فایل csproj برنامه اجرا خواهیم کرد. با توجه به اینکه قرار است یک بسته‌ی عمومی منتشر شود، بهتر است تنظیمات تولید بسته‌ی نیوگت را بر روی حالت release قرار داد که در این دستور، قید شده‌است.
در ادامه برای اینکه امکان آزمایش محلی این بسته را نیز داشته باشیم، فایل بسته‌ی تولیدی، به کش محلی نیوگت، در سیستم جاری کپی می‌شود.

نکته‌ی جالب این روش، تهیه‌ی قسمت dependencies پروژه، به صورت خودکار است:
<?xml version="1.0"?>
<package xmlns="http://schemas.microsoft.com/packaging/2011/08/nuspec.xsd">
  <metadata>
    <id>TestNuget</id>
    <version>1.0.0.0</version>
    <title>TestNuget</title>
    <authors>Vahid N.</authors>
    <owners>Vahid N.</owners>
    <licenseUrl>https://site.com/prj/LICENSE</licenseUrl>
    <projectUrl>https://site.com/prj</projectUrl>
    <requireLicenseAcceptance>false</requireLicenseAcceptance>
    <description>This is a test.</description>
    <copyright>Copyright 2015 My Name</copyright>
    <dependencies>
      <dependency id="EntityFramework" version="6.1.2" />
    </dependencies>
  </metadata>
</package>
اطلاعاتی را که در اینجا مشاهده می‌کنید، حاصل کامپایل فایل nuspec معرفی شده‌ی در ابتدای بحث است (با اجرای فایل bat تهیه شده) که یک کپی از آن در فایل TestNuget.1.0.0.0.nupkg نهایی نیز قرار می‌گیرد. به این ترتیب دیگر نیازی نیست تا این قسمت را به صورت دستی معرفی و هر بار با به روز رسانی وابستگی‌های پروژه، شماره نگارش‌های آن‌ها را نیز به روز کرد. اطلاعات version به صورت خودکار از پروژه‌ی جاری استخراج می‌شوند.


د) آزمایش محلی بسته‌ی جدید
اکنون که فایل TestNuget.1.0.0.0.nupkg تولیدی را در آدرس localappdata%\NuGet\Cache% نیز کپی کرده‌ایم، به منوی Tools/Options مراجعه و در قسمت NuGet Package Manager آن، به قسمت Package sources، این آدرس کش محلی را نیز معرفی کنید:


به این ترتیب، بدون ارسال یک بسته به سایت اصلی نیوگت، می‌توان بسته را از کش محلی نیوگت نصب و آزمایش کرد:



فایل‌های ذکر شده در مطلب فوق را از اینجا می‌توانید دریافت کنید:
TestNuget.zip
 
مطالب
نحوه‌ی مشارکت در پروژه‌های GitHub به کمک Visual Studio
فرض کنید برای رفع باگی در پروژه‌ای از GitHub، ایده‌ای دارید. روند کاری اعلام آن، روش‌های مختلفی می‌تواند داشته باشند؛ از باز کردن یک Issue جدید تا فرستادن یک فایل zip و غیره. اما روش استاندارد مشارکت در پروژه‌های Git، ارسال یک PR یا Pull Request است. در ادامه نحوه‌ی انجام این‌کار را به کمک امکانات توکار VS.NET بررسی خواهیم کرد.


ایجاد یک Fork جدید در GitHub

برای ارسال تغییرات انجام شده بر روی یک پروژه، نیاز است به صاحب یا مسئول آن مخزن در GitHub مراجعه و سپس درخواست دسترسی اعمال تغییرات را نمود. در این حالت، احتمال اینکه جواب منفی دریافت کنید، بسیار زیاد است. جهت مدیریت یک چنین مواردی، قابلیتی به نام ایجاد یک Fork پیش بینی شده‌است.


در بالای هر مخزن کد در GitHub، یک دکمه به نام Fork موجود است. بر روی آن که کلیک کنید، یک کپی از آن پروژه را به مجموعه‌ی مخزن‌های کد شما در GitHub اضافه می‌کند. بدیهی است در این حالت، مجوز ارسال تغییرات خود را به GitHub و در اکانت خود خواهید داشت. نحوه‌ی اطلاع رسانی این تغییرات به صاحب اصلی این مخزن کد، ارسال همان PR یا Pull Request است.


دریافت مخزن کد Fork شده از GitHub به کمک Visual Studio

پس از اینکه Fork جدیدی را از پروژه‌ای موجود ایجاد کردیم، نیاز است یک Clone یا کپی مطابق اصل آن‌را جهت اعمال تغییرات محلی، تهیه کنیم. برای اینکار VS.NET را گشوده و به برگه‌ی Team Explorer آن که در کنار Solution Explorer قرار دارد، مراجعه کنید.


در اینجا بر روی دکمه‌ی Connect در نوار ابزار آن، کلیک کرده و در صفحه‌ی باز شده، بر روی لینک Clone کلیک نمائید. در اینجا می‌توان آدرس مخزن کد Fork شده را جهت تهیه یک Clone مشخص کرد؛ به همراه محلی که قرار است این Clone در آن ذخیره شود.
آدرس HTTPS وارد شده، در کنار تمام مخازن کد GitHub قابل مشاهده هستند:


پس از تکمیل این دو آدرس، بر روی دکمه‌ی Clone کلیک نمائید. پس از پایان کار، اگر به آدرس محلی داده شده بر روی کامپیوتر خود مراجعه کنید، یک کپی از فایل‌های این مخزن، قابل مشاهده هستند.


اعمال تغییرات محلی و ارسال آن به سرور GitHub

در ادامه، این پروژه‌ی جدید را در VS.NET باز کرده و تغییرات خود را اعمال کنید. اکنون نوبت به ارسال این تغییرات به سرور GitHub است.  برای این منظور به برگه‌ی Team Explorer مراجعه کرده و بر روی دکمه‌ی Home آن کلیک کنید. سپس گزینه‌ی Changes را انتخاب نمائید:


در اینجا توضیحاتی را نوشته و سپس بر روی دکمه‌ی Commit کلیک کنید.


پس از هماهنگ سازی محلی، اکنون نوبت به هماهنگ سازی این تغییرات با مخزن کد GitHub است. بنابراین بر روی لینک Sync در پیام ظاهر شده کلیک کنید و در صفحه‌ی بعدی نیز بر روی دکمه‌ی Sync کلیک نمائید:



اکنون اگر به پروژه‌ی GitHub خود مراجعه کنید، این تغییر جدید قابل مشاهده‌است:



مطلع سازی صاحب اصلی مخزن کد از تغییرات انجام شده

تا اینجا کسی از تغییرات جدید انجام شده‌ی توسط ما باخبر نیست. برای اطلاع رسانی در مورد این تغییرات، به مخزن کد Fork شده که اکنون تغییرات جدید به آن ارسال شده‌اند، مراجعه کنید. سپس در کنار صفحه بر روی لینک Pull request کلیک نمائید:


در اینجا بر روی دکمه‌ی New pull request کلیک کنید:


در ادامه تغییرات ارسال شما نمایش داده خواهند شد. آن‌ها را بررسی کرده و مجددا بر روی دکمه‌ی Create pull request کلیک کنید:


در اینجا عنوان و توضیحاتی را وارد کرده و سپس بر روی دکمه‌ی Create pull request کلیک نمائید:



یکی سازی تغییرات با مخزن اصلی

اکنون صاحب اصلی مخزن کد یک ایمیل را دریافت خواهد کرد؛ همچنین اگر به مخزن کد خود مراجعه نماید، آمار Pull requests دریافتی قابل مشاهده است:


پس از انتخاب یکی از آن‌ها، لینکی برای بررسی تغییرات انجام شده و همچنین دکمه‌ای برای یکی سازی آن‌ها با پروژه‌ی اصلی وجود دارد:



دریافت این تغییرات در مخزن کد محلی توسط صاحب اصلی پروژه

اکنون که این تغییرات با پروژه‌ی اصلی Merge و یکی شده‌اند، صاحب اصلی پروژه جهت تهیه‌ی یک کپی محلی و بهبود یا تغییر آن‌ها می‌تواند به صورت ذیل عمل کند:


ابتدا به برگه‌ی Team explorer مراجعه کرده و بر روی دکمه‌ی Home آن کلیک کنید. سپس گزینه‌ی Unsynced commits را انتخاب نمائید. در صفحه‌ی باز شده بر روی دکمه‌ی Sync کلیک نمائید. به این ترتیب آخرین تغییرات را از مخزن کد GitHub به صورت خودکار دریافت خواهید کرد:

 
مطالب
روشی سریع برای ایجاد RSS و Sitemap در ASP.NET MVC
برای مطالعه روش‌های بدست آوردن خروجی xml مربوط به Rss و Sitemap،  میتوانید از مقالات مشخص شده استفاده کنید .[اینجا] و [اینجا].

در صورتیکه طراحی شما بر اساس MVC صورت گرفته است، در کمتر از چند دقیقه و در سه مرحله میتوانید پرونده Rss و Sitemap را برای همیشه ببندید. 

پیش از تشریح مراحل، به ساختار این دو فایل توجه کنید. 

مراحل کار : 

مرحله 1. ایجاد نوع(Type) مورد نیاز برای ایجاد Xml ‌های فوق

مرحله 2 . ایجاد کنترلر XML

مرحله 3. ایجاد مسیریابی(Routing)


مرحله 1 : ابتدا یک کلاس به منظور شکل دهی به اطلاعات، بر اساس خواسته‌های xml مرتبط با RSS و Sitemap تشکیل دهید:

public class PostToXml
    {
        
        public int PostId { get; set; }

        public string title { get; set; }

        public string link { get; set; }
        
        public string description { get; set; }

        public Nullable<DateTime> pubDate { get; set; }

      
    }

مرحله 2 : یک کنترلر به نام xml ایجاد کنید و اکشن متدهای زیر را درون آن قرار دهید :

       public ContentResult RSS()
        {
            
            var items = GetRssFeed();
            var rss = new XDocument(new XDeclaration("1.0", "utf-8", "yes"),
              new XElement("rss",
                new XAttribute("version", "2.0"),
                  new XElement("channel",
                    new XElement("title", "آخرین مطالب سایت"),
                    new XElement("link", "http://" + Request.Url.Host+"/rss"),
                    new XElement("description", "آخرین مطالب سایت من"),
                    new XElement("copyright","(c)" + DateTime.Now.Year + ", نام سایت من.تمامی حقوق محفوظ است"),
                  from item in items
                  select
                  new XElement("item",
                    new XElement("title", item.title),
                    new XElement("description", item.description),
                    new XElement("link", item.link),
                    new XElement("pubDate", item.pubDate)

                  )
                )
              )
            );
            return Content(rss.ToString(), "text/xml");
        }



        public ContentResult Sitemap()
        {
            XNamespace ns = "http://www.sitemaps.org/schemas/sitemap/0.9";
            var items = GetLinks();
            var sitemap = new XDocument(new XDeclaration("1.0", "utf-8", "yes"),
                new XElement(ns + "urlset",
                    from item in items
                    select
                    new XElement("url",
                      new XElement("loc", item.link),
                      new XElement("changefreq", "monthly"),
                      new XElement("priority", "0.5")
                      )
                    )
                  );
            return Content(sitemap.ToString(), "text/xml");
        }


        public IEnumerable<PostToXml> GetRssFeed()
        {
          // یک کوئری که لیستی از تایپ مشخص شده به ما بدهد
        }

         public IEnumerable<PostToXml> GetLinks()
        {
            // یک کوئری که لیستی از تایپ مشخص شده به ما بدهد
        }

این کنترلر دارای دو اکشن متد Rss و Sitemap است و این اکشن‌ها وظیفه‌ی ایجاد فایل‌های Xml را به عهده دارند. مواد اولیه این xml ‌ها از دو متد GetRssFeed و GetLinks تهیه می‌شوند. ما این مواد را در تمپلیت Rss و Sitemap جایگذاری خواهیم کرد. (به کمک دو اکشن متد Rss و Sitemap )

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

مرحله 3 : در مرحله آخر کافیست دو مورد زیر را به فایل RoutConfig.cs بیافزایید: 

routes.MapRoute(
              "Sitemap", "sitemap",
              new { controller = "XML", action = "Sitemap" });
 routes.MapRoute(
              "RSS", "rss",
               new { controller = "XML", action = "RSS" });

به کمک آدرس‌های زیر می‌توانید به آنچه که تهیه کرده‌اید دسترسی داشته باشید :

http://domain.com/rss
http://domain.com/sitemap  

فایل پروژه را دریافت کنید :

MVC_RSS_Sitemap-43ad3c6681734b34b91deaaabcdba871.rar 

مطالب
نکات استفاده از افزونه‌ی Web Essentials جهت پردازش LESS
در این مطلب، نحوه‌ی استفاده از افزونه‌ی Web Essentials جهت پردازش فایل‌های LESS را بررسی می‌کنیم. پیش‌تر مطالبی را در رابطه با CSS pre-processorها مطالعه کرده‌اید، LESS نیز یک CSS pre-processor است، یا در واقع بهتر است بگوئیم یک زبان جهت پویا کردن CSS می‌باشد که در سال 2009 توسط Alexis Sellier به صورت سورس باز ایجاد شد. یکی از خصوصیات جالب LESS نسبت به دیگر CSS preprocessorها، قابلیت کامپایل فایل‌های CSS به صورت real-time از طریق مرورگر توسط LESS.js می‌باشد.

روش‌های استفاده از LESS در دات نت
1- استفاده از SimpLESS
SimpLESS تمام تغییرات فایل‌های CSS را مشاهده می‌کند و در نهایت به صورت خودکار آنها را به CSS کامپایل و همچنین miniy می‌کند. این روش مستقل از دات نت است و برای هر فایل LESSی جوابگو خواهد بود.

2- استفاده از {}less.

Dotless یک پیاده سازی از کتابخانه جاوا اسکریپتی LESS برای دات نت می‌باشد. پکیج نیوگت DotLess را نیز می‌توانید از اینجا دریافت کنید. بعد از اضافه شدن فایل‌های آن، یک ارجاع به dotless.core به پروژه تان اضافه خواهد شد. همچنین در فایل Web.Config در قسمت HttpHandler خط زیر اضافه خواهد شد:

<add type="dotless.Core.LessCssHttpHandler,dotless.Core" validate="false" path="*.LESS" verb="*" />

خط فوق یعنی به محض مواجه شدن با فایل LESS، پردازشگر فایل‌های LESS وارد عمل می‌شود. همچنین خط زیر نیز جهت پیکربندی به قسمت configSections در فایل Web.Config اضافه می‌شود:

<section name="dotless" type="dotless.Core.configuration.DotlessConfigurationSectionHandler,dotless.Core" />

همچنین اگر مایل بودید می‌توانید تنظیمات مربوط به فشرده سازی و caching را نیز فعال کنید:

<dotless minifyCss="false" cache="true" />

3- استفاده از افزونه‌ی Web Essentials

Web Essentials برای کامپایل فایل‌های LESS از کامپایلر node استفاده می‌کند. کار با این افزونه خیلی ساده است. کافی است پسوند فایل CSS موجود در پروژه تان را درون ویژوال استودیو، به less. تغییر دهید. با دوبار کلیک بر روی فایل، ویرایشگر فایل‌های LESS برای شما نمایش داده می‌شود، همزمان نیز فایل یک فایل CSS و یک نسخه از فایل CSS را به صورت فشرده، برایتان تولید می‌کند. خب، هر بار که فایل LESS را تغییر دهید، Web Essentials به صورت خودکار فایل‌های css. و min.css. را برایتان روز رسانی می‌کند.

خوب با کلیک بر روی فایل less، ویرایشگر فایل‌های less نمایش داده می‌شود که با تغییر فایل css می‌توانید پیش نمایش آنرا در سمت راست مشاهده کنید:

تعریف متغیر

با استفاده از syntax زیر می‌توانید متغیرهای خود را تعریف کنید:

@variable-name: variableValue;

یکی از قابلیت‌های جالب در حین مقداردهی متغیرها به خصوص زمانیکه مقدار یک کد رنگی باشد، نمایش کادر انتخاب رنگ است، این کادر بلافاصله بعد از نوشتن علامت # در ابتدای مقدار متغیر نمایش داده می‌شود:

به طور مثال با تعریف متغیر فوق هر جایی می‌توانیم برای تعیین رنگ از آن استفاده کنیم:

@primary-color: #ff6a00;
body
{
    background-color: @primary-color;
}

استفاده از توابع

LESS شامل تعداد زیادی توابع از پیش نوشته شده است که می‌توانید به راحتی از آنها استفاده کنید، توابعی از جمله کار با رنگ ها، اعمال ریاضی و غیره. استفاده از آنها خیلی ساده است. به طور مثال در کد زیر از تابع percentage جهت تبدیل 0.5 به 50% استفاده کرده ایم:

.myClass
{
    width: percentage(0.5);
}

استخراج یک فایل

یکی دیگر از قابلیت‌های Web Essentials استخراج(Extract) یک فایل می‌باشد به طور مثال فایل LESS شما شامل متغیرهای زیر است:

@primary-color: #7BA857;
@primary-color-light: #B6DE8F;
@primary-color-lighter: #D3EFC3;
@primary-color-lightest: #EFFAE6;
@secondary-color: #AE855C;
@text-color-light: #666666;
@text-color-dark: #0444;

به راحتی می‌توانید تعاریف فوق را درون یک فایل LESS دیگر با نام colors.less قرار دهید:

تغییر تنظیمات پیش فرض Web Essentials

افزونه Web Essentials دارای یک قسمت جهت تغییر تنظیمات پیش فرض برای کار با LESS می‌باشد که با مراجعه به منوی Tools در ویژوال استودیو و سپس Options می‌توانید آنها را تغییر دهید:

Auto-compile dependent files on save: توسط این گزینه می‌توانیم تعیین کنیم که فایل‌های که import کرده ایم تنها در صورتی که تغییر کرده و ذخیره شده باشند، در فایل CSS جاری کامپایل شوند.

Compile files on build: توسط این گزینه می‌توانیم تعیین کنیم که فایل‌های less در زمان Build پروژه کامپایل شوند.

Compile files on save: توسط این گزینه می‌توانیم تعیین کنیم که فایل‌های less در زمان ذخیره کردن پروژه کامپایل شوند. 

Create source map files: اگر این گزینه True باشد فایل map. نیز تولید خواهد شد.

Custom output directory: اگر می‌خواهید خروجی در پوشه‌ی موردنظر شما نمایش داده شود می‌توانید آدرس آن را تعیین کنید.

Don't save raw compilation output: با فعال بودن این گزینه فایل CSS عادی ایجاد نخواهد شد.

Process source maps: توسط این گزینه می‌توانید قابلیت‌های ویرایشگر فایل‌های source map را فعال یا غیرفعال کنید.

Strict Math: با فعال بودن این گزینه LESS تمام اعمال ریاضی درون فایل CSS را پردازش خواهد کرد.

Show preview pane: از این گزینه نیز جهت نمایش یا عدم نمایش preview window استفاده می‌شود.

مطالب
استفاده از چندین Context در EF 6 Code first
در نگارش قبلی EF Code first به ازای یک پروژه تنها یک سیستم Migration قابل تعریف بود و این سیستم مهاجرت، تنها با یک DbContext کار می‌کرد. در نگارش ششم این کتابخانه، سیستم مهاجرت Code first آن از چندین DbContext، به ازای یک پروژه که به یک بانک اطلاعاتی اشاره می‌کنند، پشتیبانی می‌کند. مزیت اینکار اندکی بهبود در نگهداری تنها کلاس DbContext تعریف شده است. برای مثال می‌توان یک کلاس DbContext مخصوص قسمت ثبت نام را ایجاد کرد. یک کلاس DbContext مخصوص کلیه جداول مرتبط با مقالات را و همینطور الی آخر. نهایتا تمام این Contextها سبب ایجاد یک بانک اطلاعاتی واحد خواهند شد.
اگر در یک پروژه EF Code first چندین Context وجود داشته باشد و دستور enable-migrations را بدون پارامتری فراخوانی کنیم، پیغام خطای More than one context type was found in the assmbly xyz را دریافت خواهیم کرد.
الف) اما در EF 6 می‌توان با بکار بردن سوئیچ جدید ContextTypeName، به ازای هر Context، مهاجرت مرتبط با آن‌را تنظیم نمود:
 enable-migrations -ContextTypeName dbContextName1 -MigrationDirectory DataContexts\Name1Migrations
همچنین در اینجا نیز می‌توان با استفاده از سوئیچ MigrationDirectory، فایل‌های تولید شده را در پوشه‌های مجزایی ذخیره کرد.

ب) در مرحله بعد، نیاز به فراخوانی دستور add-migration است:
 add-migration -ConfigurationTypeName FullNameSpaceCtx1.Configuration "InitialCreate"
با اجرای دستور enable-migrations یک کلاس Configuration جهت DbContext مشخص شده، ایجاد می‌شود. سپس آدرس کامل این کلاس را به همراه ذکر دقیق فضای نام آن در اختیار دستور add-migration قرار می‌دهیم.
ذکر کامل فضای نام، از این جهت مهم است که کلاس Configuration به ازای Contextهای مختلف ایجاد شده، یک نام را خواهد داشت؛ اما در فضاهای نام متفاوتی قرار می‌گیرد.
با اجرای دستور add-migration، کدهای سی شارپ مورد نیاز جهت اعمال تغییرات بر روی ساختار بانک اطلاعاتی تولید می‌شوند. در مرحله بعد، این کدها تبدیل به دستورات SQL متناظری شده و بر روی بانک اطلاعاتی اجرا خواهند شد.
بدیهی است اگر دو Context در برنامه تعریف کرده باشید، دوبار باید دستور enable-migrations و دوبار دستور add-migration را با پارامترهای اشاره کننده به Conetxtهای مدنظر اجرا کرد.

ج) سپس برای اعمال این تغییرات، باید دستور update-database را اجرا کرد.
 update-database  -ConfigurationTypeName FullNameSpaceCtx1.Configuration
اینبار دستور update-database نیز بر اساس نام کامل کلاس Configuration مدنظر باید اجرا گردد و به ازای هر Context موجود، یکبار نیاز است اجرا گردد.
نهایتا اگر به بانک اطلاعاتی مراجعه کنید، تمام جداول و تعاریف را یکجا در همان بانک اطلاعاتی می‌توانید مشاهده نمائید.


داشتن چندین Context در برنامه و مدیریت تراکنش‌ها

در EF، هر DbContext معرف یک واحد کار است. یعنی تراکنش‌ها و چندین عمل متوالی مرتبط انجام شده، درون یک DbContext معنا پیدا می‌کنند. متد SaveChanges نیز بر همین اساس است که کلیه اعمال ردیابی شده در طی یک واحد کار را در طی یک تراکنش به بانک اطلاعاتی اعمال می‌کند. همچنین مباحثی مانند lazy loading نیز در طی یک Context مفهوم دارند. به علاوه دیگر امکان join نویسی بین دو Context وجود نخواهد داشت. باید اطلاعات را از یکی واکشی و سپس این اطلاعات درون حافظه‌ای را به دیگری ارسال کنید.

یک نکته
می‌توان یک DbSet را در چندین ‍Context تعریف کرد. یعنی اگر بحث join نویسی مطرح است، با تکرار تعریف DbSetها اینکار قابل انجام است اما این مساله اساس جداسازی Contextها را نیز زیر سؤال می‌برد.
 

داشتن چندین Context در برنامه و مدیریت رشته‌های اتصالی

در EF Code first روش‌های مختلفی برای تعریف رشته اتصالی به بانک اطلاعاتی وجود دارند. اگر تغییر خاصی در کلاس مشتق شده از DbContext ایجاد نکنیم، نام کلید رشته اتصالی تعریف شده در فایل کانفیگ باید به نام کامل کلاس Context برنامه اشاره کند. اما با داشتن چندین Context به ازای یک دیتابیس می‌توان از روش ذیل استفاده کرد:

  public class Ctx1 : DbContext
    {
        public Ctx1()
            : base("DefaultConnection")
        {
            //Database.Log = sql => Debug.Write(sql);
        }
    }

  public class Ctx2 : DbContext
    {
        public Ctx2()
            : base("DefaultConnection")
        {
            //Database.Log = sql => Debug.Write(sql);
        }
    }

  <connectionStrings>
    <add name="DefaultConnection" connectionString="…." providerName="System.Data.SqlClient" />
  </connectionStrings>
در اینجا در سازنده کلاس‌های Context تعریف شده، نام کلید رشته اتصالی موجود در فایل کانفیگ برنامه ذکر شده است. به این ترتیب این دو Context به یک بانک اطلاعاتی اشاره خواهند کرد.


چه زمانی بهتر است از چندین Context در برنامه استفاده کرد؟
عموما در طراحی‌های سازمانی SQL Server، تمام جداول از schema مدیریتی به نام dbo استفاده نمی‌کنند. جداول فروش از schema خاص خود و جداول کاربران از schema دیگری استفاده خواهند کرد. با استفاده از چندین Context می‌توان به ازای هر کدام از schemaهای متفاوت موجود، «یک ناحیه ایزوله» را ایجاد و مدیریت کرد.
  public class Ctx2 : DbContext
    {
        public Ctx2()
            : base("DefaultConnection")
        {
            //Database.Log = sql => Debug.Write(sql);
        }

         protected override void OnModelCreating(DbModelBuilder modelBuilder)
        {
            modelBuilder.HasDefaultSchema("sales");
            base.OnModelCreating(modelBuilder);
        }
    }
در این حالت در EF 6 می‌توان DefaultSchema کلی یک Context را در متد بازنویسی شده OnModelCreating به نحو فوق تعریف و مدیریت کرد. در این مثال به صورت خودکار کلیه DbSetهای Ctx2 از schema ایی به نام sales استفاده می‌کنند.
مطالب
نصب Mono Develop 4.x در Ubuntu
پیشنیازها

در قسمت قبل، موفق به نصب Mono 3.0 در لینوکس شدیم. در ادامه قصد داریم یک IDE لینوکسی مخصوص کار با Mono را به نام Mono Develop بر روی Ubuntu نصب کنیم. اگر مونو را نصب کرده‌اید، نیاز است پیشنیازهای ذیل را بر روی سیستم خود نصب کنید:
 sudo apt-get update
sudo apt-get upgrade -y
sudo apt-get install -y build-essential libc6-dev g++ gcc libglib2.0-dev pkg-config \
 git-core apache2 apache2-threaded-dev bison gettext autoconf automake libtool \
libpango1.0-dev libatk1.0-dev libgtk2.0-dev libtiff5-dev libgif-dev libglade2-dev curl \
python-software-properties gawk libjpeg-dev libexif-dev flex checkinstall intltool git \
libcairo2-dev libgnomecanvas2-dev libgnome2-dev libgnomeui-dev libgnomeprint2.2-dev \
libgnomeprintui2.2-dev libgtkhtml3.14-dev libgtksourceview2.0-dev librsvg2-dev libvte-dev \
libnspr4-dev libnss3-dev libwebkit-dev apache2-threaded-dev libpng12-dev libfontconfig1-dev \
libfreetype6-dev zlib1g-dev libjpeg8-dev libjpeg-turbo8-dev libart-2.0-dev libgnomevfs2-dev \
libgnome-desktop-dev libnautilus-extension-dev libwnck-dev libvala-0.18-dev \
mono-addins-utils gtk-sharp2 gnome-sharp2
نصب این پیشنیارها ضروری بوده و در غیر اینصورت موفق به build کامل Mono Develop نخواهید شد. برای مثال پیغام خطای ذیل را در انتهای build دریافت می‌کنید؛ به این معنا که اسمبلی‌های ذیل کامپایل نشده‌اند:
 * art-sharp.dll: no
* gnomevfs-sharp.dll: no
* gnome-sharp.dll: no
و یا عنوان می‌کند که  gnome-sharp.dll برای کامپایل نیاز به یک سری کتابخانه کمکی دیگر نیز دارد:
  gnome-sharp.dll requires libgnomecanvas, libgnome, and libgnomeui.


نصب متداول محیط برنامه نویسی Mono Develop

برای نصب یک IDE که بتوان تحت همان لینوکس نیز کار برنامه نویسی دات نت را انجام داد، می‌توان از Mono deveop استفاده کرد. برای نصب آن فرمان ذیل را در خط فرمان لینوکس صادر نکنید !
 sudo apt-get install monodevelop
این روش هر چند کار می‌کند، اما تا این تاریخ، نگارش 3 را نصب خواهد کرد؛ با توجه به اینکه آخرین نگارش موجود در سایت Mono Develop، نگارش 4 است. همچنین نصب آن نیز نگارش جاری Mono را به نگارش 2 آن تنظیم می‌کند که جالب نیست. اگر به اشتباه آن‌را نصب کرده‌اید، برای حذف مونو از دستور ذیل استفاده کنید:
 sudo apt-get purge cli-common mono-runtime
همچنین الان کلیه مسیرهای سیستم به هم ریخته است. برای رفع آن مسیر نصب Mono-3.0 را باید به نحو ذیل مجددا تنظیم کرد:
 export PATH=/opt/mono-3.0/bin:$PATH
export PKG_CONFIG_PATH=/opt/mono-3.0/lib/pkgconfig:$PKG_CONFIG_PATH


نصب محیط برنامه نویسی Mono Develop از روی مخزن کد آن

دریافت و نصب وابستگی‌های Monodevelop جهت کامپایل سورس آن، شاید نصف روز شما را به خود اختصاص دهد؛ به علاوه حداقل مصرف حدود 500 مگابایت حجم اینترنت. راه ساده‌تری نیز برای دریافت آخرین نگارش سازگار با Ubuntu آن وجود دارد و آن هم استفاده از بسته‌های شخصی کامپایل شده است؛ که اصطلاحا به آن‌ها PPA نیز گفته می‌شود. برای مثال: (^ و ^ )
چند نمونه بسته شخصی برای دریافت ساده آخرین نگارش Mono develop جهت نصب بر روی Ubuntu : (^ و ^ و ^ )
و به صورت خلاصه فرامین ذیل را در ترمینال لینوکس اجرا کنید تا از بسته شخصی keks9n استفاده کنیم:
 sudo add-apt-repository ppa:keks9n/monodevelop-latest
sudo apt-get update
sudo apt-get install monodevelop-latest
این روش، از تمام روش‌های ذکر شده تا کنون، ساده‌تر است. از این لحاظ که mono 3.2.1 را نیز به صورت خودکار بر روی سیستم شما نصب می‌کند (این بسته شخصی، به صورت خودکار هر از چندگاهی آخرین نگارش مونو، وابستگی‌های آن و monodevelop جدید را بسته بندی و ارائه می‌دهد).
بنابراین اگر مونو 3.2.1 یا جدیدتر را هنوز نصب نکرده‌اید، همین سه سطر فوق، کار نصب کلی آن‌را نیز انجام می‌دهد؛ علاوه بر نصب monodevelop در آخر کار به همراه تمام پیشنیازهای لازم مانند gtk-sharp و gnome-sharp.
پس از نصب کامل، برای اجرای آن در همان خط فرمان، دستور monodevelop را صادر کنید.