بازخوردهای دوره
مدیریت استثناءها در حین استفاده از واژه‌های کلیدی async و await
- در مورد EF و متدهای Async آن مطلب جداگانه‌ای تهیه شده: «پردازش‌های Async در Entity framework 6»
- در مورد ASP.NET MVC و متدهای Async هم یک مطلب اختصاصی تهیه شده: «استفاده از Async و Await در برنامه‌های ASP.NET MVC »
- مثال دوم شما async نیست چون از متد Wait استفاده کرده‌اید (این متد، یک متد blocking است و ترد جاری را قفل می‌کند). این مثال با نمونه‌ی همزمان تقریبا یکسان عمل می‌کند.
همچنین در این مثال استفاده از Task.Factory.StartNew به معنای async تقلبی است و اصلا توصیه نمی‌شود. برای EF متدهای Async واقعی وجود دارند.
- هدف از بکارگیری متدهای async الزاما سریعتر کردن اجرای عملیات مورد نظر نیست. هدف خالی کردن ترد جاری و امکان استفاده‌ی مجدد از آن برای پاسخ دهی به یک کاربر دیگر است؛ با توجه به اینکه هزینه ایجاد تردهای جدید بالا است و همچنین نهایتا بر اساس مشخصات و منابع سرور، این تعداد محدود است. هدف بالا بردن میزان مقیاس پذیری یک برنامه است با تعداد کاربران بالا.
نظرات اشتراک‌ها
نگاهی به آمار سال 2015 سایت StackOverflow
باتوجه به اینکه برنامه نویس‌های ایرانی رتبه‌ی دوم رو از نظر رضایت شغلی در دنیا دارند (مطابق تصویر) فکر کنم مفهوم job satisfaction رو درست متوجه نشدند. job satisfaction به این معنا نیست که «آیا عاشق برنامه نویسی هستید یا نه؟» و بعد هم شما پاسخ بدید YES YES YES ! رضایت شغلی شامل این موارد هست:
- آیا از توانمند‌ی‌های شما به درستی استفاده می‌شود؟
- آیا به منابع کافی برای انجام کارهای خود دسترسی دارید؟
- آیا امکان رشد به شما داده می‌شود؟
- آیا از لحاظ میزان دریافت حقوق رضایتمند هستید؟
- آیا از رفتار بالاتری‌ها و مدیران خود رضایت دارید؟
- آیا تابحال تشویق و پاداشی را از مدیران خود دریافت کرده‌اید؟
- آیا انتظارات مدیر شما از شما واقعی هستند؟
- آیا نظرات شما در تصمیم گیری‌های مدیران شما مؤثر هستند؟
- آیا می‌توانید به سادگی با نظرات و تصمیمات ارائه شده‌ی توسط مدیران مخالفت کنید؟
- میزان استرس شغلی شما چقدر است؟
- آیا شغل شما تعادل زندگی و کار را به همراه داشته است یا آن‌را به هم زده‌است؟
- به چه میزان احساس امنیت شغلی می‌کنید؟
- آیا در محیط کاری خود احساس راحتی می‌کنید؟
- آیا بیمه شده‌اید؟
مطالب
دیباگ سرویس‌های ویندوز
یکی از سخت‌ترین چالش‌های تهیه سرویس‌های ویندوز، دیباگ آن‌ها است. برای تست و دیباگ کد‌ها در ویندوز سرویس‌ها، راهکارها و ابزارهای متفاوتی ارائه شده‌اند که در این مقاله قصد دارم یکی از آن‌ها را معرفی کنم.

برای تست کدها در ویندوز سرویس، اولین راه پیشنهادی همیشه این بوده که سرویس را موقتا به Console Application تبدیل کنیم و با تهیه یک متد در سرویس و فراخوانی آن در متد Main برنامه کنسولی، بتوانیم به دیباگ برنامه بپردازیم. مثال: 
تغییرات مورد نیاز در سرویس : 
 public Service1(string[] args)
        {
            this.args = args;
        }

        internal void TestStartupAndStop(string[] args)
        {
            this.OnStart(args);
            Console.ReadLine();
            this.OnStop();
        }
        protected override void OnStart(string[] args)
        {
            Console.WriteLine("Service Started");
            //Do Somthing
        }
تغییرات مورد نیاز در متد Main : 
static void Main(string[] args)
        {
            if (Environment.UserInteractive)
            {
                Service1 service1 = new Service1(args);
                service1.TestStartupAndStop(args);
            }
            else
            {
                // Put the body of your old Main method here.
                ServiceBase[] ServicesToRun;
                ServicesToRun = new ServiceBase[]
                {
                new Service1()
                };
                ServiceBase.Run(ServicesToRun);
            }
        }
برای کسب اطلاعات بیشتر در مورد این روش برای دیباگ، میتوانید به این لینک مراجعه نمایید.
این راه حل کلی، عموما جوابگوی نیازها هست و تست و دیباگ را میتوانیم از همین طریق انجام دهیم. اما مشکلات زیادی هم دارد. به طور مثال یکی از مشکلات هنگام استفاده از این راه حل، تفاوت دسترسی‌ها و کاربر اجرا کننده برنامه، در حالت کنسول و سرویس ویندوز است. به همین دلیل بسیار با این مشکل مواجه خواهید شد که هنگام دیباگ مشکلی وجود نداشته ولی بعد از نصب سرویس، برنامه بدرستی کار نکند. به طور مثال وقتی شما سرویس را به صورت Network Service ویا Local System نصب کنید، دسترسی برنامه به کلیدهای رجیستری , فایل سیستم و Environment تغییر میکند. در نتیجه اگر مانند روشی که در بالا ذکر شد دیباگ را انجام دهید، نمیتوانید مشکلات را شناسایی و رفع کنید. همینطور روش قبلی صرفا برای دیباگ نیازمند تغییر در سورس کد اصلی برنامه است که خود میتواند مشکلات یا محدودیت‌هایی را هنگام کار به صورت تیمی ایجاد کند.

برای دیباگ سرویس نصب شده چه باید کرد ؟
در این مطلب نمیخواهم وارد جزئیات نحوه نصب ویندوز سرویس‌ها شوم؛ چراکه خودش مبحث گسترده‌ایست. برای کسب اطلاعات بیشتر در مورد نحوه‌ی نصب سرویس‌ها میتوانید به این لینک مراجعه نمایید.
برای اینکه بعد از نصب سرویس بتوانیم به دیباگ آن بپردازیم، مراحل زیر را طی کنید.
1- اول در ابتدای متد OnStart سرویس، تکه کد زیر را وارد نمایید و یک BreakPoint کنارش قرار دهید:
System.Diagnostics.Debugger.Launch(); // Start Debugger
البته پیشنهاد میکنم که این بخش را به صورت زیر وارد کنید تا فقط درصورتیکه سرویس شما در حالت Debug ساخته شده باشد، اجرا شود.
#if DEBUG
      System.Diagnostics.Debugger.Launch(); // Start Debugger
#endif
2- سرویس را با استفاده از installutil نصب کرده و استارت نمایید.
هنگام استارت سرویس، پنجره زیر نمایان میشود.


درصورتی که Yes را انتخاب نمایید، میتوانید در یک Solution جدید به دیباگ برنامه بپردازید و دیباگر به صورت خودکار کدهای مورد نیاز را برای شروع کار، برای شما بارگذاری خواهد کرد. اما در پروژه‌های بزرگ‌تر به دلیل وابستگی‌های سرویس به کتابخانه‌های متعدد، امکان دیباگ کامل را هنوز در اختیار نداریم و دیباگ ما در اینجا، محدود به خود سرویس است. برای اینکه بتوانیم دیباگ را کامل در Solution اصلی برنامه انجام دهید، قبل پاسخ دادن به پنجره بالا یک مرحله دیگر از کار باقی مانده است.
3- در Solution اصلی برنامه خود، کلید‌های Ctrl+Alt+P را فشار دهید؛ یا از طریق منوی Debug > Attach to process، پنجره Attack to Process را باز نمایید.

