مطالب دوره‌ها
آشنایی با AOP IL Weaving
IL Weaving در AOP به معنای اتصال Aspects تعریف شده، پس از کامپایل برنامه به فایل‌های باینری نهایی است. اینکار با ویرایش اسمبلی‌ها در سطح IL یا کد میانی صورت می‌گیرد. بنابراین در این حالت دیگر یک محصور کننده و پروکسی، در این بین جهت مزین سازی اشیاء، در زمان اجرای برنامه تشکیل نمی‌شود. بلکه فراخوانی Aspects به معنای فراخوانی واقعی قطعه کدهایی است که به اسمبلی‌های برنامه پس از کامپایل آن‌ها تزریق شده‌اند.
در دنیای دات نت، ابزارهای چندی امکان انجام IL Weaving را فراهم ساخته‌اند که تعدادی از آن‌ها به قرار ذیل هستند:
- PostSharp
- LOOM.NET
- Wicca
و ...

در بین این‌ها، PostSharp معروفترین فریم ورک AOP بوده و در ادامه از آن استفاده خواهیم کرد.


پیشنیاز ادامه بحث

ابتدا یک پروژه کنسول جدید را آغاز کرده و سپس در خط فرمان پاور شل نوگت در VS.NET دستور ذیل را اجرا کنید:
 PM> Install-Package PostSharp
به این ترتیب ارجاعی به PostSharp به پروژه جاری اضافه خواهد شد. البته حجم آن نسبتا بالا است؛ نزدیک به 20 مگ به همراه ابزارهای تزریق کد همراه با آن. مجوز استفاده از آن نیز تجاری و مدت دار است.


مراحل ایجاد یک Aspect برای پروسه IL Code Weaving

ابتدا یک کلاس پایه مشتق شده از کلاسی ویژه موجود در یکی از فریم ورک‌های AOP باید تعریف شود. مرحله بعد، کار اتصال این Aspect می‌باشد که توسط پردازشگر ثانویه IL Code Weaving انجام می‌شود.
در ادامه قصد داریم همان مثال LoggingInterceptor قسمت دوم این سری را با استفاده از IL Code Weaving پیاده سازی کنیم.
using System;

namespace AOP03
{
    public class MyType
    {
        public void DoSomething(string data, int i)
        {
            Console.WriteLine("DoSomething({0}, {1});", data, i);
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            new MyType().DoSomething("Test", 1);
        }
    }
}
کدهای برنامه همانند قبل است. اما اینبار بجای استفاده از Interceptors، با ارث بری از کلاس OnMethodBoundaryAspect کتابخانه PostSharp شروع خواهیم کرد:
using System;
using PostSharp.Aspects;

namespace AOP03
{
    [Serializable]
    public class LoggingAspect : OnMethodBoundaryAspect
    {
        public override void OnEntry(MethodExecutionArgs args)
        {
            Console.WriteLine("On Entry");
        }

        public override void OnExit(MethodExecutionArgs args)
        {
            Console.WriteLine("On Exit");
        }

        public override void OnSuccess(MethodExecutionArgs args)
        {
            Console.WriteLine("On Success");
        }

        public override void OnException(MethodExecutionArgs args)
        {
            Console.WriteLine("On Exception");
        }
    }
}
نیاز است این کلاس توسط ویژگی Serializable مزین شود تا توسط PostSharp قابل استفاده گردد. همانطور که ملاحظه می‌کنید، مراحل مختلف اجرای یک Aspcet در اینجا با override متدهای کلاس پایه OnMethodBoundaryAspect پیاده سازی شده‌اند. این مراحل را پیشتر در زمان استفاده از Interceptors توسط try/finally/catch بررسی کرده بودیم.
اکنون اگر برنامه را اجرا کنیم، اتفاق خاصی رخ نداده و همان خروجی معمول متد DoSomething در کنسول نمایش داده خواهد شد. بنابراین در مرحله بعد نیاز است تا این Aspect را به کدهای برنامه متصل کنیم.
کلاس OnMethodBoundaryAspect در کتابخانه PostSharp، از کلاس MulticastAttribute مشتق می‌شود. بنابراین LoggingAspect ایی را که ایجاد کرده‌ایم نیز می‌توان به صورت یک ویژگی به متد‌های مورد نظر خود افزود:
    public class MyType
    {
        [LoggingAspect]
        public void DoSomething(string data, int i)
        {
            Console.WriteLine("DoSomething({0}, {1});", data, i);
        }
    }
