مطالب
آموزش LINQ بخش چهارم
 بررسی عبارت Join
عبارت Join برای ایجاد ارتباط بین عناصر دو توالی استفاده می‌شود. پیش نیاز این عملیات وجود یک مقدار در عناصر توالی ورودی است که بتوان از طریق آن برابری دو عنصر را اهراز کرد.
عبارت join، دو توالی را به عنوان ورودی دریافت می‌کند. هر عنصر در توالی اول باید یک خصوصیت داشته باشد که بتوان آن را با یک خصوصیت از عناصر توالی دوم مقایسه کرد. عبارت Join، مقادیر مشخص شده را از طریق کلمه‌ی کلیدی equals مقایسه می‌کند. باید توجه داشت که عملیات join  برای بررسی برابری دو مقدار، در دو توالی مختلف است. از این رو به آن equal-joins می‌گویند.
فرم خروجی عبارت join  بر اساس نوع عملیات join ای است که ما انجام می‌دهیم.

انواع JOIN :
• Inner JOIN
• Group JOIN
• Left JOIN

کلاس‌های زیر را در نظر بگیرید:
/// <summary>
/// دستور العمل
/// </summary>
class Recipe
{
  public int Id { get; set; }
  public string Name { get; set; }
}

/// <summary>
/// بازخورد
/// </summary>
class Review
{
  public int RecipeId { get; set; }
  public string ReviewText { get; set; }
}
بر اساس مدل‌های تعریف شده، هر Recipe ممکن است 0، 1 یا تعداد نامحدودی Review داشته باشد. همانطور که می‌بینید هیچ رابطه‌ی مستقیمی این دو مدل با هم ندارند. در کلاس Review یک خصوصیت وجود دارد که ID مدل Recipe را در خود نگه می‌دارد.

Inner Join
 این دستور عنصری از  توالی اول را که متناظر با آن عنصری در توالی دوم وجود داشته باشد، به خروجی می‌برد.
مثال:

Recipe[] recipes =
{
   new Recipe {Id = 1, Name = "Mashed Potato"},
   new Recipe {Id = 2, Name = "Crispy Duck"},
   new Recipe {Id = 3, Name = "Sachertorte"}
};

Review[] reviews =
{
   new Review {RecipeId = 1, ReviewText = "Tasty!"},
   new Review {RecipeId = 1, ReviewText = "Not nice :("},
   new Review {RecipeId = 1, ReviewText = "Pretty good"},
   new Review {RecipeId = 2, ReviewText = "Too hard"},
   new Review {RecipeId = 2, ReviewText = "Loved it"}
};

var query = from recipe in recipes
join review in reviews on recipe.Id equals review.RecipeId
select new //anonymous type
{
   RecipeName = recipe.Name,
   RecipeReview = review.ReviewText
};

foreach (var item in query)
{
   Console.WriteLine($"{item.RecipeName}-{item.RecipeReview}");
}
در مثال فوق، در ابتدا دو توالی تعریف شد. recipes که تعدادی دستور العمل و reviews که مجموعه‌ای از بازخوردها را در خود نگه می‌دارند.
پرس و جو با عبارت from که اشاره‌گری به توالی اول است آغاز و با معرفی یک متغیر Range به نام Recipe ادامه پیدا می‌کند. سپس دستور Join نوشته شده است. مجددا متغیر range  جدیدی به نام review معرفی شده که به عناصر توالی دوم اشاره خواهد کرد. در ادامه کلمه‌ی کلیدی on اجازه می‌دهد که عناصر یکسانی در توالی اول را با عناصر یکسانی در توالی دوم مشخص کنیم. کلمه‌ی کلیدی equal هم برای مقایسه‌ی برابری دو مقدار استفاده شده است. عبارت join  بر اساس مقدار id  در مجموعه recipes و همچنین Recipeid در مجموعه‌ی reviews خروجی را مهیا خواهد کرد.
خروج مثال فوق به شکل زیر است :
Mashed Potato-Tasty!
Mashed Potato-Not nice :(
Mashed Potato-Pretty good
Crispy Duck-Too hard
Crispy Duck-Loved it
همانطور که مشاهده می‌کنید کلیه دستورالعمل‌هایی که بازخوردی برای آنها وجود دارد، در خروجی وجود دارند.

Group Join
بکارگیری into به همراه join، دستور Group Join را می‌سازد.
این دستور  خروجی حاصل از join  را گروه بندی خواهد کرد. Group join یک توالی سلسله مراتبی را تولید می‌کند که در آن یک عنصر از توالی اول با یک یا چند عنصر در توالی دوم در ارتباط است.
مثال:
var query = from recipe in recipes
join review in reviews on recipe.Id equals review.RecipeId
into reviewGroup
select new //anonymous type
{
   RecipeName = recipe.Name,
   Reviews = reviewGroup//collection of related reviews
};

foreach (var item in query)
{
   Console.WriteLine($"Review for {item.RecipeName}");
   foreach (var review in item.Reviews)
   {
       Console.WriteLine($"-{review.ReviewText}");
   }
}
در این مثال از 2 توالی تعریف شده‌ی در مثال قبل استفاده کرده‌ایم.
متغیر reviewGroup توالی حاصل از اجرای join  را نمایش می‌دهد. برای ایجاد توالی خروجی، نتیجه به یک نوع بی نام، بازتاب شده است. هر عنصر در نوع بی نام یک گروه را نشان می‌دهد. نوع بی نام شامل دو خصوصیت RecipeName که مقدار آن از توالی اول می‌آید و Reviews که حاصل خروجی Join است می‌باشد.
خروجی مثال بالا به شکل زیر است:
Review for Mashed Potato
-Tasty!
-Not nice :(
-Pretty good
Review for Crispy Duck
-Too hard
-Loved it
Review for Sachertorte
همانطور که می‌بینید اینبار عنصر Sachertorte در خروجی ظاهر شده است. اگر عنصری در توالی سمت چپ وجود داشته باشد که عنصر و یا عناصری در توالی سمت راست با آن متناظر نباشند، آنگاه دستور join،  یک لیست خالی را برای این عنصر تخصیص می‌دهد.

Left outer join
برای آنکه بتوان یک خروجی غیر سلسله مراتبی و اصطلاحا flat را ایجاد کرد که مانند خروجی مثال group join  باشد (نمایش عنصر Sachertorte) می‌توان از عملگر  ()DefaultIfEmpty به‌همراه یک عبارت from اضافی و معرفی یک متغیر Range استفاده کرد. در صورت نبودن عنصر متناظر در توالی دوم این متغیر range بصورت null تنظیم می‌شود.
مثال :
در این مثال از مجموعه‌های تعریف شده‌ی در بخش اول مطلب استفاده کرده‌ایم:
var query = from recipe in recipes
join review in reviews on recipe.Id equals review.RecipeId
into reviewGroup
from rg in reviewGroup.DefaultIfEmpty()
select new //anonymous type
{
   RecipeName = recipe.Name,
   //RecipeReview = rg.ReviewText SystemNullException
   RecipeReview = (rg == null ? "n/a" : rg.ReviewText)
};

foreach (var item in query)
{
   Console.WriteLine($"{item.RecipeName}-{item.RecipeReview}");
}
در بخشی از کد بالا به خاطر وجود حالت null، در خروجی استثنائی رخ خواهد داد. به همین خاطر قبل از تخصیص، مقدار را کنترل کرده‌ایم.
خروجی مثال فوق به شکل زیر است:
Mashed Potato-Tasty!
Mashed Potato-Not nice :(
Mashed Potato-Pretty good
Crispy Duck-Too hard
Crispy Duck-Loved it
Sachertorte-n/a
همانطور که مشاهده می‌کنید، خروجی به صورت غیر سلسله مراتبی و flat می‌باشد. از طریق دستور select و جایگزین کردن مقدار N/A به جای null، عنصر Sachertorte را در خروجی مهیا کرده‌ایم .
یک راه جایگزین برای کنترل مقدار null در دستور select بازسازی متد DefaultIfEmpty به‌صورتی است که به جای ایجاد مقدار null، یک نمونه‌ی جدید از مدل review را با مقدار پیش فرض N/A ایجاد کند.
مثال:
var query = from recipe in recipes
join review in reviews on recipe.Id equals review.RecipeId
into reviewGroup
from rg in reviewGroup.DefaultIfEmpty(new Review { ReviewText = "N/A" })
select new //anonymous type
{
   RecipeName = recipe.Name,
   RecipeReview = rg.ReviewText
};

foreach (var item in query)
{
   Console.WriteLine($"{item.RecipeName}-{item.RecipeReview}");
}
خروجی مثال بالا :
 Mashed Potato-Tasty!
Mashed Potato-Not nice :(
Mashed Potato-Pretty good
Crispy Duck-Too hard
Crispy Duck-Loved it
Sachertorte-N/A 
مطالب
AngularJS #2
بهتر است قبل از این که به ادامه‌ی آموزش بپردازم، دو نکته را متذکر شوم:
1) روند آموزشی این فریمورک از کل به جز است؛ به این معنا که ابتدا تمامی قابلیت‌های اصلی فریمورک را به صورت کلی و بدون وارد شدن به جزئیات بیان می‌کنم و پس از آن، جزئیات را در قالب مثال‌هایی واقعی بیان خواهم کرد.
2) IDE مورد استفاده بنده Visual Studio 2012 است. همچنین از ابتدا پروژه را با ASP.NET MVC شروع می‌کنم. شاید بگویید که می‌شود Angular را بدون درگیر شدن با مباحث ASP.NET MVC بیان کرد؛ اما پاسخ من این است که این مثال‌ها باید قابل پیاده‌سازی در نرم‌افزارهای واقعی باشند و یکی از بسترهای مورد علاقه‌ی من ASP.NET MVC است. اگرچه باز هم تاکید می‌کنم که کلیه‌ی مباحث ذکرشده، برای کلیه‌ی زبان‌های سمت سرور دیگر هم قابل استفاده است و هدف من در اینجا بیان یک سری چالش‌ها در ASP.NET MVC است.

نحوه‌ی دریافت AngularJS
1) NuGet Package Manager
2) دریافت از وب‌سایت angularjs.org