همانطور که در تصویر مشاهده میکنید، ID پروسه را در هر دو عکس برایتان مشخص کرد‌ه‌ام (هایلایت زرد) که به راحتی میتوانید پروسه سرویستان را از این طریق پیدا کنید.
کافیست روی کلید Attach کلیک نمایید تا در Solution اصلی برنامه بتوانید به صورت کامل به دیباگ سرویس نصب شده بپردازید. پس از اتچ کردن پروسه به Solution خود، پنجره اول (Visual Studio Just-In Time debugger) را ببندید یا گزینه No را انتخاب نمایید.
نکته: برای استفاده از این روش باید Visual Studio به صورت Administrator اجرا شده باشد.
مطالب
تولید و ارسال خودکار بسته‌های NuGet پروژه‌های NET Core. به کمک AppVeyor
اگر پروژه‌ی شما به همراه توزیع بسته‌های نیوگت است، پس از مدتی، از build و آپلود دستی بسته‌های نیوگت آن‌ها خسته خواهید شد. همچنین این سؤال هم برای مصرف کنندگان بسته‌ی نیوگت شما همواره وجود خواهد داشت: «آیا بسته‌ی نهایی را که آپلود کرده، دقیقا بر اساس سورس کد موجود در مخزن کد عمومی آن تهیه شده‌است؟»
برای رفع این مشکلات، از روش‌های توسعه‌ی به همراه ابزارهای یکپارچگی مداوم استفاده می‌شود. برای نمونه، AppVeyor یکی از سرویس‌های ابری یکپارچگی مداوم (Continuous Integration و یا به اختصار CI) است. به کمک آن می‌توان یک image از ویندوز سرور را به همراه ابزارهای build، آزمایش و توزیع برنامه‌های NET. در اختیار داشت. این سرویس، مخزن کد شما را مونیتور کرده و هر زمانیکه تغییری را در آن ایجاد کردید، آن‌ها را به صورت خودکار build و در صورت موفقیت آمیز بودن این عملیات، بسته‌ی نیوگت متناظری را به سایت nuget.org ارسال می‌کند. بنابراین پس از یکپارچه کردن مخزن کد خود با این نوع سرویس‌های یکپارچگی مداوم، دیگر حتی نیازی به build دستی آن نیز نخواهید داشت. همینقدر که کدی را به مخزن کد تحت نظر، commit کنید، مابقی مراحل آن خودکار است.
به همین جهت در این مطلب قصد داریم نحوه‌ی اتصال یک مخزن کد GitHub را به سرویس یکپارچگی مداوم AppVeyor، جهت تولید خودکار بسته‌های Nuget، بررسی کنیم.




معرفی سرویس ابری AppVeyor

AppVeyor یک راه حل یکپارچگی مداوم چند سکویی است که استفاده‌ی از آن برای پروژه‌های سورس باز رایگان است و سازگاری فوق العاده‌ای را با محصولات مایکروسافت دارد. برای ورود به آن می‌توان از اکانت‌های GitHub ،BitBucket و VSTS (Visual Studio Team Services) استفاده کرد.
گردش کاری متداول یکپارچگی مداوم AppVeyor به این صورت است:
الف) با اکانت GitHub خود به آن وارد شوید.
ب) یک مخزن کد GitHub خود را به آن Import کنید.
ج) به مخزن کد GitHub خود یک فایل yml. تنظیمات مخصوص AppVeyor را اضافه کنید.
د) نظاره‌گر Build و توزیع خودکار پروژه‌ی خود باشید.


ایجاد اکانت و اتصال به مخزن کد GitHub

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


پس از ورود موفق، گزینه‌ی new project را انتخاب کنید:


در ادامه مخزن کد GitHub و نوع عمومی آن‌را انتخاب می‌کنیم تا AppVeyor بتواند پروژه‌های آن‌را Import کند و همچنین به آن‌ها web hookهایی را اضافه کند تا با اعمال تغییراتی در سمت GitHub، کار اطلاع رسانی آن‌ها به AppVeyor به صورت خودکار صورت گیرد:


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


انجام تنظیمات عمومی مخزن کد

در صفحه‌ی بعدی، برگه‌ی settings و سپس از منوی کنار صفحه‌ی آن، گزینه‌ی ‌General را انتخاب کنید:


در اینجا اگر پروژه‌ی شما از نوع NET Core. است، گزینه‌ی NET Core .csproj patching. را انتخاب نمائید:


سپس در پایین صفحه بر روی دکمه‌ی Save کلیک کنید.


انتخاب و تنظیم محیط Build

در ادامه در برگه‌ی settings و سپس از منوی کنار صفحه‌ی آن، گزینه‌ی Environment را انتخاب کنید:


در این صفحه، worker image را بر روی VS 2017 قرار دهید و همچنین در قسمت Cached directories and files، مسیر C:\Users\appveyor\.dnx را جهت کش کردن عملیات Build و بالا بردن سرعت آن، مقدار دهی کنید. سپس در پایین صفحه بر روی دکمه‌ی Save کلیک نمائید.

اکنون بر روی گزینه‌ی Build در منوی سمت چپ صفحه کلیک کنید. در اینجا سه حالت msbuild ،script و off را می‌توان انتخاب کرد.
- در حالت msbuild، که ساده‌ترین حالت ممکن است، فایل sln. مخزن کد، یافت شده و بر اساس آن به صورت خودکار تمام پروژه‌های این solution یکی پس از دیگری build خواهند شد. این مورد برای برنامه‌های Full .NET Framework شاید گزینه‌ی مناسبی باشد.
- حالت script برای پروژه‌های NET Core. مناسب‌تر است و در این حالت می‌توان کنترل بیشتری را بر روی build داشت. به علاوه این روش بر روی لینوکس هم کار می‌کند؛ زیرا در آنجا دسترسی به msbuild نداریم.
- حالت off به معنای خاموش کردن عملیات build است.

در اینجا گزینه‌ی cmd را جهت ورود build script انتخاب می‌کنیم:


سپس دستورات ذیل را جهت ورود به پوشه‌ی پروژه‌ی کتابخانه (جائیکه فایل csproj آن قرار دارد)، بازیابی وابستگی‌های پروژه و سپس تولید بسته‌ی نیوگتی از آن، وارد می‌کنیم:
cd ./src/DNTPersianUtils.Core
dotnet restore
dotnet pack -c release
cd ../..
در ادامه در پایین صفحه بر روی دکمه‌ی Save کلیک نمائید.
ذکر  ../.. cd  در انتهای این دستورات ضروری است. در غیر اینصورت cd بعدی در تنظیماتی دیگر، داخل همین پوشه انجام می‌شود.


تنظیم اجرای خودکار آزمون‌های واحد


در همین صفحه، گزینه‌های settings -> tests -> script -> cmd را انتخاب و سپس دستورات زیر را وارد کرده و آن‌را ذخیره کنید:
cd ./src/DNTPersianUtils.Core.Tests
dotnet restore
dotnet test
cd ../..
به این ترتیب به صورت خودکار آزمون‌های واحد موجود در پروژه‌ی انتخابی، توسط NET Core CLI. اجرا خواهند شد.


تنظیم اطلاع رسانی خودکار از اجرای عملیات


در برگه‌ی settings -> notifications مطابق تنظیمات فوق می‌توان نوع email را جهت اطلاع رسانی شکست انجام عملیات یکپارچگی مداوم، انتخاب کرد.


آزمایش Build خودکار

برای آزمایش تنظیماتی که انجام دادیم، به برگه‌ی latest build مراجعه کرده و بر روی دکمه‌ی new build کلیک کنید تا اسکریپت‌های build و test فوق اجرا شوند. بدیهی است اجرای بعدی این اسکریپت‌ها خودکار بوده و به ازای هر commit به GitHub، بدون نیاز به مراجعه‌ی مستقیم به appveyor صورت می‌گیرند.



اضافه کردن نماد AppVeyor به پروژه

در تنظیمات برگه‌ی Settings، گزینه‌ی AppVeyor badge نیز در منوی سمت چپ صفحه، وجود دارد:


در اینجا همان کدهای mark down آن‌را انتخاب کرده و به ابتدای فایل readme پروژه‌ی خود اضافه کنید. برای نمونه نماد فعلی (تصویر فوق)، build failing را نمایش می‌دهد؛ چون سه آزمون واحد آن مشکل دارند و باید اصلاح شوند.
پس از رفع مشکلات پروژه و commit آن‌ها، build و اجرای خودکار آزمون‌های واحد آن توسط AppVeyor صورت گرفته و اینبار این نماد به صورت زیر تغییر می‌کند:



ارسال خودکار بسته‌ی نیوگت تولید شده به سایت nuget.org

برای ارسال خودکار حاصل Build، به سایت نیوگت، نیاز است یک API Key داشته باشیم. به همین جهت به صفحه‌ی مخصوص آن در سایت nuget پس از ورود به سایت آن، مراجعه کرده و یک کلید API جدید را صرفا برای این پروژه تولید کنید (در قسمت Available Packages بسته‌ی پیشینی را که دستی آپلود کرده بودید انتخاب کنید).
پس از کپی کردن کلید تولید شده‌ی در سایت nuget، به قسمت settings -> deployment مراجعه کرده و یک تامین کننده‌ی جدید از نوع nuget را اضافه کنید:


در اینجا API Key را ذکر خواهیم کرد. سپس در پایین صفحه بر روی دکمه‌ی Save کلیک کنید.

همچنین نیاز است مشخص کنیم که بسته‌های nupkg تولید شده در چه مسیری قرار دارند. به همین جهت در قسمت settings -> artifacts مسیر پوشه‌ی bin نهایی را ذکر می‌کنیم:


این مورد را نیز با کلیک بر روی دکمه‌ی Save ذخیره کنید.

اکنون اگر نگارش جدیدی را به GitHub ارسال کنیم (تغییر VersionPrefix در فایل csproj و سپس commit آن)، پس از Build پروژه، بسته‌ی نیوگت آن نیز به صورت خودکار تولید شده و به سایت nuget.org ارسال می‌شود. لاگ آن‌را در پایین صفحه‌ی برگه‌ی latest build می‌توانید مشاهده کنید.



ساده سازی مراحل تنظیمات AppVeyor

در صفحه‌ی settings‌، در منوی سمت چپ آن، گزینه‌ی export YAML نیز وجود دارد. در اینجا می‌توان تمام تنظیمات انجام شده‌ی فوق را با فرمت yml. دریافت کرد و سپس این فایل را به ریشه‌ی مخزن کد خود افزود. با وجود این فایل، دیگر نیازی به طی کردن دستی هیچکدام از مراحل فوق نیست.
برای نمونه فایل appveyor.yml نهایی مطابق با توضیحات این مطلب، چنین محتوایی را دارد:
version: 1.0.{build}
image: Visual Studio 2017
dotnet_csproj:
  patch: true
  file: '**\*.csproj'
  version: '{version}'
  package_version: '{version}'
  assembly_version: '{version}'
  file_version: '{version}'
  informational_version: '{version}'
cache: C:\Users\appveyor\.dnx
build_script:
- cmd: >-
    cd ./src/DNTPersianUtils.Core

    dotnet restore

    dotnet pack -c release

    cd ../..
test_script:
- cmd: >-
    cd ./src/DNTPersianUtils.Core.Tests

    dotnet restore

    dotnet test

    cd ../..
artifacts:
- path: ./src/DNTPersianUtils.Core/bin/release/*.nupkg
  name: NuGet
deploy:
- provider: NuGet
  api_key:
    secure: xyz
  skip_symbols: true
notifications:
- provider: Email
  to:
  - me@yahoo.com
  on_build_success: false
  on_build_failure: true
  on_build_status_changed: true
بنابراین بجای طی مراحل عنوان شده‌ی در این بحث می‌توانید یک فایل appveyor.yml را با محتوای فوق (پس از اصلاح مسیرها و نام‌ها) در ریشه‌ی پروژه‌ی خود قرار دهید و ... صرفا مخزن کد آن‌را در appveyor ثبت و import کنید. مابقی مراحل یکپارچگی مداوم آن خودکار است و نیاز به تنظیم دیگری ندارد. فقط برای آزمایش آن به برگه‌ی Latest build مراجعه کرده و یک build جدید را شروع کنید تا مطمئن شوید همه چیز به درستی کار می‌کند.
یک نکته: api_key ذکر شده‌ی در اینجا در قسمت secure، رمزنگاری شده‌است. برای تولید آن می‌توانید از مسیر https://ci.appveyor.com/tools/encrypt استفاده کنید. به این صورت مشکلی با عمومی کردن فایل appveyor.yml خود در GitHub نخواهید داشت.
مطالب
Gulp #3
در قسمت اول گالپ را معرفی کردیم و در مقاله قبلی به نوشتن اولین تسک با گالپ پرداختیم. در این قسمت می‌خواهیم با نصب bower، پروژه‌ی workflow بوت استرپ راستچین شده را انجام دهیم.

نصب bower



bower یک مدیریت پکیج سمت Front end است و از مزیای استفاده از آن می‌توان به موارد زیر اشاره کرد:
  • ساده کردن تعریف وابستگی‌های منابع پروژه با تعریف یک فایل bower.json
  • نیازی به commit کردن واستگی‌های پروژه نیست.
  • با ذکر ورژن مربوط به وابستگی یا محدوده‌ی قابل قبول برای آن، به روز رسانی منابع به سادگی با یک دستور انجام می‌شود.
  • وابستگی های وابسته به یک منبع  را نیز نصب می‌کند. برای مثال زمانیکه بوت استرپ را به عنوان وابستگی پروژه تعریف می‌کنیم، وابستگی آن یعنی jquery را چون در فایل bower.json بوت استرپ تعریف شده‌است، به صورت خودکار دانلود می‌کند.
  • در نهایت افراد هم تیمی یا توسعه دهندگان دیگر به راحتی با زدن دستور bower install تمام وابستگی‌های پروژه را می‌توانند نصب کنند.
برای نصب آن کافی است دستور زیر را بزنید و بعد از نصب نیز دستور خط دوم را در مسیر پروژه وارد کنید تا یک فایل bower.json را برایمان بسازد. برای اینکار به سوال‌هایی که می‌پرسد باید جواب دهیم. تنها نکته‌ای که قابل ذکر است، پاسخ به سوال ? what types of modules does this package expose است که باید گزینه‌ی Node را انتخاب کنید. 
sudo npm install -g bower
bower init
حال می‌خواهیم وابستگی‌های پروژه را نصب کنیم که عبارتند از bootstrap-sass,fontawesome,bootstrap-rtl :
bower install bootstrap-sass-official --save  
bower install fontawesome --save
bower install bootstrap-rtl --save
نکته : عبارت save-- وابستگی مربوطه را به bower.json اضافه می‌کند. اگر نصب با موفقیت صورت گرفته باشد، پکیج‌های مربوطه را می‌توانید در فولدر bower_components در root پروژه مشاهده کنید.

نصب پلاگین‌های مورد نیاز gulp

ما می‌خواهیم که بوت استرپ و نگارش sass آن‌را کامپایل کنیم و همچنین وابستگی‌های bower پروژه را از طریق گالپ نصب کنیم تا نیازی به زدن bower install نباشد و توسعه دهنده‌ی پروژه فقط با زدن npm install، تمام وابستگی‌های پروژه‌ی ما را نصب کند. می‌توان تمام پلاگین‌ها را پشت سر هم با یک دستور نصب کرد و یا به صورت جداگانه این کار را انجام داد.
sudo npm install gulp gulp-ruby-sass gulp-notify gulp-bower --save-dev
نکته۱:پلاگین gulp-notify به منظور نشان دادن خطاها در ترمینال است؛ تا در صورت وجود اشتباه در کامپایل فایل‌های Sass، کل روند گالپ متوقف نشود.
نکته ۲ : برای اینکه کامپایل sass انجام شود نیاز به Ruby دارید. برای ویندوز می‌توانید از روبی اینستالر استفاده کنید.

نوشتن تسک‌ها برای گالپ

به قسمت مهم و هیجان انگیز کار رسیدیم! همان طور در مقاله قبلی گفتیم، ابتدا باید ماژول‌هایی را که نصب کردیم، include کنیم به این صورت:
var gulp = require('gulp'),
    sass = require('gulp-ruby-sass'),
    notify = require('gulp-notify'),
    bower = require('gulp-bower');
برای اینکه دسترسی به مسیر‌های مهم پروژه آسان‌تر شود، آن‌ها را درون یک شیء نگه داری می‌کنیم.
var config = {
    sassPath = './resources/sass',
    bowerDir = './bower_components'
}
تسک باور را اضافه می‌کنیم تا کار bower install را خودکار کنیم. مزیت این کار این است اگر یک هم تیمی، پکیج جدیدی را در حین توسعه‌ی پروژه نصب کرد، بدون اینکه لازم باشد تا در جایی از پروژه، بقیه را از آن مطلع کنید، فقط با زدن gulp خیالتان راحت شود که تمام کارهایی که باید انجام دهید، گالپ برایتان انجام می‌دهد.
// create a task to do bower install
gulp.task('bower', function() {
    return bower()
      .pipe(gulp.dest(config.bowerDir))
});
در گام بعدی، تسک جاوا اسکریپت را اضافه می‌کنیم. یعنی جی کوری و فایل bootstrap.js را به مسیر public/js می‌آوریم. فولدر public برای جدا سازی فایل‌های نهایی از فایل‌های توسعه است و به همین صورت برای فونت آیکن‌های fontawesome.

// Copy js files to public folder
gulp.task('js', function() {
    return gulp.src([config.bowerDir + '/bootstrap-sass-official/assets/javascripts/bootstrap.min.js',
                    config.bowerDir + '/jquery/dist/jquery.min.js'
            ])
        .pipe(gulp.dest('./public/js'));

});

// Copy fontawesome icons to public/fonts folder
gulp.task('icons', function() {
    return gulp.src(config.bowerDir + '/fontawesome/fonts/**.*')
        .pipe(gulp.dest('./public/fonts'));
});

:برای سی اس اس هم تسک مربوطه‌اش را به صورت زیر می‌نویسیم

gulp.task('css', function() {
    return sass(config.sassPath + '/style.scss', { // Our coustom sass
      style: 'compressed',  // minify css
      loadPath: [ // load paths to easy use import in resources/sass
        './resources/sass',
        config.bowerDir + '/bootstrap-sass-official/assets/stylesheets', // bootstrap sass files
        config.bowerDir + '/fontawesome/scss' // awesome icons sass files
      ]
    })
});
 حال تعریف می‌کنیم که اگر خطایی در حین کامپایل رخ داد، آن را به ما نشان دهد و در نهایت فایل کامپایل و فشرده شده را در مسیر خروجی قرار می‌دهیم. کد‌ها را به صورت زیر به روز می‌کنیم
gulp.task('css', function() {
    return sass(config.sassPath + '/style.scss', { // Our coustom sass
      style: 'compressed',  // minify css
      loadPath: [ // load paths to easy use import in resources/sass
        './resources/sass',
        config.bowerDir + '/bootstrap-sass-official/assets/stylesheets', // bootstrap sass files
        config.bowerDir + '/fontawesome/scss' // awesome icons sass files
      ]
    })
        .on('error', notify.onError(function(error) {
            return 'Error: ' + error.message;
        }))
      .pipe(gulp.dest('./public/css'));
});
اینجا ما می‌خواهیم که کار‌ها را خودکار سازی کنیم تا با تغییر و ذخیره‌ی مجدد فایل‌های سس، تسک سی اس اس را انجام دهد. برای این کار کد‌های زیر را اضافه می‌کنیم
// Rerun the task when a file changes
gulp.task('watch', function() {

    gulp.watch(config.sassPath + '/**/*.scss', ['css']); 

});
در نهایت برای سادگی می‌توانیم مجموعه‌ای از وظایف را در یک تسک تعریف کنیم تا به راحتی و با زدن تنها یک دستور در ترمینال، کار‌ها خودکار سازی شوند
// Run this task with :  gulp
// OR gulp default
gulp.task('default', ['bower', 'icons', 'css','js']);