اکنون اگر برنامه را اجرا کنیم، با خروجی زیر مواجه خواهیم شد:
 On Entry
DoSomething(Test, 1);
On Success
On Exit
برای اینکه بتوان عملیات رخ داده را بهتر توضیح داد می‌تواند از یک دی‌کامپایلر مانند برنامه معروف Reflector استفاده کرد:
public void DoSomething(string data, int i)
{
    <>z__Aspects.a0.OnEntry(null);
    try
    {
        Console.WriteLine("DoSomething({0}, {1});", data, i);
        <>z__Aspects.a0.OnSuccess(null);
    }
    catch (Exception)
    {
        <>z__Aspects.a0.OnException(null);
        throw;
    }
    finally
    {
        <>z__Aspects.a0.OnExit(null);
    }
}
این کدی است که به صورت پویا توسط PostSharp به اسمبلی نهایی فایل اجرایی برنامه تزریق شده است.

خوب! این یک روش اتصال Aspects به برنامه است. اما اگر همانند Interceptors بخواهیم Aspect تعریف شده را سراسری اعمال کنیم چکار باید کرد (بدون نیاز به قرار دادن ویژگی بر روی تک تک متدها)؟
برای اینکار ابتدا نیاز است میدان عملکرد Aspect تعریف شده را توسط ویژگی MulticastAttributeUsage محدود کنیم تا برای مثال به خواص اعمال نشوند:
 [Serializable]
[MulticastAttributeUsage(MulticastTargets.Method, TargetMemberAttributes = MulticastAttributes.Instance)]
public class LoggingAspect : OnMethodBoundaryAspect
سپس فایل AssemblyInfo.cs استاندارد پروژه را گشوده و سطر زیر را به آن اضافه کنید:
 [assembly: LoggingAspect(AttributeTargetTypes = "AOP03.*")]
توسط AttributeTargetTypes می‌توان اعمال این Aspect را به یک فضای نام خاص نیز محدود کرد.

مزیت روش IL Code Weaving نسبت به Interceptors، کارآیی و سرعت بالاتر است. از این جهت که کدهایی که قرار است اجرا شوند، پیشتر در اسمبلی برنامه قرار گرفته‌اند و نیازی نیست تا در زمان اجرا، کدی به برنامه به صورت پویا تزریق گردد.
نظرات مطالب
4# آموزش سیستم مدیریت کد Git : نصب و پیکر‌‏بندی
- OpenSSH کار مدیریت و اجرای دستورات کاربران راه دور سرور Git را انجام می‌دهد.
- در لینوکس OpenSSH هست. کار CopSSH (که دیگر رایگان نیست) ساده سازی نصب OpenSSH بر روی ویندوز است. البته OpenSSH را در ویندوز بدون نیاز به این ابزارهای جانبی، توسط cygwin می‌شود نصب کرد (اصل کار و درستش به این صورت است). شبیه CopSSH، مثلا sshwindows هم هست ولی بهتره وقت بگذارید روی cygwin.
- اگر ویندوزی می‌خواهید کار کنید و سرور Git راه اندازی کنید، از Bonobo Git Server استفاده کنید. راهنمای نصب
- همچنین Bitvise SSH Server هم برای ویندوز تهیه شده و از آن هم می‌شود جهت نصب سرور Git استفاده کرد.
- لیست کاملتر نصاب‌های سرور Git روی ویندوز
پاسخ به بازخورد‌های پروژه‌ها
کندی ایجاد فایل pdf
این اندازه گیری را به صورت زیر مجددا انجام دهید:
- یک فایل Global.asax به سرویس تهیه شده اضافه کنید. در روال protected void Application_Start آن، یک گزارش خالی رو تهیه کنید. هدف از اینکار وادار کردن فعال شدن JIT، جهت کامپایل زود هنگام iTextSharp است. JIT در هنگام آغاز یک برنامه دات نتی، قسمت‌های اعظم و مورد نیاز کدهای میانی را کامپایل می‌کند اما نه همه‌ی آن‌را. مابقی در زمان نیاز کامپایل خواهند شد. با این روش می‌تونید JIT رو وادار کنید زودتر کارش را به اتمام برساند. (همین مساله در زمان تهیه اولین گزارش به شدت خودش را نشان می‌دهد)
- تهیه دیتاسورس را از متد تهیه گزارش خارج کنید. این هم بالاخره زمانی را صرف می‌کند. اما بر اساس آن نباید سرعت کار با کتابخانه تهیه گزارش را محاسبه کرد.
- سه بار اندازه گیری کنید. بعد میانگین بگیرید.
اشتراک‌ها
تفاوت بین NET Core 2.0. و NET Standard 2.0. در چیست؟