دریافت از طریق Nuget Package Manager
روش ارجح افزودن کتابخانه‌های جانبی در یک پروژه‌ی واقعی، استفاده از NuGet Package Manager است. دلیل آن هم بارها بیان‌شده است از جمله: باخبر شدن از آخرین به‌روزرسانی کتابخانه‌ها، دریافت وابستگی‌های کتاب‌خانه‌ی مورد نظر و نبودن محدودیت تحریم برای دریافت فایل‌ها است.
روش کار هم بسیار ساده است، کافی است که بر روی پروژه کلیک راست کرده و گزینه‌ی Manage NuGet Packages را انتخاب کنید و با جست جو angularjs نسبت به نصب آن اقدام نمایید.
اگر هم با ابزارهای گرافیکی رابطه‌ی خوبی ندارید، می‌توانید از Package Manager Console فراهم‌شده توسط NuGet استفاده کنید. کافی است در کنسول پاورشل آن عبارت زیر را تایپ کنید:
Install-Package angularjs

پس از نصب angularjs، شاهد تغییراتی در پوشه‌ی Scripts پروژه‌ی خودخواهید بود. تعداد زیادی فایل جاوا اسکریپت که با عبارت angular شروع‌شده‌اند، به این پوشه اضافه شده است. در حال حاضر ما تنها به فایل angular.js نیاز داریم و احتیاجی به فایل‌های دیگر نیست.
همچنین یک پوشه به نام i18n نیز اضافه شده است که برای مباحث Globalization و Internationalization به کار گرفته می‌شود. 
 
دریافت از سایت angularjs.org
برای دریافت Angular از وب سایت رسمی‌اش، به angularjs.org مراجعه کنید؛ اما گویا به دلیل تحریم‌ها این سایت برای IP ایران مسدود شده است (البته افرادی نیز بدون مشکل به آن دسترسی دارند). دکمه‌ی Download را فشار داده و در نهایت کلید دریافت را بزنید. اگر نسخه‌ی کامل آن را دریافت کنید، لیستی از مستندات AngularJS را نیز در فایل دریافتی، خواهید داشت. در هر صورت این روش برای استفاده از angular دریک پروژه‌ی واقعی توصیه نمی‌شود.
پس به عنوان یک best practice، همیشه کتاب‌خانه‌های جانبی را با NuGet دریافت و نصب کنید. رفع موانع تحریم‌ها، یکی از مزایای مهم آن است.
   
پس از دریافت angular،  نوشتن برنامه‌ی معروف Hello, World به وسیله‌ی آن ، می‌تواند بهترین شروع باشد؛ اما اگر اجازه بدهید، نوشتن این برنامه را در قالب توضیح قالب‌های سمت کلاینت انجام دهیم.
   
قالب‌های سمت کلاینت (Client Side Templates)
در برنامه‌های وب چند صفحه‌ای و یا اکثر وب سایت‌های معمول، داده‌ها و کدهای HTML، در سمت سرور اصطلاحا سرهم و مونتاژ شده و خروجی نهایی که HTML خام است به مرورگر کاربر ارسال می‌شود. با یک مثال بیشتر توضیح می‌دهم: در ASP.NET MVC معمولا از لحظه‌ای که کاربر صفحه‌ای را درخواست می‌کند تا زمانی که پاسخ خود را در قالب HTML می‌بیند، این فرآیند طی می‌شود: ابتدا درخواست به Controller هدایت می‌شود و سپس اطلاعات مورد نیاز از پایگاه داده خوانده‌شده و در قالب یک Model به View که یک فایل HTML ساده است، منتقل می‌شود. سپس به کمک موتور نمایشی Razor، داده‌ها در جای مناسب خود قرار می‌گیرند و در نهایت، خروجی که HTML خام است به مرورگر کلاینت درخواست‌کننده ارسال می‌شود تا در مرورگر خود نتیجه را مشاهده نماید. روال کار نیز در اکثر SPA‌های معمول و یا اصطلاحا برنامه‌های AJAX، باکمی تغییر به همین شکل است.
 اما در Angular داستان به شکل دیگری اتفاق می‌افتد؛ Angular قالب HTML و داده‌ها را به صورت جداگانه از سرور دریافت می‌کند و در مرورگر کاربر آن‌ها را سرهم و مونتاژ می‌کند. بدیهی است که در اینجا قالب، یک فایل HTML ساده و داده‌ها می‌تواند به فرم JSON باشد. در نتیجه کار سرور دیگر فراهم کردن قالب و داده‌ها برای کلاینت است و بقیه‌ی ماجرا در سمت کلاینت رخ می‌دهد.