بسیار خوب؛ ما توانستیم پایه‌ی ورک فلو یمان را بسازیم. در مقاله‌ی بعدی از پلاگین‌های دیگری برای بهینه سازی کارهایمان کمک خواهیم گرفت

مخزن گیت هاب 
مطالب
Resource Governor در 2008 SQL Server
مقدمه
Resource  Governor، اجازه می‌دهد تا انواع مختلف Session را بر روی Server طبقه بندی کنید که به نوبه خود چگونگی کنترل تخصیص منابع سرور به فعالیت داده شده را به شما اعطا می‌کند. این قابلیت کمک می‌کند که ادامه فرآیند‌های OLTP تضمین شود و یک عملکرد قابل پیش بینی فراهم می‌کند تا توسط فرآیند‌های غیر قابل پیش بینی، تحت تاثیر منفی قرار نگیرد. با استفاده از Resource  Governor، قادر خواهید بود نحوه دستیابی به Session را به منظور محدود کردن منابع خاص برای SQL Server مشخص کنید. به عنوان مثال می‌توانید مشخص کنید که بیش از 20 درصد از پردازنده یا منابع حافظه به گزارش‌های در حال اجرا اختصاص داده نشود. هنگامیکه این ویژگی فعال باشد، مهم نیست چه تعداد گزارش در حال اجرا است، آنها هرگز نمی‌توانند از تخصیص منابع تعیین شده تجاوز کنند. البته این موضوع عملکرد گزارش گیری را کاهش می‌دهد ولی عملکرد فرآیند‌های OLTP حداقل توسط گزارش ها، دیگر تحت تاثیر منفی قرار نمی‌گیرد.

1- بررسی اجمالی Resource Governor:

Resource Governor، با کنترل تخصیص منابع بر حسب Workload کار می‌کند. هنگامی که یک درخواست اتصال به موتور بانک اطلاعاتی ارسال می‌شود درخواست براساس یک تابع رده بندی (Classification function) طبقه بندی می‌شود. تابع رده بندی یک تابع اسکالر است که از طریق T-SQL تعریف می‌شود. تابع رده بندی، اطلاعات را درباره یک اتصال (برای مثال  login ID، application name، hostname، server role ) ارزیابی می‌کند، به منظور تشخیص اینکه چگونه آنها را دسته بندی کند. پس از دسته بندی درخواست اتصال، آنها به گروه‌های حجم کاری (Workload Group) که برای رده بندی تعریف شده اند، شکسته می‌شوند. هر Workload Group مرتبط با یک مخزن منابع (Resource Pool) است.
یک Resource Pool، منابع فیزیکی SQL Server را نمایش می‌دهد (در حال حاضر در SQL Server 2008، تنها منابع فیزیکی موجود برای پیکربندی پردازنده و حافظه است) و مقدار حداکثر پردازنده و یا منابع حافظه را که به نوع خاصی از Workload اختصاص داده می‌شود، تعیین می‌کند. هنگامی که یک اتصال طبقه بندی شده و در Workload Group صحیح خود قرار می‌گیرد به این اتصال، پردازنده و منابع حافظه به اندازه نسبت داده شده به آن تخصیص داده می‌شود و سپس Query به Query Optimizer برای اجرا داده می‌شود. 

2-  اجزای Resource Governor:
Resource Governor، از سه قسمت اصلی تشکیل شده است: Classification، Workload Groups و Resource Pools. درک این سه قسمت و چگونگی تعامل آنها به درک و استفاده از Resource Governor کمک می‌کند.

2-1- Classification:
Classification، فرآیند ارزیابی اتصالات ورودی کاربر و اختصاص آن به یک Workload Group است که توسط منطق موجود در یک تابع تعریف شده توسط کاربر (user-defined function) انجام می‌شود. تابع نام یک Workload Group را برمی گرداند که Resource Governor از آن برای مسیر دهی Session به Workload Group مناسب استفاده می‌کند.
هنگامی که Resource Governor پیکربندی می‌شود فرآیند ورود به سیستم برای یک Session شامل گام‌های زیر است:
• Login authentication
• LOGON trigger execution
• Classification
2-2- Workload Groups:
Workload Groups، ظروفی برای اتصالات مشابه هستند که با توجه به معیارهای طبقه بندی برای هر اتصال گروه بندی می‌شوند. Workload Groups همچنین مکانیسمی برای تجمیع نظارت بر روی منابع مصرفی فراهم می‌کند.
Resource Governor دو Workload Group از پیش تعریف شده دارد: یک گروه داخلی (internal group) و یک گروه پیش فرض (default group).
 Internal Workload Group، تنها توسط فرآیندهای داخلی موتور بانک اطلاعاتی استفاده می‌شود. معیارهای طبقه بندی را برای گروه‌های داخلی نمی‌توانید تغییر دهید و همچنین هیچ یک از درخواست‌های کاربران را برای انتقال به گروه داخلی نمی‌توانید رده بندی کنید، با این حال بر گروه  داخلی می‌توانید نظارت کنید.
درخواست‌های اتصال به طور خودکار هنگامی که شرایط زیر وجود دارد، به  Default Workload Group رده بندی می‌شوند:
• معیاری برای طبقه بندی درخواست وجود ندارد.
• کوششی برای رده بندی درخواستی به گروهی که وجود ندارد.
• خرابی کلی Classification
Resource Governor، در مجموع 20 عدد Workload Group را پشتیبانی می‌کند. از آنجائی که دو عدد از آنها برای Workload Group‌های داخلی و پیش فرض ذخیره شده اند در مجموع 18 عدد Workload Group تعریف شده توسط کاربر (user-defined) می‌توان تعریف نمود.