NET Standard‌. در حقیقت یک قرار داد است که سکوهای کاری مختلف دات نتی مانند Full .NET Framework ، Xamarin ، Mono ، UWP و غیره می‌توانند آن‌را پیاده سازی کنند. یک نمونه‌ی دیگر این پیاده سازی‌ها نیز NET Core. است. برای مثال دات نت 4.6.1، استاندارد و قرار داد شماره‌ی 2 دات نت را پیاده سازی می‌کند. به همین صورت NET Core 2.0. نیز پیاده سازی کننده‌ی این استاندارد شماره 2 است.
«اما» باید درنظر داشت که دات نت استاندارد، بیش از یک قرار داد چیزی نیست و پیاده سازی کنندگان آن می‌توانند سطح بیشتری را نسبت به این قرار داد نیز لحاظ کنند. برای مثال دات نت 4.6.1 شامل سطح API بیشتری از دات نت استاندارد 2 است.
 
 با تغییرات اخیر، اکنون NuGet می‌تواند کتابخانه‌های مبتنی بر NET Standard 2. را در برنامه‌های مبتنی بر سکوهای کاری که آن‌را پیاده سازی می‌کنند، بدون مشکل اضافه کند. برای مثال می‌توان اسمبلی‌های دات نت 4.6.1 را به برنامه‌های ASP.NET Core 2.0 اضافه کرد (کاری که در نگارش 1x آن به صورت مستقیم میسر نیست) و یا می‌توان اسمبلی‌های کامپایل شده‌ی برای دات نت استاندارد 2 را به برنامه‌های مبتنی بر دات نت 4.6.1 اضافه کرد.
 
«اما» باید درنظر داشت که امکان اضافه کردن یک بسته‌ی نیوگت از یک کتابخانه‌ی نوشته شده‌ی برای دات نت کامل در برنامه‌های دات نت Core به معنای تضمینی برای کار کردن آن در زمان اجرا نخواهد بود. از این جهت که دات نت کامل، به همراه قسمت‌هایی است که در NET Standard. وجود خارجی ندارند. بنابراین اگر کتابخانه‌ی استفاده شده صرفا این API مشترک را هدف قرار داده‌است، هم قابلیت اتصال و هم قابلیت اجرا را خواهد داشت؛ اما اگر برای مثال کسی بسته‌ی NServiceBus را به پروژه‌ی ASP.NET Core 2.0 اضافه کند، بدون مشکل کامپایل خواهد شد. اما از آنجائیکه این کتابخانه از MSMQ استفاده می‌کند که خارج از میدان دید این استاندارد است، در زمان اجرا با شکست مواجه خواهد شد.