خیلی خوب، مزیت این کار نسبت به روش‌های معمول چیست؟ اگر اجازه بدهید این را با یک مثال شرح دهم:
در بسیاری از سایت ها، ویژگی ای به نام اسکرول نامحدود وجود دارد. در همین سایت نیز دکمه ای با عنوان بیشتر در انتهای لیستی از مطالب، برای مشاهده‌ی ادامه‌ی لیست قرار گرفته است. سعی کنید پس از فشردن دکمه‌ی بیشتر، داده‌های دریافتی از سرور را مشاهده کنید. پس از انجام این کار مشاهده خواهید کرد که پاسخ سرور HTML خام است. اگر تعداد 10 پست از سرور درخواست شود، 10 بار محتوای HTML تکراری نیز دریافت خواهد شد؛ در صورتی که ساختار HTML یک پست هم کفایت می‌کرد و تنها داده‌ها در آن 10 پست متفاوتند؛ چرا که قالب کار مشخص است و فقط به ازای هر پست باید آن داده‌ها در جای مناسب خود قرار داد.
دیدگاه‌های یک پست هم به خوبی با Angular قابل پیاده سازی است. قالب HTML یک دیدگاه را برای angular تعریف کرده و داده‌های مناسب که احتمالا JSON خام است از سرور دریافت شود. نتیجه‌ی این کار هم صرفه جوی در پهنای باند مصرفی و افزایش فوق العاده‌ی سرعت است، همچنین در صورت نیاز می‌توان داده‌ها و قالب‌ها راکش کرد تا مراجعه به سرور به حداقل برسد.
 چگونگی انجام این کار در AngularJs به صورت خلاصه به این صورت است که در angular یک directive به نام ng-repeat تعریف شده است که مانند یک حلقه‌ی foreach برای HTML عمل می‌کند. شما در داخل حلقه، قالب را مشخص می‌کنید و به ازای تعداد داده‌ها، آن حلقه تکرار می‌شود و بر روی داده‌ها پیمایش صورت می‌گیرد.
البته این مثال‌ها فقط دو نمونه از کاربرد این ویژگی در دنیای واقعی بود و مطمئن باشید که در مقالات آینده مثال‌های زیادی از این موضوع را پیاده‌سازی خواهیم کرد.
بهتر است که دیگر خیلی وارد جزئیات نشویم و اولین برنامه‌ی خود را به کمک angularjs بنویسیم. این برنامه، همان برنامه‌ی معروف Hello ,World است؛ اما در این برنامه به جای نوشتن یک Hello, World ساده در صفحه، آن را با ساختار angularjs پیاده‌سازی می‌کنیم.
در داخل ویژوال استادیو یک فایل HTML ساده ایجاد کنید و کد‌های زیر را داخل آن بنویسید.
<!DOCTYPE html>
<html ng-app>
<head>
    <title>Sample 1</title>
</head>
<body>
    <div ng-controller="GreetingController">
        <p>{{greeting.text}}, World!</p>
    </div>

    <script src="../Scripts/angular.js"></script>
    <script>
        function GreetingController($scope) {
            $scope.greeting = {
                text: "Hello"
            };
        }
    </script>
</body>
</html>
سپس فایل فوق را در مرورگر اجرا کنید. بله؛ عبارت Hello, World را مشاهده خواهید کرد. یک بار دیگر خاصیت text  را در scope.greeting$ به hi تغییر بدهید و باز هم نتیجه را مشاهده کنید.
این مثال در نگاه اول خیلی ساده است، اما دنیایی از مفاهیم angular را در بر دارد. شما خواص جدیدی را برای عناصر HTML مشاهده می‌کنید: ng-app، ng-controller، آکلود‌ها و عبارت درون آن و متغیر scope$ به عنوان پارامتر.
حال بیایید ویژگی‌ها و مفاهیم جالب کدهای نوشته شده را بررسی کنیم؛ چرا که فرصت برای بررسی ng-app و بقیه‌ی موارد نا آشنا زیاد است:

- هیچ id و یا class برای عناصر html در نظر گرفته نشده تا با استفاده از آنها، رویدادی را برای عناصر مورد نظر مشخص کنیم.

- وقتی در GreetingController مقدار greeting.text را مشخص کرده ایم، باز هم هیچ رویدادی را صدا نزده و یا مشخص نکرده ایم.

- GreetingController یک کلاس ساده‌ی جاوا اسکریپت (POJO) است و از هیچ چیزی که توسط angular فراهم شده باشد، ارث بری نکرده است.

- اگر به متد سازنده‌ی کلاس GreetingController دقت کنید، متغیر scope$ به عنوان پارامتر تعریف شده است. نکته‌ی جالب این است که ما هیچ گاه به صورت دستی سازنده‌ی کلاس GreetingController را صدا نزده ایم و حتی درون سازنده هم scope$ را ایجاد نکرده ایم؛ پس چگونه توانسته ایم خاصیتی را به آن نسبت داده و برنامه به خوبی کار کند. بهتر است برای پاسخ به این سوال خودتان دست به کار شوید؛ ابتدا نام متغیر scope$ را به نام دلخواه دیگری تغییر دهید و سپس برنامه را اجرا کنید. بله برنامه دیگر کار نمی‌کند. دلیل آن چیست؟ همان طور که گفتم Angular دارای یک سیستم تزریق وابستگی توکار است و در اینجا نیز scope$ به عنوان وابستگی در سازنده‌ی  این کلاس مشخص شده است تا نمونه‌ی مناسب آن توسط angular به کلاس GreetingController ما تزریق شود؛ اما چرا به نام آن یعنی scope$ حساس است؟ به این دلیل که زبان جاوا اسکریپت یک زبان پویا است و نوع در آن مطرح نیست؛ angular مجبور است که از نام پارامترها برای تزریق وابستگی استفاده می‌کند. در مقالات آینده چگونگی عملکرد سیستم تزریق وابستگی angular را به تشریح بیان می‌کنم.

- همچنین همان طور که در مورد قبلی نیز به آن اشاره کردم، ما هیچ گاه خود دستی سازنده‌ی GreetingController را صدا نزدیم و جایی نیز نحوه‌ی صدا زدن آن را مشخص نکرده ایم.

 تا همین جا فکر کنم کاملا برای شما مشخص شده است که ساختار فریمورک Angular با تمامی کتاب خانه‌های مشابه متفاوت است و با ساختاری کاملا اصولی و حساب شده طرف هستیم. همچنین در مقالات آینده توجه شما را به قابلیت‌هایی بسیار قدرتمند‌تر جلب خواهم کرد.
   
MVC ،MVP ، MVVM و یا MVW
 در بخش اول این مقاله، الگوی طراحی پیشنهادی فریمورک Angular را MVC بیان کرده‌ام؛ اما همان طور که گفته بودم AngularJS از انقیاد داده دوطرفه (Two Way Data Binding) نیز به خوبی پشتیبانی می‌کند و به همین دلیل عده ای آن را یک MVVM Framework تلقی می‌کنند. حتی داستان به همین جا ختم نمی‌شود و عده ای آن را به چشم MVP  Framework  نیز نگاه می‌کنند. در ابتدا سایت رسمی AngularJS الگوی طراحی مورد استفاده را MVC بیان می‌نمود ولی در این چند وقت اخیر عنوانش را به MVW Framework تغییر داده است.
MVW مخفف عبارت Model View Whatever هست و کاملا مفهومش مشخص است. Model و View بخش‌های مشترک تمام الگو‌ها بودند و تنها بخش سوم مورد اختلاف توسعه دهندگان بود؛ در نتیجه انتخاب آن را بر عهده‌ی استفاده کننده قرار داده اند و تمام امکانات لازم برای پیاده‌سازی این الگو‌های طراحی را فراهم کرده اند. در طی این مقالات صرف نظر از تمام الگوهای طراحی فوق، من بیشتر بر روی MVC تمرکز خواهم کرد.
الگوی طراحی MVC در سال 1970 به عنوان بخشی از زبان برنامه نویسی Smalltalk معرفی شد و از همان ابتدا به سرعت محبوبیت زیادی در بین محیط‌های توسعه‌ی دسکتاپی از قبیل ++C و Java  که رابط کاربری گرافیکی به نوعی در آن‌ها دخیل است، پیدا کرد.
تفکر MVC این را بیان می‌کند که باید جداسازی واضح و روشنی بین مدیریت داده‌ها (Model)، منطق برنامه (Controller) و نمایش داده‌ها به کاربر (View) وجود داشته باشد و در اصل هدفش جداسازی اجزای رابط کاربری به بخش هایی مجزا است.
     