2-3- Resource pools:
Resource Pool (مخزن منابع)، نشان دهنده تخصیص منابع فیزیکی به SQL Server است. یک Resource Pool از دو بخش تشکیل شده است:
• در بخش نخستین حداقل رزرو منابع را مشخص می‌کنیم، این بخش از مخزن منابع با مخازن دیگر همپوشانی نمی‌کند.
• در بخش دیگر حداکثر ممکن رزرو منابع را برای مخزن مشخص می‌کنیم، تخصیص منابع با مخازن دیگر مشترک است.
در 2008 SQL Server مخزن منابع با تعیین حداقل و حداکثر تخصیص CPU و حداقل و حداکثر تخصیص حافظه تنظیم می‌گردد. با تنظیم حداقل، در دسترس بودن منبع از مخزن تضمین می‌شود. از آنجائی که در هر رزرو حداقل منابع تداخلی نمی‌تواند وجود داشته باشد، مجموع مقادیر حداقل در تمام مخازن از 100% کل منابع Server نمی‌تواند تجاوز کند.
مقدار حداکثر در محدوده بین حداقل و شامل 100% مقدار می‌تواند تنظیم گردد. تنظیم حداکثر نشان دهنده مقدار حداکثری است که یک Session می‌تواند مصرف کند، مادامی که منابع در دسترس باشند و توسط مخزن دیگر که با حداقل مقدار غیر صفر پیکربندی شده، استفاده نشود. هنگامی که یک مخزن با حداقل مقدار غیر صفر تعریف شده، مقدار حداکثر موثر از مخزن‌های دیگر دوباره تنظیم می‌شوند، در صورت لزوم حداکثر مقدار موجود از جمع کل حداقل منابع مخازن دیگر کسر می‌گردد.
برای مثال، دو مخزن تعریف شده توسط کاربر (user-defined) را در نظر بگیرید. مخزن اول Pool1 با مقدار حداقل 20% و مقدار حداکثر 100% تعریف شده، مخزن دیگری Pool2 با مقدار حداقل 50% و مقدار حداکثر 70% تعریف شده است. حداکثر مقدار موثر برایPool1 برابر 50% است (100% منهای مقدار حداقل 50% مخزن Pool2) و حداکثر مقدار موثر برای Pool2، 70% است زیرا حداکثر مقداری است که پیکربندی شده است، گر چه 80% باقی می‌ماند.
بخش مشترکی از مخزن (مقدارش بین مقدار حداقل و مقدار حداکثر موثر است) که برای تعیین مقدار منابع مورد استفاده است، توسط مخزن می‌تواند مصرف شود اگر منابعی موجود باشد و توسط مخازن دیگر مصرف نشده باشد. هنگامی که منابعی توسط یک مخزن مصرف می‌شوند، آنها به یک مخزن مشخص نسبت داده می‌شوند، به بیان دیگر اشتراکی نیستند تا زمانی که فرآیند در آن مخزن به اتمام برسد.
برای توضیح بیشتر یک سناریو که در آن سه مخزن تعریف شده توسط کاربر (user-defined) وجود دارد، را در نظر بگیرید:
PoolA با حداقل مقدار 10% و حداکثر مقدار 100% تعریف می‌شود.
PoolB با حداقل مقدار 35% و حداکثر مقدار 90% تعریف می‌شود.
PoolC با حداقل مقدار 30% و حداکثر مقدار 80% تعریف می‌شود.
مقدار موثر PoolA و مجموع در صد منابع به اشتراک گذاشته PoolA به شرح زیر محاسبه خواهد شد:
( حداکثر مقدار PoolA ) -  ( حداقل مقدار PoolB ) -  ( حداقل مقدار PoolC ) =  ( حداکثر مقدار موثر PoolA )
(حداکثر مقدار موثر PoolA ) –  ( حداقل مقدار PoolA ) = ( اشتراک PoolA )
جدول زیر مقدار حداکثر موثر و اشتراکی را برای هر مخزن در این پیکربندی نمایش می‌دهد:



  Internal Pool، منابع مصرف شده توسط فرآیندهای داخلی موتور بانک اطلاعاتی را نشان می‌دهد. این مخزن تنها شامل گروه‌های داخلی است و به هیچ وجه قابل تغییر نیست. مخزن داخلی مقدار ثابت حداقل صفر و حداکثر 100% را دارد و مصرف منابع توسط مخزن داخلی، از طریق تنظیمات در هر مخزن دیگر محدود یا کاسته نمی‌شود.
به عبارت دیگر حداکثر مقدار موثر مخزن داخلی همیشه 100% است. هر workloads در مخزن داخلی برای عملکرد Server حیاتی در نظر گرفته می‌شود و Resource Governor در صورت لزوم اجازه می‌دهد تا مخازن داخلی 100% منابع موجود را مصرف کند حتی اگر به معنی نقض نیازمندیهای منابع از سایر مخازن باشد.
Default Pool، اولین مخزن تعریف شده کاربر است. قبل از هرگونه پیکربندی، Default Pool تنها حاوی Default group است. Default Pool نمی‌تواند ایجاد یا حذف شود اما می‌تواند تغییر کند. Default Pool علاوه بر Default group می‌تواند شامل گروه‌های تعریف شده توسط کاربر (user-defined) نیز باشد.

3- پیکر بندی Resource Governor :
پیکربندی Resource Governor شامل مراحل زیر است:
- فعال کردن Resource Governor
- ایجاد مخازن منابع (Resource Pools) تعریف شده توسط کاربر (user-defined)
- تعریف Workload Groups و نسبت دادن آن به مخازن
- ایجاد Classification function
- ثبت Classification function به Resource Governor
3-1-  فعال کردن Resource Governor
پیش از اینکه بتوانید یک Resource Pool را ایجاد کنید، نیاز است تا نخست Resource Governor را فعال کنید.

3-2-  تعریف Resource Pool

ویژگی‌های موجود برای یک Resource Pool عبارتند از:
Name، Minimum CPU %، Maximum CPU%، Min Memory%، Max Memory%

3-3-  تعریف Workload Group 

پس از اینکه Resource Pool را تعریف کردید، گام بعدی ایجاد یک Workload Group و اختصاص آن به Resource Pool مناسب است. چندین workgroup را می‌توان به مخزن (Pool) یکسان نسبت داد اما یک workgroup را به چندین Resource Pool نمی‌توان نسبت داد. خواص انتخابی موجود برای Workload Groups به شما اجازه می‌دهد سطح بهتری از کنترل را روی اجرای دستورات یک Workload Group تنظیم کنید. انتخاب‌های موجود عبارتند از:
3-3-1- Importance :
اهمیت نسبی (کم، متوسط یا بالا) Workload Group درون Resource Pool را تعیین می‌کند. اگر چندین Workload Group را در یک Resource Pool تعریف کنید این تنظیمات تعیین می‌کند که درخواست‌ها در عرض یک Workload Group در اولویت بالاتر یا پائین‌تری از Workload Group‌های دیگر درون همان Resource Pool اجرا شوند، مقدار متوسط تنظیم پیش فرض است. در حال حاضر فاکتورهای وزنی برای هر تنظیم کم برابر 1، متوسط برابر3 و زیاد برابر 9 است. به این معنی که زمانبند به اجرای Session‌های درون workgroup هائی با اهمیت بالا، سه برابر بیشتر از workgroup‌های با اهمیت متوسط و نه برابر بیشتر از workgroup‌های کم اهمیت، مبادرت خواهد کرد.
3-3-2- Maximum Request  :
حداکثر تعداد درخواست‌های همزمان که اجازه دارند در یک Workload Group اجرا شوند را مشخص می‌کند. تنظیم پیش فرض، صفر، تعداد نامحدود دستور را اجازه می‌دهد.
3-3-3-  CPU Time :
حداکثر مقدار زمان پردازنده در ثانیه را مشخص می‌کند که یک درخواست درون Workload Group می‌تواند استفاده کند. تنظیم پیش فرض، صفر، به معنی نامحدود است.
3-3-4- Memory Grant %:
به صورت در صد، حداکثر مقدار اعطا حافظه برای اجرا (Execution grant memory)، که یک تک دستور از Resource Pool می‌تواند اخذ کند را مشخص می‌کند. این درصد نسبی است از مقدار حافظه ای که به Resource Pool نسبت داده می‌شود. محدوده مجاز مقادیر از 0 تا 100 است. تنظیم پیش فرض 25 است.
 Execution grant memory، مقدار حافظه ای است که برای اجرای query استفاده می‌شود (نه برای Buffer کردن یا cache کردن) که می‌تواند صرفه نظر از Resource Pool یا Workload Group توسط تعدادی از Session‌ها به اشتراک گذاشته شود. توجه شود که تنظیم این مقدار به صفر از اجرای عملیات Hash Join و دستورات مرتب سازی در Workload Group‌های تعریف شده توسط کاربر (user-defined)جلوگیری می‌کند. همچنین این مقدار توصیه نمی‌شود بیشتر از 70 باشد زیرا ممکن است Server قادر نباشد، اگر Query‌های همزمان در حال اجرا باشند، حافظه آزاد کافی اختصاص دهد.