تفاوت بین NET Core 2.0. و NET Standard 2.0. در چیست؟
نظرات مطالب
شروع به کار با AngularJS 2.0 و TypeScript - قسمت دوازدهم - توزیع برنامه
یک نکته‌ی تکمیلی

روش توصیه‌ی شده‌ی توسط تیم AngularJS 2.0، جهت توزیع برنامه‌ها به این صورت است:
 1) ابتدا برنامه‌ی جدید angular-cli را نصب کنید: (بدیهی است پیش از آن باید وابستگی‌های Nodejs بر روی سیستم شما نصب باشند)
npm install -g angular-cli
 2) با دستور ذیل، یک برنامه‌ی جدید AngularJS 2.0 را به همراه تمام وابستگی‌های آن، می‌توانید آغاز کنید:
ng new AngularCLIDemoApp
ابتدا به پوشه‌ی مدنظر وارد شده و سپس در خط فرمان، دستور فوق را وارد کنید. به این ترتیب ساختار یک برنامه‌ی جدید AngularJS 2.0 را خواهید داشت.
 3) اکنون اگر دستور ذیل را صادر کنید:
 ng build -prod
به صورت خودکار، کار بسته بندی و توزیع نهایی برنامه، در پوشه‌ای به نام dist، انجام خواهد شد.

دو مطلب تکمیلی
Angular CLI is here for AngularJS 2  
Angular 2 CLI – Build Angular 2 apps using Command Line Interface  
نظرات اشتراک‌ها
نگارش نهایی RTL Bootstrap 3 ویرایش Less منتشر شد!
Visual Studio 2012 update 3 (به بعد) به صورت خودکار فایل‌های less رو می‌تونه کامپایل و تفسیر کنه (در ادیتور باز و آن‌ها را ذخیره کنید).
و یا از پروژه dotless استفاده کنید. نحوه یکپارچه کردن dotless با MVC در اینجا. روش دیگر آن استفاده از پروژه Bundle Transformer است.
همچنین افزونه chrispy نیز برای اینکار موجود است.
پاسخ به بازخورد‌های پروژه‌ها
خطا هنگام اجرا در IIS/7.5 کلیه آدرس ها نیاز به دریافت پارامتر ارسالی دارند

وجود , اضافی در حین معرفی خواص در زبان #C کاملا مجازه و به هیچ چیزی هم تفسیر نمیشه. اگر این رو حذف کردید و بعد برنامه رو کامپایل و به سرور ارسال کردید، یعنی فایل‌های bin روی سرور شما قدیمی بودن یا هماهنگ نشده بودند. معنای دیگری نداره.

مطالب
کار با دیتاتایپ JSON در MySQL - قسمت اول
تا قبل از اضافه شدن دیتاتایپ JSON به صورت توکار در MySQL، داده‌های JSON را تنها میتوانستیم با فرمت رشته‌ای، درون دیتابیس ذخیره کنیم: 
CREATE TABLE tableName (
jsonData CHAR(250) -- or VARCHAR, TEXT, BLOB
);

INSERT INTO tableName VALUES (
'{ "name": "User1", "age": 41}'
);

SELECT * FROM tableName;

{ "name": "User1", "age": 41}
اما مشکل اینجاست که هیچ نوع اعتبارسنجی بر روی این دیتا صورت نخواهد گرفت؛ هیچ روشی برای مطمئن شدن از اینکه تگ‌ها به درستی استفاده شده‌اند، وجود ندارد و همچنین امکان جستجو را سخت خواهد کرد؛ زیرا مجبور خواهیم بود از Regular Expressions برای جستجوی درون متن‌های ذخیره شده استفاده کنیم:
SELECT * FROM tableName
WHERE jsonData REGEXP 'User1';

از نسخه MySQL 5.7.8 به بعد، می‌توانیم از نوع داده JSON برای ذخیره‌سازی محتوای JSON، استفاده کنیم. از این دیتاتایپ برای ذخیره‌سازی یک JSON document معتبر میتوان استفاده کرد:
CREATE TABLE tableName (
jsonData JSON
);