شاید این سوال برای شما پیش بیاید که چرا باید چنین الگویی را در برنامه‌ها پیاده کرد؟
احتمالا تا کنون از بین برنامه هایی که نوشته اید، رابط کاربری بیشتر از آن‌ها را نیز خودتان مجبور شده اید طراحی کنید؛ به این دلیل که برنامه‌ی شما بدون رابط کاربری قابل اجرا شدن نبوده است. اجرای برنامه‌ی شما منوط به وجود تعدادی دکمه و textbox و ... بوده است و به قولی منطق برنامه به رابط گرافیکی گره خورده بوده است. پس می‌توان گفت که پیاده‌سازی الگوی طراحی وقتی ضرورت پیدا می‌کند که رابط گرافیکی، قسمتی از برنامه‌ی شما را تشکیل دهد.
آیا با وجود زبان‌های طراحی ساده ای مثل HTML و XAML و ... احتیاجی است که برنامه نویس وقت خود را صرف طراحی رابط کاربری کند؟ مسلما خیر، چون دیگر با این امکانات یک طراح هم از پس این کار به خوبی و یا حتی بهتر بر می‌آید. دیگر وظیفه‌ی برنامه نویس نوشتن کد‌های مربوط به منطق برنامه است. کدهایی که بدون UI هم قابل تست شدن باشد و به راحتی بتوان برای آن‌ها آزمون‌های واحد نوشت. برنامه نویس باید این را در نظر بگیرد که UI وجود ندارد و حتی ممکن است هیچ گاه هم ایجاد نشود و  این کد‌ها تبدیل به یک کتابخانه شود و مورد استفاده قرار بگیرد تا در یک برنامه با رابط کاربری گرافیکی.
در MVC، روال عمومی کار به این شکل است که View داده‌ها را از Model دریافت می‌کند و به کاربر نمایش می‌دهد. وقتی که کاربر با کلیک کردن و تایپ کردن با برنامه ارتباط برقرار می‌نماید، Controller به این درخواست‌ها پاسخ می‌دهد و داده‌های موجود در Model را به روز رسانی می‌کند. در نهایت هم Model  تغییرات خود را به View منعکس می‌کند تا View آن چه را که پیش از آن نمایش می‌داده است، تغییر دهد و View را از تغییرات رخ داده آگاه نماید.
اما در برنامه‌های Angular قضیه از چه قرار است؟ در Angular، قالب HTML  یا اگر بخواهم دقیق‌تر بگویم (Document Object Model(DOM معادل View است؛ کلاس‌های جاوا اسکریپتی نقش Controller را دارند؛ و خواص اشیای جاوا اسکریپتی و یا حتی خود اشیا نقش Model را بر عهده دارند.

ساختار بخشیدن به برنامه با استفاده MVC یک مزیت مهم دیگر نیز دارد: ساختار کار کاملا مشخص است و هر کسی نمی‌تواند به صورت سلیقه ای آن را پیاده سازی کند. با یک مثال این موضوع را تشریح می‌کنم: اگر کسی پروژه‌ی بنده را که با ASP.NET MVC نوشتم، بررسی کند، اصلا احساس غریبی نمی‌کند و به راحتی می‌تواند آن را توسعه دهد. دلیل این موضوع این است که ASP.NET MVC یک ساختار مشخص را به توسعه دهندگان اجبار کرده است و هر کسی این ساختار را رعایت کند و با آن آشنا باشد، به راحتی می‌تواند با آن کار کند. توسعه دهنده می‌داندکه من Model را کجا تعریف کرده ام، Controller مربوط به هر View کجاست و در کدام قسمت با پایگاه داده ارتباط برقرار کرده‌ام؛ اما در مورد کد‌های JavaScript و سمت کلاینت چه طور؟ توسعه دهنده ای که می‌خواهد کار من را ادامه بدهد دچار وحشت می‌شود! الگوی مشخصی وجود ندارد؛ معلوم نیست که کجا DOM را دستکاری کرده‌ام، در کدام قسمت با سرور ارتباط برقرار شده و... به قول معروف با یک اسپاگتی کد تمام عیار طرف می‌شود. AngularJS این مشکل را حل نموده و ساختار خاصی را سعی کرده به شما دیکته کند و تا حد ممکن دست شما را نیز باز گذاشته است. جدا از همه‌ی اینها، برنامه‌های مبتنی بر Angular به راحتی نگه داری  و تست می‌شوند و بدون هیچ دغدغه ای آن‌ها را می‌توان توسعه داد.
   
در حاشیه
شاید در هنگام دریافت فایل angularjs و افزودن آن به پروژه‌ی خود شروع به اعتراض کرده اید که نسخه‌ی فشرده شده‌ی آن 87 کیلو بایت حجم دارد در صورتی که این حجم در کتابخانه‌های مشابه ممکن است حتی به 10 کیلوبایت هم نرسد. اگر دقت کرده باشید من در بیان AngularJS از واژه‌ی کتاب خانه استفاده نکردم و فقط از واژه‌ی فریمورک استفاده کردم. بله نمی‌شود angular را با کتاب خانه هایی مقایسه کرد که مهمترین ویژگی خود را Data Binding می‌دانند. AngularJS یک بستر کاری قدرتمند است که تمام راه حل‌های موجود را در خود جمع کرده است. تیم توسعه دهنده‌ی آن هم هیچ ادعایی ندارد و می‌گویند که ما هیچ چیزی را خودمان اختراع نکرده ایم، بلکه راه حل‌های عالی را برگزیدیم، تفکرهای خوب را ارتقا بخشیده و در فریمورک خود استفاده کردیم و حتی از ایده‌های خوب دیگر کتاب خانه‌ها هم استفاده کرده ایم. بنابر این نباید به حجم آن در مقابل توانایی هایی که دارد اعتراض کرد.
   
همچنین به نظر می‌آید که AngularJS یک فریمورک پیچیده است. ولی من همیشه بین پیچیده و پیچیده شده تفاوت قائل می‌شوم. به نظر شخصی خودم Angular به دلیل مشکلات خاص و پیچیده ای که حل می‌کند پیچیده است و پیچیده شده نیست. اگر آن را پیچیده شده حس می‌کنید، تنها دلیلش، نحوه‌ی آموزش دادن بنده است، تمام سعی خود را می‌کنم که مفاهیم را تا حد ممکن ساده بیان کنم و امیدوارم در آینده که با مثال‌های بیشتری روبرو می‌شوید، این مفاهیم به کارتان بیاید.
     
در مقاله‌ی بعدی به مفاهیم انقیاد داده، تزریق وابستگی، هدایت گر‌ها (Directives) و سرویس‌ها در AngularJS می‌پردازم.
  
مطالب
آشنایی با SQL Server Data Tools
مقدمه
یکی از امکانات اضافه شده در Sql Server 2012 ابزار Sql Server Data Tools یا به اختصار SSDT می‌باشد. این ابزار در واقع جایگزین ابزار Business Intelligence Development Studio می باشد که همه امکانات قبلی را داشته و همچنین قابلیت‌های جدیدی نیز به آن اضافه شد است. اما کاربرد این ابزار ایجاد محیطی یکپارچه برای طراحی و توسعه تمامی نسخه‌های پایگاه داده Sql Server با استفاده از Visual Studio می‌باشد. در این مقاله من به بیشتر بر روی امکانات زیر تمرکز دارم:
  • Installation
  • Creating a SQL Server Database Project
  • Modify Database Schema
  • Schema Compare and Update
  • Snapshot Project
  • Publish
  1. نصب Sql Server Data Tools
    آخرین نسخه این ابزار را از این آدرس دانلود کنید یا زمان نصب Sql Server 2012 گزینه آن را انتخاب کنید


  2. ایجاد یک پروژه جدید از نوع  SQL Server Database Project
    پس از نصب SSDT شما از طریق Visual Studio 2012 Shell که همراه SqlServer 2012 نصب می‌شود یا با Visual Stadio 2012 یک پروژه جدید از نوع SQL Server Database Project ایجاد کنید.

     Server Database Project Project به شما امکان توسعه پایگاه داده Sql Server را با استفاده  از محیط یکپارچه Visual Studio با در اختیار گذاشتن ابزار‌های همچون navigation, intellisense, validation, debugging, declarative editing و غیره را می‌دهد. شی پایگاه داده شما در پروژه و فایل‌های مجزا ذخیره می‌شود مثل آن که شما در حال توسعه برنامه #C یا VB.NET هستید.
  3. ورود پایگاه داده موجود به پروژه SQL Server Database
    شما می‌توانید شمای پایگاه داده موجود یا SQL Server DAC Package File (.dacpac) یا هر T-SQL دیگری را با راست کلیک بر روی پروژه و انتخاب گزینه Import به پروژه خود اضافه و تغییرات لازم را اعمال نماید شکل زیر پنجره Import Database  را نشان می‌دهد:
     

      پنجره 
    Solution Explorer امکانات زیر را در اختیار شما قرارمی دهد:

    - اضافه کردن اشیای همچون Table، View  و غیره با راست کیلک کردن بر روی پروژه و انتخاب گزینه Add
    - ویرایش اشیا موجود با دبل کیلک کردن بر روی اشیا
    - مقایسه شمای پایگاه داده با پایگاه داده دیگر و یا Microsoft SQL Server DAC Package File کافیست بر روی پروژه راست کیلک و گزینه Schema Compare را         انتخاب نمایید.
    - ایجاد یک Snapshot از شمای پایگاه داده در یک Microsoft SQL Server DAC Package File . یک snapshot برای ایجاد یک پایگاه داده یا ورود در پروژه ای دیگر یا در مقایسه دو پایگاه داده کاربرد دارد.
    - انتشار پایگاه داده که امکان ایجاد پایگاه داده یر روی یک سرور SQL Server را فراهم می‌نماید.  

  4. مقایسه شمای دو پایگاه داده با هم
    SSDT ابزاری برای مقایسه دو پایگاه داده و بروز رسانی پایگاه داده مقصد از روی شمای منبع از طریق ایجاد یک Script یا به صورت مستقیم را می‌دهد.



  5. انتشار پروژه با استفاده از SQL Server Data Tools
    این ابزار امکان گسترش پروژه شما بر روی SQL Server 2005, 2008, 2008 R2, 2012, یا SQL Azure instance را می‌دهد. برای انتشار کافیت از پنجره Solution Explorer  بر روی پروژه راست کیلک و گزینه Publish را انتخاب کنید.

  6. پنجره SQL Server Object Explorer
    این پنجره با اتصال به سرور SQL Server  امکان دسترسی و مدیریت پایگاه داده را به ما می‌دهد. علاوه بر دسترسی به اجزای یک پایگاه داده امکان مدیریت پوشه‌های Security , Server Objects نیز فراهم می‌باشد. همچنین امکان اتصال به Sql Server Express , localdb نیز وجود دارد. 


  7.   
مطالب
تنظیمات پیشنهادی حداکثر حافظه‌ی مصرفی اس کیوال سرور

به صورت پیش فرض تنظیمات حافظه‌ی اس کیوال سرور به صورتی است که به آن اجازه می‌دهد تمامی حافظه‌ی مهیای سیستم عامل را مصرف کند! اگر شخصی با این مساله آشنایی نداشته باشد احتمالا تصور خواهد کرد که اس کیوال سرور نشتی حافظه دارد یا کلا مشکلی در سیستم روی داده است که تا این حد مصرف حافظه بالا رفته است.
برای مشاهده‌ی این تنظیمات روی instance سرور مورد نظر کلیک راست کرده و گزینه خواص را انتخاب کنید. سپس در صفحه‌ی باز شده گزینه memory را مشاهده نمائید.
البته این‌کار را با استفاده از دستورات T-SQL هم می‌توان انجام داد:

EXEC sp_configure 'show advanced options', 1
RECONFIGURE WITH OVERRIDE

EXEC sp_configure 'max server memory (MB)'

EXEC sp_configure 'show advanced options', 0
RECONFIGURE WITH OVERRIDE

نتیجه‌ی آن بر روی سیستم برنامه نویسی من به صورت زیر است:



که البته عمدا آن‌را بر روی یک گیگ تنظیم کرده‌ام تا عملکرد سیستم مختل نشود. (چون اگر غیر از این باشد، تعارفی نداشته و هر آنچه را که صلاح بداند مصرف می‌کند!)
کمی در بلاگ‌های رسمی برنامه نویس‌های اس کیوال سرور در سایت MSDN در این‌‌باره جستجو کردم و نتیجه آن به صورت زیر است:

تنظیمات حداکثر حافظه‌ی مصرفی اس کیوال سرورهای 2005 و 2008
برای یک سیستم عامل 64 بیتی:

Physical RAM MaxMem Setting
2GB 1500
4GB 3200
6GB 4800
8GB 6700
12GB 10600
16GB 14500
24GB 22400
32GB 30000
48GB 45000
64GB 59000


برای سروری 32 بیتی این اعداد حداکثر را تقریبا منهای 300 مگابایت نمائید. (و البته همانطور که مطلع هستید در سیستم عامل‌های سرور 32 بیتی، اگر بیشتر از 2 گیگا بایت رم داشتید سوئیچ 3GB و اگر بیشتر از 4 گیگابایت رم مهیا بود، سوئیچ PAE باید در boot.ini تنظیم شوند. در غیر اینصورت هزینه‌ی سخت افزاری بیهوده‌ای را متحمل شده‌اید، زیرا استفاده‌ی بهینه‌ای از آن در یک سیستم عامل 32 بیتی نخواهد شد)

و این اعداد را همانطور که ذکر شد، در تنظیمات سرور می‌توان وارد نمود ( از طریق management studio ) و یا با استفاده از دستورات T-SQL نیز این امر میسر است: (در مثال زیر حداکثر حافظه مجاز مصرفی به 2300 مگابایت تنظیم می‌شود)

EXEC sp_configure 'show advanced options', 1
RECONFIGURE WITH OVERRIDE

EXEC sp_configure 'max server memory (MB)', 2300

EXEC sp_configure 'show advanced options', 0
RECONFIGURE WITH OVERRIDE

و البته لازم به ذکر است که اعداد فوق برای حالتی پیشنهاد شده است که سرور مورد نظر فقط یک کار و آن‌هم اجرا و سرویس دهی اس کیوال سرور را به عهده داشته باشد. بدیهی است اگر از این سرور استفاده‌های دیگری هم می‌شود این اعداد را باید کمتر نیز در نظر گرفت.


برای مطالعه‌ی بیشتر
http://sqlnerd.blogspot.com/2006/07/memory-use-in-sql-server.html
http://blogs.msdn.com/axperf/archive/2008/03/10/welcome-database-configuration-checklist-part-1.aspx
http://technet.microsoft.com/en-us/library/bb124810.aspx

مطالب
نمایش تقویم ماهیانه شمسی توسط PdfReport
در نگارش 1.6، قالب سلول جدیدی به نام MonthCalendar اضافه شده است که امکان نمایش تقویم ماهیانه شمسی و میلادی را فراهم می‌کند. در ادامه نحوه استفاده از آن‌را بررسی خواهیم کرد. کدهای کامل این مثال را از اینجا نیز می‌توانید دریافت کنید: (^)
فرض کنید اطلاعات حضور و غیاب کارمندان را به نحو زیر در اختیار دارید:
namespace PdfReportSamples.Models
{
    public class UserWorkedHours
    {
        public int Id { set; get; }
        public string Name { set; get; }
        public int DayNumber { set; get; }
        public int Month { set; get; }
        public int Year { set; get; }
        public string Description { set; get; }
    }
}
و برای نمونه منبع داده فرضی ما نیز به صورت زیر است (تعدادی روز، به همراه ساعات کارکرد):
        private static List<UserWorkedHours> createUsersWorkedHours()
        {
            var usersWorkedHours = new List<UserWorkedHours>();
            for (int i = 1; i < 11; i++)
            {
                for (int j = 1; j < 28; j++)
                {
                    usersWorkedHours.Add(new UserWorkedHours
                    {
                        Id = i,
                        Name = "کارمند " + i,
                        Year = 1391, // سال و ماه بر اساس نوع تقویم انتخابی مشخص می‌شود
                        Month = i,
                        DayNumber = j,
                        Description = i % 2 == 0 ? "05:00" : "08:00"
                    });
                }
            }
            return usersWorkedHours;
        }
در این منبع داده فرضی، متن Description ذیل شماره روز، در تقویم ماهیانه نمایش داده خواهد شد.
سلولی که قرار است قالب MonthCalendar را نمایش دهد نیاز به شیء‌ایی از نوع PdfRpt.Calendar.CalendarData دارد که به نحو زیر تعریف شده است:
using System.Collections.Generic;

namespace PdfRpt.Calendar
{
    public class CalendarData
    {
        public int Month { set; get; }
        public int Year { set; get; }
        public IList<DayInfo> MonthDaysInfo { set; get; }
    }
}

namespace PdfRpt.Calendar
{
    public class DayInfo
    {
        public int DayNumber { set; get; }
        public int Month { set; get; }
        public int Year { set; get; }

        public string Description { set; get; }
        public bool ShowDescriptionInFooter { set; get; }
    }
}
این ساختار بر اساس اطلاعات یک ماه و روزهای آن است. متن Description در صورت false بودن ShowDescriptionInFooter ذیل شماره روز نمایش داده خواهد شد، در غیراینصورت در پایان ماه به شکل یک سطر جدید نمایش داده می‌شود. در اینجا روزهای ماه و سال بر اساس نوع تقویم معنا خواهند شد.

اکنون نیاز است تا اطلاعات منبع داده خود را به CalendarData نگاشت کنیم تا بتوان از آن در قالب سلول جدید MonthCalendar استفاده کرد. انجام اینکار با استفاده از امکانات LINQ به نحو زیر است:
        public static IList<UserMonthCalendar> CreateDataSource()
        {
            var usersWorkedHours = createUsersWorkedHours();
            // Mapping a list of normal Users WorkedHours to a list of Users + CalendarData
            return usersWorkedHours
                        .GroupBy(x => new
                        {
                            Id = x.Id,
                            Name = x.Name
                        })
                        .Select(
                                 x => new UserMonthCalendar
                                 {
                                     Id = x.Key.Id,
                                     Name = x.Key.Name,
                                     // Calendar's cell data type should be PdfRpt.Calendar.CalendarData
                                     MonthCalendarData = new CalendarData
                                     {
                                         Year = x.First().Year,
                                         Month = x.First().Month,
                                         MonthDaysInfo = x.ToList().Select(y => new DayInfo
                                         {
                                             Description = y.Description,
                                             ShowDescriptionInFooter = false,
                                             DayNumber = y.DayNumber
                                         }).ToList()
                                     }
                                 }).ToList();
        }
UserMonthCalendar، شامل ستون‌هایی است که قرار است در گزارش ما ظاهر شوند:
using PdfRpt.Calendar;

namespace PdfReportSamples.Models
{
    public class UserMonthCalendar
    {
        public int Id { set; get; }
        public string Name { set; get; }
        // Calendar's cell data type should be CalendarData
        public CalendarData MonthCalendarData { set; get; }
    }
}
ستون اول، شماره شخص، ستون دوم شامل نام شخص و ستون سوم، شامل اطلاعات یک ماه شخص است.
برای نمایش این اطلاعات توسط PdfReport، دو ستون اول یاد شده نکته خاصی ندارند، اما نحوه تعریف ستون تقویم ماهیانه آن به صورت زیر خواهد بود:
                columns.AddColumn(column =>
                {
                    // Calendar's cell data type should be PdfRpt.Calendar.CalendarData
                    column.PropertyName<UserMonthCalendar>(x => x.MonthCalendarData);
                    column.CellsHorizontalAlignment(HorizontalAlignment.Center);
                    column.IsVisible(true);
                    column.Order(3);
                    column.Width(3);
                    column.HeaderCell("تقویم ماهیانه");
                    column.ColumnItemsTemplate(itemsTemplate =>
                    {
                        itemsTemplate.MonthCalendar(new CalendarAttributes
                        {
                            CalendarType = CalendarType.PersianCalendar,
                            UseLongDayNamesOfWeek = true,
                            Padding = 3,
                            DescriptionHorizontalAlignment = HorizontalAlignment.Center,
                            SplitRows = true,
                            CellsCustomizer = info =>
                            {
                                if (info.Year == 1391 && info.Month == 1 && info.DayNumber == 1)
                                {
                                    info.NumberCell.BackgroundColor = new BaseColor(System.Drawing.Color.LimeGreen);
                                    var phrase = info.NumberCell.Phrase;
                                    foreach (var chunk in phrase.Chunks)
                                        chunk.Font.Color = new BaseColor(System.Drawing.Color.Yellow);
                                }
                            }
                        });
                    });
                });
توسط CalendarAttributes می‌توان یک سری از خواص تقویم نمایش داده شده را تغییر داد. برای مثال CalendarType مشخص می‌کند که نوع تقویم شمسی است یا میلادی؛ UseLongDayNamesOfWeek برای نمایش نام روزها به صورت کامل «شنبه» یا «ش» (نام کوتاه شده آن) بکار می‌رود. SplitRows مشخص می‌کند که اگر تقویم در یک صفحه جا نشد، به صفحه بعد منتقل شود یا تا جایی که ممکن است در صفحه جاری اطلاعات آن نمایش داده شده و سپس مابقی را در صفحه بعد ترسیم کند (مقدار true آن). به علاوه توسط CellsCustomizer می‌توان فرمت کردن شرطی اطلاعات را انجام داد. برای مثال در اینجا اگر روز مورد نظر، روز اول سال 91 باشد، رنگ زمینه سلول و رنگ متن عدد آن تغییر خواهد کرد.
 

مطالب
پردازش فایل‌های XML با استفاده از jQuery

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

و در حالت کلی :
http://api.feedburner.com/awareness/1.0/GetFeedData?uri=<feeduri>

که حاصل آن برای مثال یک فایل XML با فرمت زیر می‌باشد:

<rsp stat="ok">
<feed id="fhphjt61bueu08k93ehujpu234" uri="vahidnasiri">
<entry date="2009-01-23" circulation="153" hits="276" reach="10"/>
</feed>
</rsp>

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

<script src='http://ajax.googleapis.com/ajax/libs/jquery/1.3.1/jquery.min.js' type='text/javascript'></script>

نحوه خواندن مقدار circulation فایل xml ذخیره شده بر روی کامپیوتر:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>FeedBurner API</title>
<script src='http://ajax.googleapis.com/ajax/libs/jquery/1.3.1/jquery.min.js' type='text/javascript'>
</script>
<script type="text/javascript">
function parseXml(xml){
//find every entry and print the circulation
$(xml).find("entry").each(function(){
$("#output").append($(this).attr("circulation"));
});
}

$(document).ready(function(){
$.ajax({
type: "GET",
url: "GetFeedData_local.xml",
dataType: "xml",
success: parseXml
});
});
</script>
</head>
<body>
<div dir="rtl" style="font-family:tahoma; font-size:12px;">
تعداد مشترکین تغذیه خبری سایت:
<div id="output">
</div>
</div>
</body>
</html>

با استفاده از قابلیت Ajax کتابخانه jQuery ، اطلاعات فایل محلی GetFeedData_local.xml دریافت شده و محتوای آن به تابع parseXml پاس می‌شود (توسط قسمت success). سپس در این تابع تمام تگ‌های entry یافت شده و مقدار circulation آن‌ها به یک div با ID معادل output اضافه می‌شود.
مثال فوق در مورد خواندن اطلاعات از یک فایل xml می‌تواند برای مثال این کاربرد را در یک سایت داشته باشد:
نمایش اتفاقی سخن روز یا سخن بزرگان و امثال آن بدون برنامه نویسی سمت سرور جهت انجام این کار از یک فایل xml تهیه شده، بدون نیاز به استفاده از دیتابیس خاصی.

تا اینجای کار مشکلی نیست. اما همانطور که در مطلب مقابله با حملات CSRF نیز ذکر شد، مرورگرهای جدید امکان ارسال یا دریافت اطلاعات به صورت Ajax را بین سایت‌ها ممنوع کرده‌اند (ماجرا هم از آنجا شروع شد که یکبار جی‌میل این باگ امنیتی را داشته است). بنابراین اگر شما بجای url قسمت Ajax فوق، آدرس سایت فید برنر را قرار دهید با خطای زیر متوقف خواهید شد:

Access to restricted URI denied

تمام موارد دیگری هم که در jQuery برای دریافت اطلاعات از یک فایل یا url موجود است (مثلا تابع load یا get و امثال آن) فقط به سایت جاری و دومین جاری باید ختم شوند در غیر اینصورت توسط مرورگرهای جدید متوقف خواهند شد.

نظرات مطالب
استفاده از قابلیت پارتیشن بندی در آرشیو جداول بانک‌های اطلاعاتی SQL Server
در مثال مذکور از Partition Key در زمان تعریف یک Primary Key Constraint روی جدول به منظور داشتن ساختار Aligned Index ، استفاده نموده ایم.
در هنگام ایجاد یک Primary Key Constraint بطور خودکار یک Unique Clustered Index  نیز روی ستون (های) شرکت یافته در تعریف  Primary Key ایجاد می‌شود و بدین ترتیب Table براساس این فیلد (ها) به شکل Sort شده نگهداری می‌شود، ضمن اینکه هر Table می‌تواند، شامل 1 عدد Clustered Index و 249 عدد Nonclustered Index باشد.
مطالب
مسیریابی در AngularJs #بخش اول
در مطالب قبل کنترلر‌ها و view‌ها مورد بحث قرار گرفتند. در این پست در نظر داریم یکی از ویژگی‌های دیگر AngularJs به نام مسیر یابی (Routing) را مورد بحث قرار دهیم.
یکی از ویژگی‌های برنامه‌های تک صفحه ای عدم Reload شدن صفحات است ،بر خلاف برنامه‌های وب چند صفحه ای که برای نمایش صفحه ای دیگر ، باید از صفحه ای به صفحه ای دیگر منتقل شد و عمل Reload هم به طبع نیز اتفاق می‌افتد.
در قسمت اول  این سری مقالات ، مزایای برنامه‌های وب تک صفحه ای SPA به صورت کاملتری  بیان شده است. در ادامه ما قصد داریم برنامه‌ی وب خود را به صفحات مختلف تقسیم کنیم و سپس با استفاده از امکان مسیریابی موجود در AngularJs آن صفحات را که هر کدام به کنترلری مجزا مقید شده اند، در صفحه‌ی اصلی خود بارگزاری کنیم. همچین استفاده از مسیریابی موجود، میتواند به ما در مدیریت بهتر صفحات کمک فراوانی بکند.
به تصویر زیر دقت کنید :  

در تصویر بالا دو مسیر با آدرس‌های : ShowPage1/  و ShowPage2/  تعریف شده است که هر کدام به یک view مشخص و یک Controller برای مدیریت آن اشاره میکند.

زمانی که ما از تزریق وابستگی‌ها در AngularJs استفاده میکنیم و یک شیء را به کنترلر تزریق میکنیم، Angular توسط Injector$  سعی در پیدا کردن وابستگی مربوطه و سپس تزریق آن به کنترلر را انجام میدهد. برای استفاده از امکان مسیریابی Route ، ما نیز باید از پروایدر مخصوص آن برای تزریق استفاده کنیم. در Angular مسیر‌های برنامه توسط پروایدری به نام routeProvider$ شناسایی میشود که خدمات مسیریابی را به ما ارائه میدهد. این سرویس به ما کمک میکند تا بتوانیم اتصال بین کنترلر ها، ویوها و آدرس URL جاری مرورگرها را به آسانی برقرار کنیم.

بهتر است کار را شروع کنیم . یک فایل JS ایجاد و سپس محتویات زیر را در آن قرار دهید : 

var myFirstRoute = angular.module('myFirstRoute', []);
  
myFirstRoute.config(['$routeProvider',
  function($routeProvider) {
    $routeProvider.
      when('/pageOne', {
        templateUrl: 'templates/page_one.html',
        controller: 'ShowPage1Controller'
      }).
      when('/pageTwo', {
        templateUrl: 'templates/page_two.html',
        controller: 'ShowPage2Controller'
      }).
      otherwise({
        redirectTo: '/pageOne'
      });
}]);


myFirstRoute.controller('ShowPage1Controller', function($scope) {
    $scope.message = 'Content of page-one.html';
});
 
 
myFirstRoute.controller('ShowPage2Controller', function($scope) {
    $scope.message = 'Content of page-two.html';
});

در کدهای بالا ابتدا یک ماژول تعریف کرده ایم و سپس توسط ()config. تنظیمات مربوط به مسیریابی را انجام داده ایم. با استفاده از متدهای when. و otherwise. میتوانیم مسیرها را تعریف کنیم. برای هر مسیر دو پارامتر وجود دارد که اولین پارامتر نام مسیر و دومین پارامتر شامل 2 قسمت میشود که templateUrl  آن آدرسی که باز خواهد شد و controller نیز نام کنترلری که ویو را مدیریت میکند.

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

در قطعه کد بالا همچنین دو مسیر با نام‌های pageOne/ و pageTwo/ تعریف کرده ایم که هر کدام به ترتیب به View‌های : templates/page_one.html و templates/page_two.html مرتبط شده اند. همچنین دو کنترلر برای مدیریت ویو‌ها نیز تعریف شده است.

زمانی که ما آدرس http://appname/#pageOne را در نوار آدرس مرورگر وارد میکنیم، Angular به صورت اتوماتیک آدرس URL را با تنظیماتی که ما در اینجا تعریف کرده ایم مطابقت میدهد و در صورت وجود چنین آدرسی ، view مربوطه را بارگزاری میکند و در این مثال نیز مطابق با تنظیمات بالا، صفحه‌ی templates/page_one.html برای ما بارگزاری و سپس کنترلر ShowPage1Controller را فراخوانی میکند ، جایی که ما منطق کار را در آن قرار میدهیم.

محتویات فایل main.html :  

<body ng-app="app">
  
    <div>
        <div>
        <div>
            <ul>
                <li><a href="#pageOne"> Show page one </a></li>
                <li><a href="#pageTwo"> Show page two </a></li>
            </ul>
        </div>
        <div>
            <div ng-view></div>
        </div>
        </div>
    </div>
  
    <script src="http://ajax.googleapis.com/ajax/libs/angularjs/1.0.7/angular.min.js"></script>
    <script src="app.js"></script>
  
  </body>

در قطعه کد بالا دو لینک تعریف شده است که ویژگی href از علامت هش و نام صفحه تشکیل شده است. یکی از چیزهایی که شایان ذکر است ، دایرکتیو ng-view است. مکانی برای بارگزاری صفحات در آن.

ما میتوانیم این تگ را به سه شکل زیر نیز استفاده کنیم :

<div ng-view></div>
..
<ng-view></ng-view>
..
<div class="ng-view"></div>

محتویات صفحه  templates/page_one.html :

<h2>Page One</h2>
 
{{ message }}

محتویات صفحه templates/page_two.html :

<h2>Page Two</h2>
 
{{ message }}

حال اگر پروژه را اجرا کنید و به کنسول مرور گر خود نگاه کنید متوجه میشوید که مسیریاب از مسیر پیشفرض استفاده کرده است و صفحه‌ی page_one.html را به صورت ایجکسی فراخوانی کرده است :

و اگر روی لینک Show Page two کلیک کنید ، صفحه‌ی page_two.html نیز به صورت ایجکسی فراخوانی میشود.

دوباره بر روی لینک Show page one کلیک کنید. بله. هیچ درخواستی به سمت سرور ارسال نشد و صفحه‌ی page_one.html به خوبی نمایش داده شد. یکی از مزیت‌های سیستم مسیریابی قابلیت کش کردن صفحات است تا در صورت فراخوانی مجدد، درخواستی به سمت سرور ارسال نشود و خیلی سریع به شما نمایش داده شود.

مثال این مطلب : RouteExample.zip  

ادامه دارد ...

مطالب
C# 7 - Local Functions
توابع محلی، امکان تعریف یک تابع را درون یک متد، فراهم می‌کنند. هدف آن‌ها تدارک توابعی کمکی است که به سایر قسمت‌های کلاس مرتبط نمی‌شوند. برای مثال اگر متدی نیاز به کار با یک private method دیگر را دارد و این متد خصوصی در جای دیگری استفاده نمی‌شود، می‌توان جهت بالابردن خوانایی برنامه و سهولت یافتن متد مرتبط، این متد خصوصی را تبدیل به یک تابع محلی، درون همان متد کرد.
static void Main(string[] args)
{
    int Add(int a, int b)
    {
        return a + b;
    }
 
    Console.WriteLine(Add(3, 4)); 
}


بازنویسی کدهای C# 6 با توابع محلی C# 7

کلاس زیر را که بر اساس امکانات C# 6 تهیه شده‌است، در نظر بگیرید:
public class PersonWithPrivateMethod
{
    public string Name { get; set; }
    public int Age { get; set; }

    public override string ToString()
    {
        string ageSuffix = GenerateAgeSuffix(Age);
        return $"{Name} is {Age} year{ageSuffix} old";
    }

    private string GenerateAgeSuffix(int age)
    {
        return age > 1 ? "s" : "";
    }
}
متد خصوصی همین کلاس را توسط Func delegates می‌توان به صورت ذیل خلاصه کرد (باز هم بر اساس امکانات C# 6):
public class PersonWithLocalFuncDelegate
{
    public string Name { get; set; }
    public int Age { get; set; }

    public override string ToString()
    {
        Func<int, string> generateAgeSuffix = age => age > 1 ? "s" : "";
        return $"{Name} is {Age} year{generateAgeSuffix(Age)} old";
    }
}
به این ترتیب نیاز به تعریف یک متد private دیگر کمتر خواهد شد.
اکنون در C# 7 می‌توان این Func delegate را به نحو ذیل تبدیل به یک local function کرد:
public class PersonWithLocalFunction
{
    public string Name { get; set; }
    public int Age { get; set; }

    public override string ToString()
    {
        return $"{Name} is {Age} year{GenerateAgeSuffix(Age)} old";
        // Define a local function:
        string GenerateAgeSuffix(int age)
        {
            return age > 1 ? "s" : "";
        }
    }
}


مزیت کار با local functions نسبت به Func delegates محلی

در قطعه کد فوق، کار انجام شده صرفا استفاده‌ی از یک Syntax جدید نیست؛ بلکه از لحاظ کارآیی نیز سربار کمتری را به همراه دارد. زمانیکه Func Delegates تعریف می‌شوند، کار ایجاد یک anonymous type، وهله سازی و فراخوانی آن‌ها توسط کامپایلر صورت می‌گیرد. اما حین کار با توابع محلی، کامپایلر با یک متد استاندارد سروکار دارد و هیچکدام از مراحل یاد شده و سربارهای آن‌ها رخ نمی‌دهند (هیچگونه GC allocation ایی نخواهیم داشت). به علاوه اینبار کامپایلر فرصت in-line تعریف کردن متد را به نحو بهتری یافته و به این ترتیب کار سوئیچ بین متدهای مختلف کاهش پیدا می‌کند که در نهایت سرعت برنامه را افزایش می‌دهند.


میدان دید توابع محلی

البته با توجه به اینکه متد مثال فوق محلی است، به تمام متغیرها و پارامترهای متد دربرگیرنده‌ی آن نیز دسترسی دارد. بنابراین می‌توان پارامتر int age آن‌را نیز حذف کرد:
public class PersonWithLocalFunctionEnclosing
{
    public string Name { get; set; }
    public int Age { get; set; }

    public override string ToString()
    {
        return $"{Name} is {Age} year{GenerateAgeSuffix()} old";
        // Define a local function:
        string GenerateAgeSuffix()
        {
            return Age > 1 ? "s" : "";
        }
    }
}
به همین جهت نمی‌توانید داخل یک تابع محلی، متغیری را تعریف کنید که هم‌نام یکی از متغیرها یا پارامترهای متد دربرگیرنده‌ی آن باشد.


خلاصه نویسی توابع محلی به کمک expression bodies

می‌توان این متد محلی را به صورت یک expression body ارائه شده‌ی در C# 6 نیز بیان کرد:
public class PersonWithLocalFunctionExpressionBodied
{
    public string Name { get; set; }
    public int Age { get; set; }

    public override string ToString()
    {
        return $"{Name} is {Age} year{GenerateAgeSuffix(Age)} old";
        // Define a local function:
        string GenerateAgeSuffix(int age) => age > 1 ? "s" : "";
    }
}


روش ارسال یک local function به متدی دیگر

امکان ارسال یک تابع محلی به صورت یک Func delegate به متدی دیگر نیز وجود دارد:
public class LocalFunctionsTest
{
    public void PassAnonFunctionToMethod()
    {
        var p = new SimplePerson
        {
            Name = "Name1",
            Age = 42
        };
        OutputSimplePerson(p, GenerateAgeSuffix);
        string GenerateAgeSuffix(int age) => age > 1 ? "s" : "";
    }
 
    private void OutputSimplePerson(SimplePerson person, Func<int, string> suffixFunction)
    {
        Output.WriteLine(
        $"{person.Name} is {person.Age} year{suffixFunction(person.Age)} old");
    }
}
در این مثال GenerateAgeSuffix یک Local function است که به صورت expression body نیز بیان شده‌است. برای ارسال آن به متد OutputSimplePerson، پارامتر دریافتی آن باید به صورت Func تعریف شود.
نظرات مطالب
EF Code First #12
علت وقوع خطا، در استثنای صادره ذکر شده: Page not found. یعنی کاربر یا حتی مرورگر درخواست آدرسی رو کرده که در سایت شما موجود نیست (مثلا کروم اولین کاری که انجام می‌ده، وجود فایل استاندارد آیکن سایت رو به صورت خودکار بررسی می‌کنه). بنابراین امکان وهله سازی کنترلر معادل آن صفحه یا آدرس یافت نشده، وجود ندارد.