3-3-5- Grant Time-out :
حداکثر زمان، به ثانیه، که یک query برای یک منبع منتظر می‌ماند تا در دسترس شود را مشخص می‌کند. اگر منبع در دسترس نباشد، فرآیند ممکن است با یک خطای time-out مواجه شود. تنظیم پیش فرض، صفر، به معنی این است که سرور time-out را با استفاده از محاسبات داخلی بر مبنای هزینه پرس و جو ( query cost ) با تعیین حداکثر زمان برآورد می‌کند.
3-3-6- Degree of Parallelism  :
حداکثر درجه موازی سازی (DOP) را برای پرس و جو‌های موازی تعیین می‌کند. محدوده مجاز مقادیر از 0 تا 64 است. تنظیم پیش فرض، صفر، به معنی این است که فرآیند‌ها از تنظیمات عمومی استفاده می‌کنند.

3-4- ایجاد یک Classification function
پس از تعریف Resource Pool و Workload Group، به یک Classification function نیاز است که شامل منطق ارزیابی اتصالات و نسبت دادن آنها به Workload Group مناسب است. Classification function برای هر اتصال Session جدید به SQL Server بکار می‌رود. هر Session در Workload Group نسبت داده شده به آن باقی می‌ماند تا زمانی که به پایان برسد، مگر اینکه صراحتاً به یک گروه متفاوت دوباره نسبت داده شود. فقط یک Classification function فعال در هر زمان می‌تواند وجود داشته باشد. در صورت عدم تعریف شدن یا عدم فعال بودن Classification function همه اتصالات به Workload Group Default نسبت داده می‌شوند. Classification function یک نام workgroup که نوع آن SYSNAME است (که یک نام مستعار برای دیتا تایپ nvarchar 128 است.) برمی گرداند. اگر تابع تعریف شده مقدار 'NULL ،'Default یا نام گروهی که وجود ندارد را برگرداند، Session به Workload Group Default نسبت داده می‌شود. همچنین اگر به هر دلیلی تابع با موفقیت خاتمه نیابد Session به Workload Group Default نسبت داده می‌شود.
منطق Classification function معمولاً مبتنی بر ویژگی‌های اتصال است و اغلب از طریق مقدار بازگشتی توابع سیستمی از قبیل:
 ()SUSER_NAME() ،SUSER_SNAME() ،IS_MEMBER() ،IS_SERVERROLEMEMBER() ،HOST_NAME و یا ()APP_NAME، نام Workload Group اتصال مشخص می‌شود. علاوه بر این توابع می‌توانید از ویژگی‌های توابع دیگر برای ساخت منطق رده بندی  استفاده کنید. تابع ()LOGINPROPERTY شامل دو  ویژگی (DefaultDatabase و DefaultLanguage) می‌باشد  که می‌تواند برای Classification function استفاده شود. بعلاوه تابع ()CONNECTIONPROPERTY پروتکل‌ها و دسترسی به نقل و انتقالات در شبکه، همچنین جزئیات طرح احراز هویت،  Local IP address و  TCP Port و Client’s IP Address را برای استفاده اتصالات فراهم می‌کند. برای مثال می‌توانید برای یک اتصال، یک Workload Group نسبت دهید، مبتنی بر اینکه subnet یک اتصال ازکجا می‌آید.
نکته: اگر قصد دارید از هر یک از توابع ()HOST_NAME و یا ()APP_NAME در تابع رده بندی تان استفاده کنید، توجه داشته باشید این امکان وجود دارد مقادیر بازگردانده شده توسط این توابع توسط کاربران تغییر داده شوند، گر چه به طور کلی گرایش به استفاده از تابع ()APP_NAME برای رده بندی اتصالات بیشتر است.
 
4- بررسی نمونه ای از پیکربندی Resource Governor
برای سادگی، در این قسمت مثالی ارائه می‌شود که از تابع ()SUSER_NAME استفاده می‌کند: در گام نخست، دو Resource Pool ایجاد می‌شود (  ReportPool و OLTPPool ) 

  

در گام بعدی، دو Workload Group ایجاد می‌شود ( ReportWG1 و OLTPWG1 ) 

سپس دو Login ایجاد می‌شود ( report_user و oltp_user ) که در تابع رده بندی استفاده خواهند شد برای مشخص کردن این که اتصالات Seesion به کدام  Workload Group نسبت داده شوند. پس از اضافه کردن Login‌ها به عنوان User‌ها به Database مورد نظر مان، در بانک اطلاعاتی Master تابع رده بندی (Classification function ) را ایجاد می‌کنیم:  

می توان تابع ()WorkgroupClassifier را در محیط SSMS با اجرای دستور زیر برای Login‌های متفاوت تست نمود: 

در  ادامه دستور زیر برای پیکربندی تابع رده بندی به Resource Governor استفاده می‌شود: 


5- اصلاح پیکربندی Resource Governor:
می‌توانید درمحیط SSMS تنظیمات Resource Pool و Workload Group را تغییر دهید ( برای مثال حداکثر استفاده CPU برای یک Resource Pool و یا درجه اهمیت یک Workload Group). متناوباً می‌توان از دستورات T-SQL استفاده نمود.
نکته: پس از اجرای دستورات ALTER RESOURCE POOL یا ALTER WORKLOAD GROUP، برای اعمال کردن تغییرات اجرای دستور ALTER RESOURCE GOVERNOR RECONFIGURE نیاز می‌باشد.
5-1-  حذف Workload Group :
یک Workload Group را اگر هر نوع Session فعال نسبت داده شده به آن وجود داشته باشد، نمی‌توان حذف نمود. اگر یک Workload Group شامل Sessionهای فعال باشد، حذف Workload Groupو یا جابجائی آن به یک Resource Pool متفاوت، هنگامی که دستور ALTER RESOURCE GOVERNOR RECONFIGURE برای اعمال نمودن تغییرات فراخوانی می‌شود، با خطا مواجه خواهد شد.
5-2-  حذف Resource Pools:
یک Resource Pool را اگر هر نوع Workload Group نسبت داده شده به آن وجود داشته باشد، نمی‌توان حذف نمود. نخست نیاز دارید Workload Group حذف شود و یا به Resource Pool دیگری جابجا گردد.
5-3-  اصلاح Classification function:
اگر نیاز دارید تغییراتی در تابع رده بندی ایجاد نمائید، مهم است توجه داشته باشید که تابع رده بندی تا زمانی که مشخص شده (marked) برای Resource Governor است، نمی‌توان آنرا حذف و یا تغییر داد. پیش از اینکه بتوان تابع رده بندی را اصلاح و یا حذف نمود نخست نیاز دارید Resource Governor را غیر فعال نمائید. متناوباً می‌توان تابع رده بندی را جایگزین کرد با اجرای دستور ALTER RESOURCE GOVERNOR و فرستادن (passing) یک اسم متفاوت برای CLASSIFIER_FUNCTION،همچنین می‌توان با اجرای دستور زیر تابع رده بندی جاری را غیر فعال نمود:

تابع رده بندی می‌توان تعریف کرد که نام Workload Group را از جداول یک بانک اطلاعاتی جستجو کند به جای اینکه نام Workload Group به صورت hard-coding و مطابق با ضوابط درون تابع باشد. عملکرد،  در موقع دسترسی به جدول برای جستجو کردن نام Workload Group، نباید تا حد زیادی تحت تاثیر قرار گیرد. 