INSERT INTO tableName VALUES (
'{ "name": "User1", "age": 41, "name": "User2"}'
);

SELECT * FROM tableName;

{"age": 41, "name": "User2"}

همانطور که مشاهده میکنید MySQL به صورت اتوماتیک یکسری نرمال‌سازی را روی دیتا اعمال کرده است:
  • ابتدا بررسی خواهد شد که سند JSON معتبر باشد؛ در غیر اینصورت ذخیره‌سازی با مشکل مواجه خواهد شد.
  • از فیلدهایی که کلید تکراری دارند، صرفنظر خواهند شد. در مثال بالا دوبار فیلد name را مقداردهی کرده‌ایم. در اینجالت key/value دوم لحاظ شده‌است. البته میبایستی اصل first key wins لحاظ میشد، اما این مورد به عنوان یک باگ گزارش شده‌است و در نسخه‌های 8 به بعد رفع شده‌است (https://forums.mysql.com/read.php?3,660500,660500 - https://bugs.mysql.com/bug.php?id=86866).
  • فاصله‌های اضافی بین کلیدها حذف شده‌اند.
  • برای جستجوی بهتر، کلیدهای آبجکت JSON به صورت مرتب شده ذخیره شده‌اند.

جستجو درون JSON Document
یک سند JSON، از یکسری کلیدها به همراه مقادیرشان تشکیل شده‌است. همچنین مقادیر میتوانند شامل اشیاء یا آرایه‌هایی به صورت تودرتو باشند. بنابراین به یک path جهت استخراج مقادیر نیاز خواهیم داشت. برای نوشتن یک path باید scope آن را تعیین کنیم که در توابع MySQL این scope به صورت پیش‌فرض، سند جاری میباشد که توسط علامت $ مشخص میشود. 
فرض کنید ساختار زیر را درون دیتابیس ذخیره کرده‌ایم:
{
    "id": "1",
    "sku": "asdf123",
    "name": "Lorem ipsum jacket",
    "price": 12.45,
    "discount": 10,
    "offerEnd": "October 5, 2020 12:11:00",
    "new": false,
    "rating": 4,
    "saleCount": 54,
    "category": ["fashion", "men"],
    "tag": ["fashion", "men", "jacket", "full sleeve"],
    "variation": [
      {
        "color": "white",
        "image": "/assets/img/product/fashion/1.jpg",
        "size": [
          {
            "name": "x",
            "stock": 3
          },
          {
            "name": "m",
            "stock": 2
          },
          {
            "name": "xl",
            "stock": 5
          }
        ]
      },
      {
        "color": "black",
        "image": "/assets/img/product/fashion/8.jpg",
        "size": [
          {
            "name": "x",
            "stock": 4
          },
          {
            "name": "m",
            "stock": 7
          },
          {
            "name": "xl",
            "stock": 9
          },
          {
            "name": "xxl",
            "stock": 1
          }
        ]
      },
      {
        "color": "brown",
        "image": "/assets/img/product/fashion/3.jpg",
        "size": [
          {
            "name": "x",
            "stock": 1
          },
          {
            "name": "m",
            "stock": 2
          },
          {
            "name": "xl",
            "stock": 4
          },
          {
            "name": "xxl",
            "stock": 0
          }
        ]
      }
    ],
    "image": [
      "/assets/img/product/fashion/1.jpg",
      "/assets/img/product/fashion/3.jpg",
      "/assets/img/product/fashion/6.jpg",
      "/assets/img/product/fashion/8.jpg",
      "/assets/img/product/fashion/9.jpg"
    ],
    "description": {
      "shortDescription": "Ut enim ad minima veniam, quis nostrum exercitationem ullam corporis suscipit laboriosam, nisi ut aliquid ex ea commodi consequatur? Quis autem vel eum iure reprehenderit qui in ea voluptate velit esse quam nihil molestiae consequatur.",
      "fullDescription": "Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium doloremque laudantium, totam rem aperiam, eaque ipsa quae ab illo inventore veritatis et quasi architecto beatae vitae dicta sunt explicabo. Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit, sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt. Neque porro quisquam est, qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit, sed quia non numquam eius modi tempora incidunt ut labore et dolore magnam aliquam quaerat voluptatem. Ut enim ad minima veniam, quis nostrum exercitationem ullam corporis suscipit laboriosam, nisi ut aliquid ex ea commodi consequatur? Quis autem vel eum iure reprehenderit qui in ea voluptate velit esse quam nihil molestiae consequatur, vel illum qui dolorem eum fugiat quo voluptas nulla pariatur? Nor again is there anyone who loves or pursues or desires to obtain pain of itself, because it is pain, but because occasionally circumstances occur in which toil and pain can procure him some great pleasure. To take a trivial example, which of us ever undertakes laborious physical exercise, except to obtain some advantage from it? But who has any right to find fault with a man who chooses to enjoy a pleasure that has no annoying consequences, or one who avoids a pain that produces no resultant pleasure?"
    }
  }

برای دریافت دسته‌بندی‌های هر ردیف میتوانیم از تابع JSON_EXTRACT استفاده کنیم:
SELECT 
    JSON_PRETTY(
  JSON_EXTRACT(data, "$.category")
    )
FROM
    experiments.productMetadata;

/* 
  [
    "fashion",
    "men"
  ]
  [
    "fashion",
    "women"
  ]
  [
    "fashion",
    "men"
  ]
*/
همانطور که مشاهده میکنید، تابع JSON_EXTRACT یک آرگومان دومی را نیز دریافت میکند که توسط آن میتوانیم path موردنظر را وارد کنیم و همانطور که عنوان شد، از $ برای دسترسی به سند جاری استفاده میکنیم. سپس در ادامه نام پراپرتی‌ای را که میخواهیم استخراج کنیم، تعیین کرده‌ایم. در اینجا چون ساختار ذخیره شده، به صورت شیء میباشد، به صورت مستقیم از $ و بعد از آن نقطه و سپس نام پراپرتی استفاده کرده‌ایم. میتوانیم عمق پیمایش را نیز بیشتر کنیم. به عنوان مثال برای دسترسی به المنت دوم از آرایه tag درون دیتا خواهیم داشت:
JSON_EXTRACT(data, "$.tag[1]")
JSON_EXTRACT(data, "$.description.shortDescription")

همچنین اگر کلید مقداری را که میخواهیم جستجو کنیم، بدانیم اما از کلید والد آن اطلاع نداشته باشیم، میتوانیم از * استفاده کنیم: 
SELECT 
JSON_EXTRACT(data, "$.*.shortDescription")
FROM experiments.productMetadata;

JSON_KEYS
از این تابع جهت دریافت کلیدهای top level یک شیء JSON استفاده میشود:
SELECT 
JSON_KEYS(data)
FROM experiments.productMetadata;

-- ["id", "new", "sku", "tag", "name", "image", "price", "rating", "category", "discount", "offerEnd", "saleCount", "variation", "description"]
-- ["id", "new", "sku", "tag", "name", "image", "price", "rating", "category", "discount", "saleCount", "variation", "description"]


همچنین میتوانیم path را نیز به عنوان آرگومان دوم آن تعیین کنیم: 
SELECT 
JSON_KEYS(data, "$.description")
FROM experiments.productMetadata;

-- ["fullDescription", "shortDescription"]
-- ["fullDescription", "shortDescription"]

JSON_CONTAINS 
از این تابع برای جستجو استفاده خواهیم کرد و همانطور که از نام آن پیداست، در صورت وجود مقدار مورد جستجو، خروجی ۱ خواهد بود:
SELECT 
    JSON_CONTAINS(data, "10", "$.discount")
FROM
    experiments.productMetadata;

-- 1
-- 0

JSON_CONTAINS_PATH
توسط این تابع میتوانیم بررسی کنیم که یک path یا یک یکسری path خاص درون JSON document وجود دارند یا خیر: 
SELECT 
JSON_CONTAINS_PATH(data, "one", "$.description", "$.address", "$.website")
FROM experiments.productMetadata;
آرگومان اول این تابع، داکیومنتی است که میخواهیم جستجو کنیم. برای آرگومان دوم، یکی از دو مقدار one یا all را میتوانیم تنظیم کنیم. در ادامه لیستی از pathهایی را که میخواهیم جستجو کنیم، وارد کرده‌ایم. در حالت one، اگر تنها یکی از pathها درون داکیومنت JSON وجود داشته باشند، خروجی ۱ خواهد بود. اگر one را به all تنظیم کنیم، یعنی باید تمامی pathها، درون داکیومنت وجود داشته باشند تا خروجی ۱ شود؛ در غیراینصورت خروجی ۰ خواهد بود. 

JSON_SEARCH  
توسط این تابع میتوانیم position مقدار مورد جستجو را درون داکیومنت JSON پیدا کنیم: 
SELECT 
    JSON_SEARCH(data, 'one', 'fashion')
FROM
    experiments.productMetadata;
    
-- "$.tag[0]"
-- "$.tag[0]"

مطالب
آموزش LINQ بخش دوم
سبک‌های مختلف نوشتن Query در LINQ
تعریف Query:
عبارتی که اطلاعات را از منبع داده، بازیابی می‌کند، پرس و جو یا Query می‌گوییم. بطور کلی عملیات پرس و جو شامل سه بخش زیر می‌شود:
1- مشخص کردن منبع داده
2- ایجاد پرس و جو (Query)
3- اجرای پرس و جو
// The Three Parts of a LINQ Query:
//  1. منبع داده
int[] numbers = new int[7] { 0, 1, 2, 3, 4, 5, 6 };
// 2. ایجاد پرس و جو
// numQuery is an IEnumerable<int>
var numQuery =
    from num in numbers
    where (num % 2) == 0
    select num;
// 3. اجرای پرس و جو
foreach (int num in numQuery)
{
    Console.Write("{0,1} ", num);
}
شکل زیر توصیفی از کد‌های بالا می‌باشد :
 
دو سبک برای نوشتن عبارت‌های جستجو در LINQ وجود دارند :
 1- Fluent Style 
 2- Query Expression Style یا Query Syntax
سبک Fluent از متد‌های الحاقی برای عملیات پرس و جو استفاده می‌کند. در کلیه‌ی کدهای بخش اول این سری آموزشی از سبک Fluent استفاده شده است.
در کلاس‌های زیر متد‌های استاتیک مختلفی برای عملیات بر روی توالی‌ها ارائه شده‌اند:
 • System.Linq.Enumerable
 • System.Linq.Queryable
 • System.Linq.ParallelEnumarable
بطور کلی هر نمونه‌ای که اینترفیس <IEnumerable<Tsource را پیاده سازی کرده باشد می‌تواند از این متدهای الحاقی استفاده کند.
عملگرهای جستجو به دو صورت تکی و زنجیره‌ای برای ایجاد پرس و جو‌های پیچیده مورد استفاده قرار می‌گیرند.

پرس و جوی‌های زنجیره‌ای
در ابتدا کلاسی به نام Ingredient را به شکل زیر تعریف می‌کنیم (این کلاس نشان دهنده‌ی نام مواد غذایی و کالری آنهاست):
class Ingredient
{
    public string Name { get; set; }
    public int Calories { get; set; }
}
لیستی از مواد غذایی را ایجاد می‌کنیم:
Ingredient[] ingredients =
{
   new Ingredient {Name = "Suger", Calories = 500},
   new Ingredient {Name = "Egg", Calories = 100 },
   new Ingredient {Name = "Milk", Calories = 150 },
   new Ingredient {Name = "Flour", Calories = 50 },
   new Ingredient {Name = "Butter", Calories = 200 }
};
حال می‌خواهیم بصورت زنجیره‌ای از عملگر‌های پرس و جوی Where,OrderBy,Select استفاده کنیم:
Ingredient[] ingredients =
{
   new Ingredient {Name = "Suger", Calories = 500},
   new Ingredient {Name = "Egg", Calories = 100 },
   new Ingredient {Name = "Milk", Calories = 150 },
   new Ingredient {Name = "Flour", Calories = 50 },
   new Ingredient {Name = "Butter", Calories = 200 }
};

IEnumerable<string> highCalories =
ingredients.Where(x => x.Calories >= 150)
  .OrderBy(x => x.Name)
  .Select(x => x.Name);

foreach (var item in highCalories)
{
   Console.WriteLine(item);
}
خروجی کد بالا به شکل زیر است :
Butter
Milk
Suger
نمودار زیر نحوه‌ی عملکرد عملگرهای پرس و جو را نشان می‌دهد. هر عملگر بر روی توالی خروجی عملگر قبلی کار می‌کند. توجه کنید که توالی ورودی از نوع <IEnumerable<Ingredient می‌باشد و توالی خروجی تولید شده از نوع <IEnumerable<string است.
در این مثال عملگر‌های پرس و جو بر روی توالی ورودی عمل می‌کنند تا به دستور Select برسند. دستور Select هر عنصر را به یک رشته تبدیل می‌کند. این عملیات را Projection می‌گویند.











عبارت Lambda نوشته شده‌ی در بخش Select مشخص می‌کند که خروجی بر اساس چه خصوصیتی از توالی ورودی باشد. در اینجا نام عناصر به صورت رشته در خروجی ظاهر می‌شوند.


سبک Query Expression (عبارت‌های پرس و جو) 

Query Expression یک گرامر زیبا و روان برای نوشتن پرس و جو‌ها را ارائه می‌دهد. در مثال زیر از سبک Query Expression استفاده کرده‌ایم:

Ingredient[] ingredients =
{
    new Ingredient {Name = "Suger", Calories = 500},
    new Ingredient {Name = "Egg", Calories = 100},
    new Ingredient {Name = "Milk", Calories = 150},
    new Ingredient {Name = "Flour", Calories = 50},
    new Ingredient {Name = "Butter", Calories = 200}
};

IEnumerable<string> highCalories =
    from i in ingredients
    where i.Calories >= 150
    orderby i.Name
    select i.Name;

foreach (var item in highCalories)
{
    Console.WriteLine(item);
}

خروجی کد بالا با خروجی کد به سبک Fluent  یکسان است:

Butter
Milk
Suger

همانطور که می‌بینید ترتیب عملیات همانند روش قبل است. عبارت‌های پرس و جوی (from,where,orderby,select) به ترتیب با اصلاح توالی ورودی و تحویل آن به عبارت جستجوی بعدی کار را انجام می‌دهند.

عبارت جستجوی بالا با کلمه‌ی کلیدی from آغاز شده است. هدف from دو چیز است:

1- مشخص کردن توالی ورودی (منبع داده)

2- معرفی متغیر Range  (مشخص کردن عنصر مورد نظر در منبع داده)

متغیر Range همچون متغیر شمارنده در حلقه هاست. 


در ادامه این سری آموزشی درباره متغیر Range بصورت کاملتری بحث خواهیم کرد.   

نظرات مطالب
ارتقاء به ASP.NET Core 1.0 - قسمت 21 - بررسی تغییرات Bundling و Minification
با تشکر، با معرفی پکیج‌ها از طریق Bower پوشه ای به نام lib در wwwroot ایجاد شده به همین ترتیب معرفی بخش inputFiles رو من به شکل زیر انجام دادم :
"wwwroot/lib/jquery/dist/jquery.min.js",
و همچنین پکیج مربوطه در nuget  و افزونه معرفی شده در مطلب رو هم نصب کردم،با اجرای update all files در task runner محتوای فایل‌های :
"wwwroot/js/site.min.js"
"wwwroot/css/site.min.css"
تغییری نمی‌کنند، اگر ممکن هست راهنمائی بفرمائید