6- نظارت بر Resource Governor
با استفاده از Performance Monitor، events و (Dynamic Management View (DMV  می‌توان Workload Group و Resource Pool را نظارت (Monitor) کرد. دو شی Performance برای این کار موجود است: SQL Server:Workload Group Stats و SQL Server:Resource Pool Stats
شکل زیر مربوط به پیکر بندی مثال مورد نظرمان می‌باشد:
 

7- نتیجه گیری
Resource Governor چندین مزیت بالقوه ارائه می‌دهد، در درجه اول قابلیت اولویت بندی منابع Server برای کاربران و برنامه‌های کاربردی (applications) بحرانی، جلوگیری از “runaway” یا درخواست‌های غیر منتظره ای که به شدت و بطور قابل توجهی روی کارائی Server تاثیر منفی می‌گذارند.
ضمناً Resource Governor چندین مشکل بالقوه نیز عرضه می‌کند، برای مثال پیکربندی اشتباه Resource Governor تنها به عملکرد کلی Server آسیب نمی‌رساند بلکه به طور بالقوه روی سرور قفل (Lock) می‌تواند ایجاد کند و نیاز به استفاده از اتصال اختصاصی Administrator برای متصل شدن به SQL Server به منظور اشکال یابی و رفع مشکل  می‌باشد. بنابراین توصیه شده است که تنها در صورتی که DBA با تجربه ای هستید و درک خوب و آشنائی خوبی با Workload هائی که روی بانک اطلاعاتی اجرا می‌شوند دارید، Resource Governor را بکار برید. حتی در این صورت، ضروری است که پیکربندی تان را روی یک Server تستی پیش از اینکه روی محیط تولیدی بگسترانید، تست نمائید.
Resource Governor به عنوان یک ویژگی با نام تجاری جدید در SQL Server 2008، با تعدادی محدودیت همراه است که احتمالاً در نسخه‌های بعدی SQL Server حذف خواهد شد، از محدودیت های  بارز :
- محدودیت منابع (Resource)، که به CPU و حافظه محدود می‌شوند. I/O Disk و منابع شبکه را در  SQL Server 2008 نمی‌توان محدود کرد.
- استفاده از منابع برای Reporting Service، Analysis Service و Integeration Service را نمی‌توان محدود کرد . در این نسخه محدودیت‌های منابع تنها روی هسته موتور بانک اطلاعاتی بکار برده می‌شود.
- محدودیت‌های Resource Governor روی یک SQL Instance تعریف و بکار برده می‌شود.

مطالب
آموزش فایرباگ - #4 - JavaScript Development
در قسمت قبل با توابع خط فرمان آشنا شدیم . در این قسمت با توابع کنسول آشنا خواهیم شد .

فایرباگ یک متغییر عمومی به نام console دارد که به همه‌ی صفحات باز شده در فایرفاکس اضافه می‌کند . این شیء متدهایی دارد که بوسیله آن‌ها می‌توانیم عملیاتی در برنامه مان انجام داده و اطلاعاتی را در کنسول چاپ کنیم .

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

توابع کنسول - Console API :

توجه : همانند قسمت قبل ، در این قسمت هم برای همراه شدن با تست‌ها ، کد صفحه‌ی زیر را ذخیره کنید و برای اجرای کدها ، آن‌ها را در قسمت خط فرمان ( در تب کنسول ) قرار بدهید و دکمه‌ی Run ( یا Ctrl + Enter ) را بزنید .
<input type="button" onclick="startTrace('Some Text')" value="startTrace" />
<input type="button" onclick="startError()" value="test Error" />

<script type="text/javascript">
    function startTrace(str) {
        return method1(100, 200);
    }
    function method1(arg1, arg2) {
        return method2(arg1 + arg2 + 100);
    }
    function method2(arg1) {
        var var1 = arg1 / 100;
        return method3(var1);
    }
    function method3(arg1) {
        console.trace();
        var total = arg1 * 100;
        return total;
    }

    function testCount() {
        // do something
        console.count("testCount() Calls Count .");
    }

    function startError() {
        testError();
    }

    function testError() {
        var errorObj = new Error();
        errorObj.message = "this is a test error";
        console.exception(errorObj);
    }

    function testFunc() {
        var t = 0;
        for (var i = 0; i < 100; i++) {
            t += i;
        }
    }
</script>
  • console.log(object[,object,...])

    این دستور یک پیغام در کنسول چاپ می‌کند .
    console.log("This is a log message!");
    نتیجه :



    این دستور را می‌توانیم به شکل‌های مختلفی فراخوانی کنیم .
    مثلا :
    console.log(1 , "+" , 2 , "=", (1+2));
    نتیجه :


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


    مثال :

    console.log("Firebug 1.0 beta was %s in December %i.","released",2006);
    نتیجه :


    عملکرد 3 جایگزین نخست با توجه با مثال قبل مشخص شد . پس به سراغ جایگزین %o و %c می‌رویم .
    اگر در رشته‌ی مورد نظر ، یک شیء ( تابع ، آرایه ، ... ) برای جایگزین %o ارسال کنیم ، در خروجی آن شیء بصورت لینک نمایش داده می‌شود که با کلیک بروی آن ، فایرباگ آن شیء را در تب مناسبش Inspect می‌کند .
    مثال :
    console.log("this is a test functin : %o",testFunc);

    نتیجه :



    و زمانی که بروی لینک testFunc کلیک کنیم :



    یک ترفند : بوسیله جایگزین %o توانستیم به تابع مورد نظر لینک بدهیم . اگر بجای جایگزین %o از %s استفاده کنیم ، می‌توانیم بدنه‌ی تابع را ببینیم :
    console.log("this is a test functin : %s",testFunc);
    نتیجه :




    توسط جایگزین %c هم می‌توانید خروجی را فرمت کنید .

    console.log("%cThis is a Style Formatted Log","color:green;text-decoration:underline;");

    نتیجه :


  • console.debug(object[, object, ...])
  • console.info(object[, object, ...])
  • console.warn(object[, object, ...])
  • console.error(object[, object, ...])

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



  • console.assert(expression[, object, ...])

    چک می‌کند که عبارت ارسال شده true هست یا نه . اگر true نبود ، پیغام وارد شده را چاپ و یک استثناء ایجاد می‌کند .
    console.assert(1==1,"this is a test error");
    console.assert(1!=1,"this is a test error");

    نتیجه :



  • console.clear()
  • console.dir(object)
  • console.dirxml(node)
  • console.profile([title])
  • console.profileEnd()

  • این توابع معادل توابع همنامشان در خط فرمان هستند که در قسمت قبل با عملکردشان آشنا شدیم .

  • console.trace()

    با این متد می‌توانید پی ببرید که از کجا و توسط چه متدهایی برنامه به قسمت trace رسیده . برای درک بهتر مجددا اسکریپت صفحه‌ی تست این مقاله را بررسی کنید ( جایی که متد trace قرار داده شده است ) .
    اکنون صفحه‌ی تست را باز کنید و بروی دکمه‌ی startTrace کلیک کنید . خروجی ظاهر شده در کنسول را از پایین به بالا بررسی کنید .


    حتما متوجه شدید که متد method3 چگونه در کدهایمان فراخوانی شده است !؟
    ابتدا با کلیک بروی دکمه‌ی startTrace ، متد startTrace اجرا شده و به همین ترتیب متد startTrace متد method1 ، متد method1 هم متد method2 و در نهایت method2 متد method3 را فراخوانی کرده است .
    دستور trace زمانی که در حال بررسی کدهای برنامه نویسان دیگر هستید ، بسیار می‌تواند به شما کمک کند .

  • console.group(object[, object, ...])

    با این دستور می‌توانید لاگ‌های کنسول را بصورت تو در تو گروه بندی کنید .
    console.group("Group1");
    console.log("Log in Group1");
    console.group("Group2");
    console.log("Log in Group2");
    console.group("Group3");
    console.log("Log in Group3");
    نتیجه :



  • console.groupCollapsed(object[, object, ...])

    این دستور معادل دستور قبلی است با این تفاوت که هنگام ایجاد ، گروه را جمع می‌کند .

  • console.groupEnd()

    به آخرین گروه بندی ایجاد شده خاتمه می‌دهد .

  • console.time(name)

    یک تایمر با نام داده شده ایجاد می‌کند . زمانی که نیاز دارید زمان طی شده بین 2 نقطه را اندازه گیری کنید ، این تابع مفید خواهد بود .

  • console.timeEnd(name)

    تایمر همنام را متوقف و زمان طی شده را چاپ می‌کند .
    console.time("TestTime");
    var t = 1;
    for (var i = 0; i < 100000; i++) { t *= (i + t) }
    console.timeEnd("TestTime");
    نتیجه :


  • console.timeStamp()

    توضیحات کامل را از اینجا دریافت کنید .

  • console.count([title])

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


  • console.exception(error-object[, object, ...])

    یک پیغام خطا را به همراه ردیابی کامل اجرای کدها تا زمان رویداد خطا ( مانند متد trace ) چاپ می‌کند .
    در صفحه‌ی تست این متد را اجرا کنید :
    startError();
    نتیجه :

     توجه کنید که ما برای مشاهده‌ی عملکرد صحیح این دستور ، آن را در تابع testError قرار دادیم و بوسیله تابع startError آن فراخوانی کردیم .

  • console.table(data[, columns])

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


    برای اطلاعات بیشتر به اینجا مراجعه کنید .

منابع :
مطالب
کنترل شرایط تاثیرگذار بر روی یک نقش در ASP.NET MVC
در سایت جاری، مباحث زیادی در مورد دسترسی یک نقش به اکشن متدها مطرح شده است. در این مقالات یاد گرفته‌ایم اگر اکشن متدی به ویژگی Authorization مزین گردد، دسترسی این اکشن متد تنها به کاربران لاگین شده خلاصه شده و اگر پارامتر Roles را با نام نقش‌ها مقداردهی کنیم، تنها کاربرانی که آن نقش را دارند، به این اکشن متد دسترسی خواهند داشت. ولی گاهی اوقات شرایطی ایجاد میشود که مشخص نیست این نقش در حال حاضر باید دسترسی به اکشن متد مورد نظر را داشته باشد یا خیر؛ این مثال را در نظر بگیرید:
در یک سیستم حسابداری یا هر سیستم مشابهی، موقعی که یک سند در سیستم درج میشود، نقش‌های زیادی میتوانند درگیر این عمل باشند:
Create می تواند یک سند حسابداری را ایجاد کند.
Edit میتواند یک سند حسابداری را ویرایش کند.

کاربری که نقش edit را دارد توانایی ویرایش اسناد درج شده در سیستم را دارد ولی اسناد حسابداری تنها در همان روز ثبت، امکان ویرایش دارند و پس از پایان ساعاتی کاری یا از روز بعد دیگر قابل ویرایش نبوده و نباید کسی توانایی ویرایش آن را داشته باشد. به همین دلیل، در این نقطه زمانی، دیگر کاربر Edit نباید بتواند این اکشن متد را صدا بزند. به همین علت باید دسترسی او را بر روی سندهای ماقبل امروز بست.

با نگاهی بر روی بسیاری از کدهای نرم افزارهای مختلف که نوشته شده‌اند میتواند دریافت بسیاری از افراد در اکشن مربوطه یا هر دو اکشن Get و Post یک شرط قرار داده و با بررسی اینکه سند متعلق به امروز نیست پیامی را به کاربر نمایش میدهند؛ ولی این نکته باعث میشود که اکشن متد مربوطه تا حدی اولین اصل از اصول Solid یعنی اصل تک مسئولیتی را زیر سوال ببرد. ما در اینجا قصد داریم این موضوع بررسی را به خارج از اکشن متد مربوطه برده و قبل از رسیدن به اکشن متد مورد نظر جلوی آن را بگیریم.

با گردآوری و جمع بندی مطالب سایت تاکنون می‌توان تکه کد زیر را نوشت: 
در سایت جاری مباحث فیلترها (^ و ^) به طور مکرر مورد بررسی قرار گرفته‌است. طبق منابع ذکر شده یکی از این اکشن متدها ActionFilter بوده که دو متد زیر را در اختیار ما قرار می‌دهد:
// Called after the action method executes
void OnActionExecuted(ActionExecutedContext filterContext)

// Called before an action method executes
void OnActionExecuting(ActionExecutingContext filterContext)
اولین متد بعد از اجرای اکشن متد و دومی قبل از آن صدا زده میشود. از آنجا که ما نیاز داریم کاربر قبل از رسیدن به اکشن متد مسدود گردد؛ متد OnActionExecuting را بازنویسی میکنیم:
    public class BlockDocument : ActionFilterAttribute
    {
        public Func<IDocumentServices> _documentServices { get; set; };

        public string ParamName;
      
        public override void OnActionExecuting(ActionExecutingContext filterContext)
        {           
            var id = 0;
            if (filterContext.ActionParameters.ContainsKey(ParamName))
            {
                id =(int) (filterContext.ActionParameters[ParamName]??0);
            }
            if (IsInvalid(id))
            {
                return;
            } 
            var document = _documentServices().GetDocument(id);
            if (document.InserTime.IsPassed())
            {
                filterContext.Result = new HttpStatusCodeResult(403);
            }
        }
    }
در اینجا با استفاده از تزریق وابستگی‌ها و یک FilterProvider سفارشی، سرویس DocumentServices را در یک Func که باعث تاخیر در بارگذاری سرویس تا زمان استفاده از آن می‌گردد قرار میدهیم. سپس پارامتری که کد یا مشخصه‌ای از سند را داراست از ورودی دریافت کرده و بررسی می‌کنیم که آدرس مربوطه شامل این مشخصه میباشد یا خیر. در صورتیکه مشخصه صحت داشته باشد، سند را از طریق سرویس واکشی کرده و اگر زمان درج سند از محدوده زمانی خارج شده باشد، کاربر را به صفحه 403 هدایت میکنیم.
[BlockDocument(ParamName = "id")]
public ActionResult EditDocument(int id)
{
            //...
}
در نهایت اکشن متد مربوطه را به فیلتر نوشته شده مزین میکنیم.
نظرات مطالب
Functional Programming یا برنامه نویسی تابعی - قسمت اول
خیلی ممنونم که این بحث رو مطرح کردید. ولی چیزی که واقعا متوجه نمیشم اینه که چرا باید برنامه نویسی تابعی رو رقیب یا جایگزین برنامه نویسی شی گرا دونست. به نظر من مفاهیمی که این دو روش ارائه میکنن مکمل هم هستن. به عبارتی مطالب مطرح شده میتونه به عنوان رهنمون هایی در برنامه نویسی شی گرا تلقی بشه.
البته در منابع خارجی که مطالعه میکردم تفاوت اصلی رو در این دونسته بودن که در برنامه نویسی تابعی داده‌ها در شی نگهداری نمیشه و باید در تابع نگه داری و جا بجا بشه! البته نمیدونمن چطور این کار به صورت مطلق میسر هست!
در کل من فکر میکنم اگه قرار باشه این کار به صورت مطلق در تمام حالات انجام بشه خودش به ضد مفاهیمی که در این رهنمون‌ها تاکید شده تبدیل خواهد شد.
فکر نمیکنم بدون استفاده از مفاهیم شی گرایی بشه یه پروژه واقعی و بزرگ رو با استفاده از صرفا مفاهیم برنامه نویسی تابعی به صورت بهتری پیاده کرد!
خیلی ممنون میشم اگه اساتید این بحث رو ادامه بدن و توضیحاتی بدن که آیا من دچار بدفهمی شدم یا خیر.
نظرات مطالب
ارتقاء به ASP.NET Core 1.0 - قسمت 19 - بومی سازی
قسمت «... در غیراینصورت (استفاده از اسمبلی‌های دیگر)، ذکر کامل فضای نام مرتبط هم الزامی است ...» مهم است. از این جهت که اگر به اسمبلی نهایی دقت کنید (اسمبلی واقع شده‌ی در پوشه‌ی src\Core1RtmEmptyTest\bin\Debug\netcoreapp1.0\fa):

- در اینجا ابتدا فضای نام اصلی پروژه‌ی جاری ذکر شده‌است. به همین جهت است که عنوان کرده‌اند اگر منابع در اسمبلی جاری هستند، نباید مجددا این فضای نام پیش فرض ذکر شود.
- سپس نام Resources را مشاهده می‌کنید. بنابراین چیزی که بارگذاری می‌شود، یک منبع مدفون شده‌ی در یک فایل dll است و نه اینکه در زمان اجرا به پوشه‌ی Resources مراجعه می‌شود. این پوشه‌ی Resources در اینجا در حد یک جزء از نام کامل بیشتر مطرح نیست.
- در آخر هم نام کامل نوع مدنظر ذکر شده‌است. مثلا نام کامل ViewModel مورد استفاده.
- این نکات در مورد فایل‌های Shared هم مطرح هستند.
- من چون نام پوشه‌ی Views را به Features تغییر داده‌ام، دومین فایل لیست شده‌ی در اینجا، چنین نامی را دارد (بجای Views استاندارد).

بنابراین اگر اطلاعات را به اسمبلی‌های دیگر منتقل می‌کنید:
- به ذکر کامل فضاهای نام دقت داشته باشید.
- بررسی کنید آیا اسمبلی منبع با اسمی شبیه به Core1RtmEmptyTest.resources.dll در پوشه‌ی bin\Debug\netcoreapp1.0\fa موجود هست یا خیر؟ و اگر موجود است، بررسی کنید چه محتوایی در آن ثبت شده‌است.