مطالب
آشنایی با NuGet - قسمت اول

NuGet چیست؟

روش متداول استفاده از کتابخانه‌های موجود دات نتی در Visual studio‌ عموما به این صورت است: مراجعه به سایت مربوطه، دریافت بسته مورد نظر، باز کردن آن و سپس افزودن ارجاعی به اسمبلی‌های آن کتابخانه. در این حالت زمانیکه نسخه‌ی جدیدی از کتابخانه‌ی مورد استفاده ارائه ‌شود (و عموما تا مدت‌ها شاید از آن بی‌اطلاع باشیم) تمام این مراحل باید از ابتدا تکرار شوند و همینطور الی آخر.
برای رفع این نقیصه، تیم ASP.NET، افزونه‌ای سورس باز و رایگان را به نام NuGet جهت VS.Net 2010 طراحی کرده‌اند که کار مدیریت بسته‌های کتابخانه‌های مورد استفاده را بسیار ساده کرده است. امکانات این افزونه پس از نصب، در دو حالت استفاده از رابط گرافیکی کاربری آن و یا با استفاده از خط فرمان PowerShell ویندوز در دسترس خواهد بود. این افزونه در زمان بارگذاری، با مراجعه به فید سایت مرکزی خود، لیست بسته‌های مهیا را در اختیار علاقمندان قرار می‌دهد. درب این سایت مرکزی به روی تمام توسعه‌ دهنده‌ها جهت افزودن بسته‌های خود باز است.
و ... فراگیری کار با NuGet برای تمام برنامه نویسان دات نت لازم و ضروری است! از این جهت که پیغام "این بسته تنها برای NuGet عرضه شده است" کم کم در حال متداول شدن می‌باشد و دیگر سایت‌های مرتبط، لینک مستقیمی را جهت دریافت کتابخانه‌های خود ارائه نمی‌دهند. حتی خبر به روز شدن محصولات خود را هم شاید دیگر به صورت منظم ارائه ندهند؛ زیرا NuGet کار مدیریت آن‌ها را به عهده خواهد داشت.


دریافت و نصب NuGet

NuGet را حداقل به سه طریق می‌توان دریافت و نصب کرد:
الف) با مراجعه به سایت CodePlex : (+)
ب) دریافت آن از سایت گالری‌های آن : (+)


ج) با استفاده از امکانات VS.NET

هر سه روش فوق به دریافت و نصب فایل NuGet.Tools.vsix منتهی می‌شوند. برای مثال در روش (ج) باید به منوی Tools و گزینه‌ی Extension Manager مراجعه کنید. سپس برگه‌ی Online Gallery را گشوده و اندکی صبر کنید تا اطلاعات آن دریافت و نمایش داده شود. سپس NuGet را در Search box بالای صفحه نوشته و NuGet Package manager ظاهر شده را انتخاب و نصب کنید.



نحوه استفاده از NuGet

فرض کنید یک پروژه جدید ASP.NET را ایجاد کرده‌اید و نیاز است تا کتابخانه‌ی ELMAH به آن اضافه شود. روش انجام اینکار را به کمک NuGet در ادامه بررسی خواهیم کرد (کمتر از یک دقیقه زمان خواهد برد):

الف) با کمک امکانات رابط گرافیکی کاربر آن
ساده‌ترین روش استفاده از NuGet ، کلیک راست بر روی پوشه References در Solution explorer و سپس انتخاب گزینه‌ی Add Library Package Reference می‌باشد:



در صفحه‌ی باز شده، برگه‌ی Online را باز کنید و مدتی صبر نمائید تا اطلاعات لازم دریافت گردد (در زمان نگارش این مطلب، 1135 بسته در این مخزن موجود است):



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



اکنون با کلیک بر روی دکمه Install ، بسته مرتبط با این کتابخانه دریافت شده و سپس به صورت خودکار ارجاعی به آن نیز افزوده خواهد شد. همچنین تنظیمات مرتبط با فایل Config برنامه هم اضافه می‌شوند.

روش دیگر ظاهر کردن این صفحه، مراجعه به منوی Tools و گزینه‌ی Library Package Manager می‌باشد:



جهت دریافت به روز رسانی‌های بسته‌های نصب شده تنها کافی است به برگه‌ی Updates این صفحه مراجعه کرده و موارد لیست شده را نصب نمائیم:



نکته: NuGet در SharpDevelop 4.1 به بعد هم پشتیبانی می‌شود:




ب) با استفاده از امکانات خط فرمان PowerShell ویندوز
برای استفاده از امکانات پاورشل ویندوز نیاز است تا پاورشل نگارش 2 بر روی سیستم شما نصب باشد (نیاز به Windows XP with Service Pack 3 به بعد دارد). سپس به منوی Tools ، قسمت Library Package Manager ، گزینه‌ی Package Manager Console آن جهت فعال سازی کنسول پاور شل در VS.NET مراجعه نمائید:


نکته: در تصویر فوق پس از نوشتن el ، دکمه tab فشرده شده است. در این حالت منوی پکیج‌های مهیای شروع شده با el، از سایت مرکزی NuGet ظاهر گردیده است.

فرامین مهمی که در اینجا در دسترس هستند شامل: List-Package ، Uninstall-Package ، Update-Package و Get-Package می‌باشند. برای مثال اگر قصد جستجو در بین بسته‌های موجود را داشته باشید Get-Package بسیار مفید است:



برای مثال جهت یافتن بسته‌های مرتبط با wpf و silverlight به صورت زیر می‌توان عمل کرد:
PM> get-package -remote -filter wpf
PM> get-package -remote -filter silverlight

نکته: روش دیگر جستجو در بین بسته‌های مهیا، مراجعه به سایت گالری آن است : (+) . در اینجا دستور پاورشل نصب هر بسته‌ی یافت شده نیز نمایش داده می‌شود.


ج) استفاده از برنامه NuGet.exe
برنامه NuGet.exe از سایت CodePlex قابل دریافت است. این روش هم جهت علاقمندان به خط فرمان تدارک دیده شده است!
پس از دریافت آن فرض کنید می‌خواهیم تمام بسته‌های شروع شده با nhi را لیست کنیم. برای این منظور دستور خط فرمان ذیل را صادر کنید:
D:\Test>nuget list nhi
سپس برای دریافت مثلا NHibernate تنها کافی است دستور زیر اجرا شود:
D:\Test>nuget install NHibernate

به این صورت کتابخانه NHibernate ‌به همراه تمام وابستگی‌های آن دریافت خواهد شد.

به روز رسانی خودکار NuGet
برای به روز رسانی برنامه nuget.exe دستور زیر را می‌توان صادر نمود:
D:\Test>NuGet.exe u
و یا جهت فعال سازی به روز رسانی‌های خودکار افزونه‌ها در VS.NET به منوی زیر مراجعه کنید:
Tools | Options, then Environment | Extension Manager and click "Automatically check for updates to installed extensions."





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

مطالب
اعتبار سنجی سمت کاربر wysiwyg-editor ها در ASP.NET MVC
تفاوتی نمی‌کند که از کدامیک از HTML Editorها یا به عبارتی wysiwyg-editorهای موجود، جهت ورود اطلاعات استفاده می‌کنید. هیچکدام از آن‌ها سبب فراخوانی اعتبارسنجی Required سمت کاربر نمی‌شوند. چرا؟
علت اینجا است که با فعال سازی wysiwyg-editorهای موجود، المان HTML پیش فرض مانند یک TextArea حالت مخفی پیدا می‌کند:


و اگر به سورس کد فایل jquery.validate.js مراجعه کنید، یک چنین تعریف پیش فرضی در آن موجود است:
$.extend( $.validator, {
defaults: {
ignore: ":hidden",
به این معنا که در حین اعتبارسنجی سمت کاربر، از کلیه المان‌های hidden بر روی صفحه صرفنظر خواهد شد.
برای رفع این مشکل کافی است بنویسیم:
 jQuery.validator.setDefaults({ ignore: ":hidden:not(textarea)" });
در اینجا پیش فرض‌های jQuery validator بازنویسی شده و در آن از textareaهای مخفی صرفنظر نمی‌شود.
اگر می‌خواهید کلا از چیزی صرفنظر نشود، مقدار آن‌را به "" تنظیم کنید.

مشکل دوم! متد required پیش فرض، فقط به رشته‌های خالی یا نال واکنش نشان می‌دهد. اما اگر کاربری در اینجا <p><br/></p> را وارد کرد، چطور؟
در این حالت نیاز است متد rqeuired پیش فرض jQuery validator را به نحو ذیل بازنویسی کنیم:
    <script type="text/javascript">
        // حذف تمام تگ‌های یک قطعه متن
        function removeAllTagsAndTrim(html) {
            return !html ? "" : jQuery.trim(html.replace(/(<([^>]+)>)/ig, ""));
        }

        // این تنظیم برای پردازش ادیتور مخفی وب لازم است
        jQuery.validator.setDefaults({ ignore: ":hidden:not(textarea)" });

        // متد اصلی اعتبارسنجی را ابتدا ذخیره می‌کنیم
        jQuery.validator.methods.originalRequired = jQuery.validator.methods.required;
        // نحوه بازنویسی متد توکار اعتبار سنجی جهت استفاده از یک متد سفارشی
        jQuery.validator.addMethod("required", function (value, element, param) {
            value = removeAllTagsAndTrim(value);
            if (!value) {
                return false;
            }
            //  فراخوانی متد اصلی اعتبار سنجی در صورت شکست تابع سفارشی
            return jQuery.validator.methods.originalRequired.call(this, value, element, param);
        }, jQuery.validator.messages.required);
    </script>
متد removeAllTagsAndTrim کلیه تگ‌های یک عبارت HTML ایی را حذف می‌کند. متد trim جی‌کوئری نیز سبب حذف فواصل خالی در ابتدا و انتهای یک رشته می‌شود. اکنون نیاز است این متد سفارشی را جهت تمیزسازی عبارت ورودی به متد توکار required اعمال کنیم.
برای اینکار نیاز است متد اصلی required را در جایی ذخیره کنیم تا در صورت شکست اعتبارسنجی سفارشی، همان متد اصلی فراخوانی گردد. در ادامه با فراخوانی jQuery.validator.addMethod و بکارگیری نام required، دقیقا همان متد اصلی required موجود بازنویسی خواهد شد. در ابتدای کار تگ‌های ورودی پاک شده و سپس اعتبارسنجی می‌شوند.
در ادامه فراخوانی متد اصلی required را ملاحظه می‌کنید. همچنین با استفاده از jQuery.validator.messages.required اصل پیام خطای تنظیم شده به کاربر نمایش داده خواهد شد.
مطالب
نوشتن یک بات تلگرامی با استفاده از webhookها
با رشد روز افزون شبکه‌های اجتماعی و نیاز روزمره مردم به این شبکه‌ها ،اکثر شبکه‌های اجتماعی با در اختیار قرار دادن کتاب خانه‌ها و apiها، توسعه و طراحی یک برنامه‌ی مبتنی بر آن‌ها را فراهم کرده‌اند. تلگرام نیز یکی  از این شبکه‌ها است و با طراحی بات‌ها میتوان یک نرم افزار کوچک و پر کاربرد را جهت آن طراحی کرد.
در این مقاله قصد دارم نحوه ساخت یک بات تلگرامی را با استفاده از webhook که پیشنهاد خود تلگرام میباشد و همچنین کار با سایر apiهای مانند گرفتن عکس پروفایل و ... به اشتراک بگذارم. ما آموزش را بنا بر یک مثال کاربردی، در قالب یک بات تلگرامی قرار می‌دهیم که بعد از start شدن، پیغام خوش آمد گویی را نمایش میدهد و سپس جملات فارسی را از کاربر دریافت و معادل انگلیسی آن‌ها را با استفاده از از google translate به کاربر نشان میدهد.


شروع به ساخت بات

 به طور کلی دو روش برای ساخت یک بات تلگرامی وجود دارد:
1- استفاده از کتابخانه‌های آماده
2 - استفاده webhook

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

مزایا:
 بدون زحمت زیادی و فقط با فراخوانی توابع آماده، قادر خواهیم بود یک بات خیلی ساده را شبیه سازی کنیم.
هزینه آن نسبت به webhook کمتر است و شما میتوانید با یک vps، بات را اجرا کنید.

معایب:
1- این روش ازpolling استفاد میکند. یعنی دستور دریافت شده در یک حلقه‌ی بی نهایت قرا میگیرد و هر بار چک میشود که آیا درخواستی رسیده است یا خیر؟ که سربار بالایی را بر روی سرور ما خواهد داشت.
2- بعد از مدتی down میشود.
3- اگر شمار درخواست‌ها بالا رود، Down میشود.

روش  دیگر استفاده از webhook است که اصولی‌ترین روش و روشی است که خود سایت تلگرام آن را پیشنهاد داده‌است. اگر بخواهم توضیح کوتاهی درباره webhook بدهم، با استفاده از آن میتوانید تعیین کنید وقتی یک event، رخ‌داد، api ایی فرخوانی شود؛ یا مثلا شما یک سایت را با api نوشته‌اید (ASP.NET Web API) و آن را پابلیش کرده‌اید و الان میخواهید یک api جدید را بنویسید. در این حالت با استفاده از webhook، دیگر نیازی نیست تا کل پروژه را پابلیش کنید. یک پروژه api را می‌نویسید و آن را آپلود می‌کنید و درقسمت تنظیم وب هوک، آدرس دامین خودتون را می‌دهید. حتی میتوانید آن را با php  یا هر زبانی که میتوانید بنویسید.

 معایب:
1- هزینه آن. شما علاوه بر تهیه‌ی هاست و دامین، باید ssl را هم فعال کنید که در ادامه بیشتر توضیح خواهیم داد. البته نگرانی برای پیاده سازی ssl نیست. چون سایت‌هایی هستند که این سرویس‌ها را به صورت رایگان در اختیار شما میگذارند (مانند Lets encrypt).
2- تنظیم آن به مراتب سخت‌تر از روش قبل است.

مزایا:
1- سرعت آن بیشتر است.
2- درخواست‌های با تعداد بالا را می‌توان به راحتی پاسخ داد.
3- وابستگی ثالثی ندارد.


اولین مرحله ساخت بات

تا اینجای کار به مباحث تئوری بات‌ها پرداختیم. حال وارد اولین مرحله‌ی ساخت بات‌ها میشویم. قبل از شروع، شما باید در بات BotFather@ عضو شوید و سپس یک بات جدید را بسازید. برای آموزش ساخت بات در BotFather، میتوانید از این مبحث استفاده کنید. بعد از ساخت بات در BotFather، شما داری یک token خواهید شد که یک رشته‌ی کد شده‌است.


ایجاد پروژه‌ی جدید بات

- در ادامه سراغ ویژوال استودیو رفته و یک پروژه‌ی Web api Empty را ایجاد کنید.
- سپس وارد سایت تلگرام شوید و کتابخانه‌ی مربوطه را دریافت کنیدو یا میتوانید با استفاده از دستور زیر، این کتابخانه را نصب کنید:
 Install-Package Telegram.Bot
پس از آن، اولین کار، ایجاد یک controller جدید به نام Webhook میباشد. درون این کنترلر، یکaction متد جدید را به نام UpdateMsg ایجاد می‌کنیم:
[HttpPost]
public async Task<IHttpActionResult> UpdateMsg(Update update)
{
  //......
}
تمام درخواست‌های تلگرام (وقایع رسیده‌ی از آن) ،به این action متد ارسال خواهند شد. اگر دقت کنید این متد دارای یک آرگومان از نوع update میباشد که شامل تمام پراپرتی‌های یک درخواست، اعم از نام کاربری، نوع درخواست، پیام و ... است.


تنظیم کردن WebHook

- حال به قسمت تنظیم کردن webhook می‌رسیم. وارد فایل Global.asax.cs برنامه شوید و با دستور زیر، وب هوک را تنظیم کنید:
var bot = new Telegram.Bot.TelegramBotClient("Token");
bot.SetWebhookAsync("https://Domian/api/webhook").Wait();
- در قسمت token ،token خود را که از BotFather دریافت کردید، وارد کنید و در قسمت setwebhook، باید ادرس دامنه‌ی خود را وارد نمائید. البته برای آزمایش برنامه، ما دامنه‌ای نداریم و  قصد خرید هاستی را هم نداریم. بنابراین با استفاده از ابزار ngrok می‌توان به سادگی یک دامنه‌ی آزمایشی SSL را تهیه کرد و از آن استفاده نمود.
- در این حالت بعد از اجرای ngrok، آدرس https آن را کپی کرده و در قسمت بالا، بجای Domain ذکر شده قرار دهید.
- برای آزمایش انجام کار، یک break-point را در قسمت action متد یاد شده قرار دهید و سپس برنامه را اجرا کنید.
- اکنون از طریق تلگرام وارد بات شوید و یک درخواست را ارسال کنید.
- اگر کار را به درستی انجام داده باشید، در صفحه ngrok  پیغام 200 مبتنی بر ارسال صحیح درخواست را دریافت خواهید کرد و همچنین در قسمت breakpoints برنامه بر روی آرگومان update، میتوانید پراپرتی‌های یک درخواست را به صورت کامل دریافت کنید.
- ارسال اولین درخواست ما از طریق بات start/ میباشد. در این حالت میتوان دریافت که کاربر برای بار اول است که از بات استفاده میکند.
- در اکشن متد از طریق خاصیت update.Message.Text میتوان به متن فرستاده شده دسترسی داشت.
- همچین اطلاعات کاربر در update.Message.From، همراه با درخواست، فرستاده می‌شود.


کار با ابزار ترجمه‌ی گوگل و تکمیل پروژه‌ی Web API

اکنون طبق مثال بالا می‌خواهیم وقتی کاربر برای اولین بار وارد شد، پیغام خوش آمد گویی به او نمایش داده شود. بعد از آن هر متنی را که فرستاد، معنای آن را از گوگل ترنسلیت گرفته و مجددا به کاربر ارسال میکنیم. برای اینکار کلاس WebhookController را به شکل زیر تکمیل خواهیم کرد: 
namespace Telegrambot.Controllers
{
    public class WebhookController : ApiController
    {
        Telegram.Bot.TelegramBotClient _bot = new Telegram.Bot.TelegramBotClient("number");
        Translator _translator = new Translator();

        [HttpPost]
        public async Task<IHttpActionResult> UpdateMsg(Update update)
        {
            if (update.Message.Text == "/start")
            {
                await _bot.SendTextMessageAsync(update.Message.From.Id, "Welcome To My Bot");
            }
            else
            {
                var translatedRequest = _translator.Translate(update.Message.Text, "Persian", "English");
                await _bot.SendTextMessageAsync(update.Message.From.Id, translatedRequest);
            }
            return Ok(update);
        }
    }
}
توضیحات:
- با استفاده از update.Message.From.Id میتوان پیغام را به شخصی که درخواست داده‌است فرستاد.
- دقت کنید هنگام ارسال درخواست، در ngrok آیا درخواستی فرستاده می‌شود یا خطایی وجود دارد.

نکته! برای استفاده از بات باید حتما از ssl استفاده کنید. اگر نیاز به خرید این سرویس را ندارید، از این لینک نیز می‌توانید سرویس مورد نظر را بعد از 24 ساعت بر روی دامین خود تنظیم کنید.


توضیحات بیشتر در این مورد را مثلا دکمه‌های پویا و گرفتن عکس پروفایل و ....، در مقاله‌ی بعدی قرار خواهم داد.

شما میتوانید از این لینک پروژه بالا را دریافت و اجرا کنید .
مطالب
RavenDB؛ تجربه متفاوت از پایگاه داده
" به شما خواننده گرامی پیشنهاد می‌کنم مطلب قبلی را مطالعه کنید تا پیش زمینه مناسبی در باره این مطلب کسب کنید. "

ماهیت این پایگاه داده وب سرویسی مبتنی بر REST است و فرمت اطلاعاتی که از سرور دریافت می‌شود، JSON است.

گام اول: باید آخرین نسخه RavenDB  را دریافت کنید. همان طور که مشاهده می‌کنید، ویرایش‌های مختلف کتابخانه هایی که برای نسخه Client و همچنین Server طراحی شده است، دراین فایل قرار گرفته است.

برای راه اندازی Server باید فایل Start را اجرا کنید، چند ثانیه بعد محیط مدیریتی آن را در مرورگر خود مشاهده می‌کنید. در بالای صفحه روی لینک Databases کلیک کنید و در صفحه باز شده گزینه New Database را انتخاب کنید. با دادن یک نام دلخواه حالا شما یک پایگاه داده ایجاد کرده اید. تا همین جا دست نگه دارید و اجازه دهید با این محیط دوست داشتنی و قابلیت‌های آن بعدا آشنا شویم.
در گام دوم به Visual Studio می‌رویم و نحوه ارتباط با پایگاه داده و استفاده از دستورات آن را فرا می‌گیریم.
 

گام دوم:

با یک پروژه Test شروع می‌کنیم که در هر گام تکمیل می‌شود و می‌توانید پروژه کامل را در پایان این پست دانلود کنید.

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

  • استفاده از NuGet : با استفاده از دستور زیر Package مورد نیاز به پروژه شما افزوده می‌شود.

PM> Install-Package RavenDB -Version 1.0.919 

  • اضافه کردن کتابخانه‌ها به صورت دستی : کتابخانه‌های مورد نیاز شما در همان فایلی که دانلود شده بود و در پوشه Client قرار دارند.

کتابخانه هایی را که NuGet به پروژه من اضافه کرد، در تصویر زیر مشاهده می‌کنید :

با Newtonsoft.Json در اولین بخش بحث آشنا شدید. NLog هم یک کتابخانه قوی و مستقل برای مدیریت Log است که این پایگاه داده از آن بهره برده است.

" دلیل اینکه از پروژه تست استفاده کردم ؛ تمرکز روی کدها و مشاهده تاثیر آن‌ها ، مستقل از UI و لایه‌های دیگر نرم افزار است. بدیهی است که استفاده از آن‌ها در هر پروژه امکان پذیر است. "

برای شروع نیاز به آدرس Server و نام پایگاه داده داریم که می‌توانید در App.config به عنوان تنظیمات نرم افزار شما ذخیره شود و هنگام اجرای نرم افزار مقدار آن‌ها را خوانده و در متغییر‌های readonly ذخیره شوند.

<appSettings>
    <add key="ServerName" value="http://SorousH-HP:8080/"/>
    <add key="DatabaseName" value="TestDatabase" />
</appSettings>

هنگامی که صفحه Management Studio در مرورگر باز است، می‌توانید از نوار آدرس مرورگر خود آدرس سرور را به دست آورید.  

    [TestClass]
    public class BeginnerTest
    {
        private readonly string serverName;
        private readonly string databaseName;

        public BeginnerTest()
        {
            serverName = ConfigurationManager.AppSettings["ServerName"];
            databaseName = ConfigurationManager.AppSettings["DatabaseName"];
        }
    }

برای برقراری ارتباط با پایگاه داده نیاز به یک شئ از جنس DocumentStore و جهت انجام عملیات مختلف ( ذخیره، حذف و ... ) نیاز به یک شئ از جنس IDocumentSession است. کد زیر، نحوه کار با آن‌ها را به شما نشان می‌دهد :

[TestClass]
    public class BeginnerTest
    {
        private readonly string serverName;
        private readonly string databaseName;

        private DocumentStore documentStore;
        private IDocumentSession session;

        public BeginnerTest()
        {
            serverName = ConfigurationManager.AppSettings["ServerName"];
            databaseName = ConfigurationManager.AppSettings["DatabaseName"];
        }

        [TestInitialize]
        public void TestStart()
        {
            documentStore = new DocumentStore { Url = serverName };
            documentStore.Initialize();
            session = documentStore.OpenSession(databaseName);

        }
        
        [TestCleanup]
        public void TestEnd()
        {
             session.SaveChanges(); 
             documentStore.Dispose();
             session.Dispose();
        }
    }

در طراحی این پایگاه داده از اگوی Unit Of Work استفاده شده است. به این معنی که تمام تغییرات در حافظه ذخیره می‌شوند و به محض اجرای دستور ;()session.SaveChanges ارتباط برقرار شده و تمام تغییرات ذخیره خواهند شد.

هنگام شروع ( تابع : TestStart ) متغییر session مقدار دهی می‌شود و در پایان کار ( تابع : TestEnd ) تغییرات ذخیره شده و منابعی که توسط این دو شئ در حافظه استفاده شده است، رها می‌شود.

البته بر مبنای طراحی شما، دستور ;()session.SaveChanges می‌تواند پس از انجام هر عملیات اجرا شود.

برای آشنا شدن با نحوه ذخیره کردن اطلاعات، به کد زیر دقت کنید:
class User
    {
        public int Id { get; set; }
        public string Name { get; set; }
        public string Address { get; set; }
        public int Zip { get; set; }اهی 
    }
        [TestMethod]
        public void Insert()
        {
            var user = new User
                           {
                               Id = 1,
                               Name = "John Doe",
                               Address = "no-address",
                               Zip = 65826
                           };
            session.Store(user);
        }
اگر همه چیز درست پیش رفته باشد، وقتی به محیط RavenDB Studio که هنوز در مرورگر شما باز است، نگاهی می‌اندازید، یک سند جدید ایجاد شده است که با کلیک روی آن، اطلاعات آن قابل مشاهده است.
لحظه‌ی لذت بخشی است...
یکی  از روش‌های خواندن اطلاعات هم به صورت زیر است:
        [TestMethod]
        public void Select()
        {
            var user = session.Load<User>(1);
        }
نتیجه خروجی این دستور هم یک شئ از جنس کلاس User است.

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

" به شما پیشنهاد می‌کنم که منتظر بحث بعدی نباشید! همین حالا دست به کار شوید... "


مطالب
یکی از مزایای استفاده از SVN در یک پروژه تک نفره

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

چند روز قبل هنگام کار با VS.Net ، ناگهان IDE‌ کرش کرد. (از لطایف استفاده از یک دو جین افزونه و ضعف در برنامه نویسی یکی از این‌ها که می‌تواند سبب ناپایدار شدن IDE شود)
پس از کرش با صفحه‌ی زیر مواجه شدم!


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

چون همیشه از SVN به عنوان سورس کنترل استفاده می‌کنم، به سادگی چند کلیک مشکل برطرف شد.
برای این‌کار می‌توان به صورت زیر عمل کرد:
الف) کلیک راست بر روی فایل frmMain.Designer.cs (این فایل تعاریف رابط کاربر فرم تخریب شده را در خود دارد)
ب) سپس انتخاب گزینه‌ی Showlog از منوی افزونه‌ی Visual SVN (شکل زیر)



اکنون صفحه‌ی گزارش تاریخچه‌ی ریز عملیات صورت گرفته بر روی این فایل ظاهر می‌شود:



در ادامه می‌توان بر روی یکی از سطرهای ظاهر شده در گزارش کلیک راست کرد و گزینه‌ی compare with working copy را انتخاب نمود (شکل زیر):



سپس ابزار diff ظاهر شده و می‌توان به سادگی تفاوت فایل تخریب شده فعلی و فایل سالم چند نگارش قبل را مشاهده نمود:



همانطور که در تصویر مشخص است، فایل مورد استفاده (working copy) در دو نقطه اساسی که مربوط به اضافه کردن منوها است تخریب شده. سمت چپ نگارش قدیمی است و سمت راست نگارش فعلی تخریب شده.
اکنون برای اصلاح کد تخریب شده فقط کافی است روی قسمت رنگی سمت راست کلیک راست کرده و گزینه copy to right‌ را انتخاب کنیم. به این صورت در اسرع وقت و به سادگی هر چه تمام‌تر یک فایل تخریب شده به روز اول یا حداقل به یک نگارش قبل بازگشت پیدا کرده و مشکل حل می‌شود. (البته در این مورد تخریب فرم، پس از انجام اصلاح فوق، یکبار باید IDE را کاملا بست و مجددا آنرا گشود تا نتیجه ظاهر شود)



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


اشتراک‌ها
مرجع سریع کد کلیدهای صفحه کلید

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

مرجع سریع کد کلیدهای صفحه کلید
مطالب
مشکل در جابجایی پروژه های svn
بنا به دلایلی، کدهای نگهداری شده توسط svn در سیستم خودم رو باید به سیستم دیگری وارد می‌کردم که شامل چند پروژه می‌شد و در قسمت مربوطه چند پروژه کار شده بود. تا این که مشکلی پیش آمد و جهت ادامه توسعه مجبور به برگرداندن پروژه‌ها به سیستم قبلی شدیم. حالا مشکل این بود که به repository قبلی هیچ گونه دسترسی نداشتیم و نمیخواستیم که کدهای در دست هم بصورت یک پروژه تازه وارد سرور svn شود. برای همین مجبور بودیم که از طریق relocate کردن، این کار را انجام دهیم، که به خطای زیر برخورد کردم:

بله؛ مشکل از اینجا ناشی می‌شد که سرور دوم کدها را import نکرده بود و بلکه با یک کامیت ساده، کدها وارد سرور شده بودند.
راه حل: در کل برای تغییر این uid که در تصویر مشخص شده، باید فایل SQLite مربوطه را یافت و به راحتی، دو مشخصه مربوط به آدرس مخزن و uid را در آن اصلاح کرد.
در پوشه svn کنار پروژه، فایلی با نام wc.db از نوع SQLite وجود دارد:

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


  همانطور که مشخص است، در جدول repository، تک ردیفی وجود دارد که مشخصات مربوط به مخزن svn در آن ذخیره شده است:


نکته: در این نوع آدرس دهی، باید حتما به نوع قرار گیری پروژه‌ها در کنار هم نیز دقت داشت. مثلا به محل آخری که در آدرس وجود دارد باید دقت کرد تا در مسیردهی، اشتباهی صورت نگیرد و فایلها جابجا کامیت نشوند.
مطالب
شروع به کار با AngularJS 2.0 و TypeScript - قسمت نهم - مسیریابی
یک برنامه، از صفحات و Viewهای مختلفی تشکیل می‌شود و Routing یا مسیریابی، امکان ناوبری بین این Viewها را میسر می‌کند. یک برنامه‌ی AngularJS 2.0، یک برنامه‌ی تک صفحه‌ای وب است. به این معنا که تمام Viewهای برنامه، در یک صفحه نمایش داده می‌شوند؛ که معمولا همان index.html سایت است. هدف از سیستم مسیریابی، مدیریت نحوه‌ی نمایش و قرارگیری این Viewها، درون تک صفحه‌ی برنامه است.


برپایی تنظیمات اولیه‌ی سیستم مسیریابی در AngularJS 2.0

برای کار با سیستم مسیریابی AngularJS 2.0، ابتدا باید اسکریپت‌های آن به صفحه اضافه شوند. در ادامه المان پایه‌ای تعریف شده و سپس باید سرویس پروایدر مسیریابی را رجیستر کرد. جزئیات این موارد را در ادامه بررسی می‌کنیم:

الف) سرویس مسیریابی، جزئی از angular2/core نیست. به همین جهت مدخل اسکریپت متناظر با آن باید به صفحه‌ی اصلی سایت اضافه شود که این مورد، در قسمت اول بررسی پیشنیازهای نصب AngularJS 2.0 صورت گرفته‌است:
 <!-- Required for routing -->
<script src="~/node_modules/angular2/bundles/router.dev.js"></script>
این تعریف در فایل Views\Shared\_Layout.cshtml (و یا index.html) پروژه‌ی جاری موجود است.

ب) افزودن المان base به ابتدای صفحه:
 <!DOCTYPE html>
<html>
<head>
    <base href="/">
بلافاصله پس از تگ head، المان base اضافه می‌شود. این المان به سیستم مسیریابی اعلام می‌کند که چگونه آدرس‌های خود را تشکیل دهد. به صورت پیش فرض، AngularJS 2.0 از آدرس‌هایی با فرمت HTML5 استفاده می‌کند. در این حالت دیگر نیازی به ذکر # برای مشخص سازی مسیریابی‌های محلی نیست.
از آنجائیکه فایل index.html در ریشه‌ی سایت قرار گرفته‌است، مقدار آغازین href آن به / تنظیم شده‌است.

ج) شبیه به حالت ثبت پروایدر HTTP در قسمت قبل، برای ثبت پروایدر مسیریابی نیز به فایل App\app.component.ts مراجعه می‌کنیم:
//same as before ...
import { ROUTER_PROVIDERS } from 'angular2/router';
 
//same as before ... 

@Component({
//same as before …
    providers: [
        ProductService,
        HTTP_PROVIDERS,
        ROUTER_PROVIDERS
    ]
})
//same as before ...
در اینجا سرویس ROUTER_PROVIDERS به خاصیت providers اضافه شده‌است و همچنین import متناظر با آن نیز به ابتدای صفحه اضافه گردیده‌است.
علت ختم شدن نام این سرویس‌ها به PROVIDERS این است که این تعاریف، امکان استفاده‌ی از چندین سرویس زیر مجموعه‌ی آن‌ها را فراهم می‌کنند و صرفا یک سرویس نیستند.


ساخت کامپوننت نمایش جزئیات محصولات

در ادامه می‌خواهیم جزئیات هر محصول را با کلیک بر روی نام آن در لیست محصولات، در آدرسی دیگر به صورتی مجزا مشاهده کنیم. به همین منظور به پوشه‌ی products برنامه مراجعه کرده و دو فایل جدید product-detail.component.ts و product-detail.component.html را ایجاد کنید؛ با این محتوا:
الف) محتوای فایل product-detail.component.html
<div class='panel panel-primary'>
    <div class='panel-heading'>
        {{pageTitle}}
    </div>
</div>
ب) محتوای فایل product-detail.component.ts
import { Component } from 'angular2/core';

@Component({
    templateUrl: 'app/products/product-detail.component.html'
})
export class ProductDetailComponent  {
    pageTitle: string = 'Product Detail'; 
}
در اینجا یک کامپوننت جدید را ایجاد کرده‌ایم که در قالب آن، مقدار خاصیت pageTitle با روش interpolation در آن درج شده‌است. کلاس ProductDetailComponent، قالب خود را از طریق مقدار دهی آدرس آن در خاصیت templateUrl متادیتای خود، پیدا می‌کند.
اگر دقت کنید، این کامپوننت ویژه دارای خاصیت selector نیست. ذکر selector تنها زمانی اجباری است که بخواهیم این کامپوننت را داخل کامپوننتی دیگر قرار دهیم. در اینجا قصد داریم این کامپوننت را به صورت یک View جدید، توسط سیستم مسیریابی نمایش دهیم و نه به صورت جزئی از یک کامپوننت دیگر.


افزودن تنظیمات مسیریابی به برنامه

مسیریابی در AngularJS 2.0، مبتنی بر کامپوننت‌ها است. به همین جهت، ابتدای کار مسیریابی، مشخص سازی تعدادی از کامپوننت‌ها هستند که قرار است به عنوان مقصد سیستم راهبری (navigation) مورد استفاده قرار گیرند و به ازای هر کدام، یک مسیریابی و Route جدید را تعریف می‌کنیم. تعریف هر Route جدید شامل انتساب نامی به آن، تعیین مسیر مدنظر و مشخص سازی کامپوننت مرتبط است:
 { path: '/products', name: 'Products', component: ProductListComponent },
برای مثال جهت تعریف Route کامپوننت لیست محصولات، نام آن‌را Products، مسیر آن‌را products/ و در آخر کامپوننت آن‌را به نام کلاس متناظر با آن، تنظیم می‌کنیم.
این تنظیمات به عنوان یک متادیتای جدید دیگر به کلاس AppComponent، در فایل app.component.ts اضافه می‌شوند:
//same as before …
import { ROUTER_PROVIDERS, RouteConfig } from 'angular2/router';
 
//same as before …
 
@Component({
    //same as before …
})
@RouteConfig([
    { path: '/welcome', name: 'Welcome', component: WelcomeComponent, useAsDefault: true },
    { path: '/products', name: 'Products', component: ProductListComponent }
])
export class AppComponent {
    pageTitle: string = "DNT AngularJS 2.0 APP";
}
در اینجا decorator جدیدی به نام RouteConfig به کلاس AppComponent اضافه شده‌است و همچنین importهای متناظری نیز در ابتدای این فایل تعریف شده‌اند.
همانطور که ملاحظه می‌کنید، یک کلاس می‌تواند بیش از یک decorator داشته باشد.
()RouteConfig@ را به کامپوننتی الصاق می‌کنیم که قصد میزبانی مسیریابی را دارد (Host component). این مزین کننده، آرایه‌ای از اشیاء را قبول می‌کند و هر شیء آن دارای خواصی مانند مسیر، نام و کامپوننت است. باید دقت داشت که نام هر مسیریابی تعریف شده باید pascal case باشد. در غیراینصورت مسیریاب ممکن است این نام را با path اشتباه کند.  
همچنین امکان تعریف خاصیت دیگری به نام useAsDefault نیز در اینجا میسر است. از آن جهت تعریف مسیریابی پیش فرض سیستم، در اولین بار نمایش آن، استفاده می‌شود.

در اینجا نام کامپوننت، رشته‌ای ذکر نمی‌شود و دقیقا اشاره دارد به نام کلاس متناظر. بنابراین هر نام کلاسی که در اینجا اضافه می‌شود، باید به همراه import ماژول آن نیز در ابتدای فایل جاری باشد. به همین جهت اگر تنظیمات فوق را اضافه کنید، ذیل کلمه‌ی WelcomeComponent یک خط قرمز مبتنی بر عدم تعریف آن کشیده می‌شود. برای تعریف آن، پوشه‌ی جدیدی را به ریشه‌ی سایت به نام home اضافه کنید و به آن دو فایل ذیل را اضافه نمائید:
الف) محتوای فایل welcome.component.ts
import { Component } from 'angular2/core';
 
@Component({
    templateUrl: 'app/home/welcome.component.html'
})
export class WelcomeComponent {
    public pageTitle: string = "Welcome";
}
ب) محتوای فایل welcome.component.html
<div class="panel panel-primary">
    <div class="panel-heading">
        {{pageTitle}}
    </div>
    <div class="panel-body">
        <h3 class="text-center">Default page</h3>
    </div>
</div>
کار این کامپوننت، نمایش صفحه‌ی آغازین برنامه است؛ بر اساس تنظیم useAsDefault: true مسیریابی‌های تعریف شده‌.
پس از تعریف این کامپوننت، اکنون باید import ماژول آن‌را به ابتدای فایل app.component.ts اضافه کنیم، تا مشکل عدم شناسایی نام کلاس WelcomeComponent برطرف شود:
 import { WelcomeComponent } from './home/welcome.component';


فعال سازی مسیریابی‌های تعریف شده

روش‌های مختلفی برای دسترسی به اجزای یک برنامه وجود دارند؛ برای مثال کلیک بر روی یک لینک، دکمه و یا تصویر و سپس فعال سازی مسیریابی متناظر با آن. همچنین کاربر می‌تواند آدرس صفحه‌ای را مستقیما در نوار آدرس‌های مرورگر وارد کند. به علاوه امکان کلیک بر روی دکمه‌های back و forward مرورگر نیز همواره وجود دارند. تنظیمات مسیریابی‌های انجام شده، دو مورد آخر را به صورت خودکار مدیریت می‌کنند. در اینجا تنها باید مدیریت اولین حالت ذکر شده را با اتصال مسیریابی‌ها به اعمال کاربران، انجام داد.
به همین جهت منویی را به بالای صفحه‌ی برنامه اضافه می‌کنیم. برای این منظور، فایل app.component.ts را گشوده و خاصیت template کامپوننت AppComponent را به نحو ذیل تغییر می‌دهیم:
@Component({
    //same as before …
    template: `
     <div>
        <nav class='navbar navbar-default'>
            <div class='container-fluid'>
                <a class='navbar-brand'>{{pageTitle}}</a>
                <ul class='nav navbar-nav'>
                    <li><a [routerLink]="['Welcome']">Home</a></li>
                    <li><a [routerLink]="['Products']">Product List</a></li>
                </ul>
            </div>
        </nav>
        <div class='container'>
            <router-outlet></router-outlet>
        </div>
     </div>
    `,
    //same as before …
})
در اینجا یک navigation bar بوت استرپ 3، جهت تعریف منوی بالای صفحه اضافه شده‌است.
سپس جهت تعریف لینک‌های هر آیتم، از یک دایرکتیو توکار AngularJS 2.0 به نام routerLink استفاده می‌کنیم. هر routerLink به یکی از آیتم‌های تنظیم شده‌ی در RouteConfig بایند می‌شود. بنابراین نام‌هایی که در اینجا قید شده‌اند، دقیقا نام‌هایی هستند که در خاصیت name هر کدام از اشیاء تشکیل دهنده‌ی RouteConfig، تعریف و مقدار دهی گردید‌ه‌اند.
اکنون اگر کاربر بر روی یکی از لینک‌های Home و یا Product List کلیک کند، مسیریابی متناظر با آن فعال می‌شود (بر اساس این نام، در لیست عناصر RouteConfig جستجویی صورت گرفته و عنصر معادلی بازگشت داده می‌شود) و سپس View آن کامپوننت نمایش داده خواهد شد.
تا اینجا دایرکتیو جدید routerLink به قالب کامپوننت اضافه شد‌ه‌است؛ اما AngularJS 2.0 نمی‌داند که باید آن‌را از کجا دریافت کند. به همین جهت ابتدا import آن‌را (ROUTER_DIRECTIVES) به ابتدای ماژول جاری اضافه خواهیم کرد:
 import { ROUTER_PROVIDERS, RouteConfig, ROUTER_DIRECTIVES } from 'angular2/router';
و سپس خاصیت دایرکتیوهای کامپوننت ریشه‌ی سایت را نیز با آن مقدار دهی خواهیم کرد:
 directives: [ROUTER_DIRECTIVES],
علت جمع بود نام این دایرکتیو این است که routerLink استفاده شده، یکی از اعضای مجموعه‌ی دایرکتیوهای مسیریابی توکار AngularJS 2.0 است.

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

در انتهای قالب کامپوننت ریشه‌ی سایت، یک دایرکتیو جدید به نام router-outlet نیز تعریف شده‌است. وقتی یک کامپوننت فعال می‌شود، نیاز است View مرتبط با آن نیز نمایش داده شود. دایرکتیو router-outlet محل نمایش این View را مشخص می‌کند.

اکنون اگر برنامه را اجرا کنیم، به این شکل خواهیم رسید:


اگر دقت کنید، آدرس بالای صفحه، در اولین بار نمایش آن به http://localhost:2222/welcome تنظیم شده و این مقدار دهی بر اساس خاصیت useAsDefault تنظیمات مسیریابی سایت انجام شده‌است (نمایش welcome به عنوان صفحه‌ی اصلی و پیش فرض).
همچنین با کلیک بر روی لینک لیست محصولات، کامپوننت آن فعال شده و نمایش داده می‌شود. محل قرارگیری این کامپوننت‌ها، دقیقا در محل قرارگیری دایرکتیو router-outlet است.


ارسال پارامترها به سیستم مسیریابی

در ابتدا بحث، مقدمات کامپوننت نمایش جزئیات یک محصول انتخابی را تهیه کردیم. برای فعال سازی این کامپوننت و مسیریابی آن، نیاز است بتوان پارامتری را به سیستم مسیریابی ارسال کرد. برای مثال با انتخاب آدرس product/5، جزئیات محصول با ID مساوی 5 نمایش داده شود.
برای این منظور:
الف) اولین قدم، تعریف مسیریابی آن است. به همین جهت به فایل app.component.ts مراجعه و دو تغییر ذیل را به آن اعمال کنید:
//same as before …

import { ProductDetailComponent } from './products/product-detail.component';
 
@Component({
    //same as before …
})
@RouteConfig([
    //same as before …
    { path: '/product/:id', name: 'ProductDetail', component: ProductDetailComponent }
])
//same as before …
ابتدا مسیریابی جدیدی به نام ProductDetail اضافه شده‌است و سپس ماژول دربرگیرنده‌ی کلاس کامپوننت آن نیز import شده‌است.
تفاوت این مسیریابی با نمونه‌های قبلی در تعریف id:/ است. پس از ذکر :/، نام یک متغیر عنوان می‌شود و اگر نیاز به چندین متغیر بود، همین الگو را تکرار خواهیم کرد.

ب) سپس نحوه‌ی فعال سازی این مسیریابی را توسط تعریف لینکی جدید، معرفی می‌کنیم. بنابراین فایل قالب product-list.component.html را گشوده و سپس بجای نمایش عنوان محصول:
 <td>{{ product.productName }}</td>
لینک به جزئیات آن‌را نمایش می‌دهیم:
<td>
    <a [routerLink]="['ProductDetail', {id: product.productId}]">
        {{product.productName}}
    </a>
</td>
نحوه‌ی تعریف این لینک، با لینک‌هایی که در منوی بالای سایت اضافه کردیم، یکی است؛ با این تفاوت که اکنون پارامتر دومی را به قسمت یافتن نام این Route، جهت مشخص سازی روش مقدار دهی متغیر id، تعریف کرده‌ایم. در اینجا id هر لینک از productId بایند شده تامین می‌شود.
اکنون که از دایرکتیو جدید routerLink در این قالب استفاده شده‌است، نیاز است تعریف دایرکتیو آن‌را به متادیتای کلاس کامپوننت لیست محصولات نیز اضافه کنیم تا AngularJS 2.0 بداند آن‌را از کجا باید تامین کند:
import { Component, OnInit } from 'angular2/core';
import { ROUTER_DIRECTIVES } from 'angular2/router';
//same as before …
 
@Component({
    //same as before …
    directives: [StarComponent, ROUTER_DIRECTIVES]
})

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


ج) در آخر زمانیکه View نمایش جزئیات محصول فعال می‌شود، نیاز است این id را از url جاری دریافت کند. به همین جهت فایل product-detail.component.ts را گشوده و تغییرات ذیل را به آن اعمال کنید:
import { Component } from 'angular2/core';
import { RouteParams } from 'angular2/router';
 
@Component({
    templateUrl: 'app/products/product-detail.component.html'
})
export class ProductDetailComponent {
    pageTitle: string = 'Product Detail';
 
    constructor(private _routeParams: RouteParams) {
        let id = +this._routeParams.get('id');
        this.pageTitle += `: ${id}`;
    } 
}
با نحوه‌ی تزریق وابستگی‌ها در قسمت هفتم آشنا شدیم. در اینجا سرویس توکار RouteParams به سازنده‌ی کلاس تزریق شده‌‌است. با استفاده از آن می‌توان به id ارسالی از طریق url دسترسی یافت. در اینجا پارامتری که به متد get ارسال می‌شود، باید با نام پارامتری که در تنظیمات آغازین مسیریابی سیستم تعریف گردید، تطابق داشته باشد.
در این حالت، id دریافتی، به متغیر pageTitle اضافه شده و در قالب مربوطه به صورت خودکار نمایش داده می‌شود.

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



افزودن دکمه‌ی back با کدنویسی

اکنون برای بازگشت مجدد به لیست محصولات، می‌توان از دکمه‌ی back مرورگر استفاده کرد، اما امکان طراحی این دکمه در قالب‌ها نیز پیش بینی شده‌است.
برای این منظور قالب product-detail.component.html را به نحو ذیل بازنویسی می‌کنیم:
<div class='panel panel-primary'>
    <div class='panel-heading'>
        {{pageTitle}}
    </div>
    <div class='panel-footer'>
        <a class='btn btn-default' (click)='onBack()' style='width:80px'>
            <i class='glyphicon glyphicon-chevron-left'></i> Back
        </a>
    </div>    
</div>
در اینجا دکمه‌ی بازگشت به صفحه‌ی قبلی اضافه شده‌است که به متد onBack در کلاس مرتبط با این قالب، متصل است.

سپس کدهای product-detail.component.ts را به صورت ذیل تکمیل خواهیم کرد:
import { Component } from 'angular2/core';
import { RouteParams, Router } from 'angular2/router';
 
@Component({
    templateUrl: 'app/products/product-detail.component.html'
})
export class ProductDetailComponent {
    pageTitle: string = 'Product Detail';
 
    constructor(private _routeParams: RouteParams, private _router: Router) {
        let id = +this._routeParams.get('id');
        this.pageTitle += `: ${id}`;
    }
 
    onBack(): void {
        this._router.navigate(['Products']);
    }
}
در اینجا سرویس جدیدی به نام Router در سازنده‌ی کلاس تزریق شده‌است. این سرویس امکان فراخوانی متدهایی مانند navigate را جهت حرکت به مسیریابی مشخصی، میسر می‌کند. پارامتری که به این متد ارسال می‌شود، دقیقا معادل همان پارامتری است که به دایرکتیو routerLink ارسال می‌گردد و در اینجا صرفا نام یک مسیریابی مشخص شده‌است؛ بدون ذکر پارامتری.


رفع تداخل مسیریابی‌های ASP.NET MVC با مسیریابی‌های AngularJS 2.0

در طی بحث جاری عنوان شد که اگر کاربر مسیر http://localhost:2222/product/2 را جایی ثبت کرده یا bookmark کند، پس از فراخوانی مستقیم آن در نوار آدرس‌های مرورگر، بلافاصله به این آدرس هدایت خواهد شد. این مورد صحیح است اگر از index.html بجای بکارگیری ASP.NET MVC، جهت هاست برنامه استفاده شود. اگر چنین آدرسی را در یک برنامه‌ی ASP.NET MVC فراخوانی کنیم، ابتدا به دنبال کنترلری به نام product می‌گردد (ابتدا وارد موتور ASP.NET MVC می‌شود) و چون این کنترلر در سمت سرور تعریف نشده‌است، پیام 404 و یا یافت نشد را مشاهده خواهید کرد و فرصت به اجرای برنامه‌ی AngularJS نخواهد رسید.
برای حل این مشکل نیاز است یک route جدید را به نام catch all، در انتهای مسیریابی‌های فعلی اضافه کنید؛ تا سایر درخواست‌های رسیده را به صفحه‌ی نمایش برنامه‌ی AngularJS هدایت کند:
public class RouteConfig
{
    public static void RegisterRoutes(RouteCollection routes)
    {
        routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
 
        routes.MapRoute(
            name: "Default",
            url: "{controller}/{action}/{id}",
            defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional },
            constraints: new { controller = "Home" } // for catch all to work, Home|About|SomeName
        );
 
        // Route override to work with Angularjs and HTML5 routing
        routes.MapRoute(
            name: "NotFound",
            url: "{*catchall}",
            defaults: new { controller = "Home", action = "Index", id = UrlParameter.Optional }
        );
    }
}


کدهای کامل این قسمت را از اینجا می‌توانید دریافت کنید: MVC5Angular2.part9.zip


خلاصه‌ی بحث

حین ایجاد کامپوننت‌ها باید به نحوه‌ی نمایش آن‌ها نیز فکر کرد. اگر کامپوننتی قرار است داخل یک کامپوننت دیگر نمایش یابد، باید دارای selector باشد. یک چنین کامپوننتی نیاز به تعریف مسیریابی ندارد. برای کامپوننت‌هایی که به عنوان یک View مستقل طراحی می‌شوند و قرار است در یک صفحه‌ی مجزا نمایش داده شوند، نیازی به تعریف selector نیست؛ اما باید برای آن‌ها مسیریابی‌های ویژه‌ای را تعریف کرد. همچنین نیاز است مدیریت اعمال کاربران را جهت فعال سازی آن‌ها نیز مدنظر داشت. برای استفاده از امکانات مسیریابی توکار AngularJS 2.0 نیاز است اسکریپت آن‌را به صفحه‌ی اصلی اضافه کرد. سپس باید المان base را جهت نحوه‌ی تشکیل آدرس‌های مسیریابی، به صفحه اضافه کرد. در ادامه کار ثبت ROUTER_PROVIDERS در بالاترین سطح سلسه مراتب کامپوننت‌های سایت انجام می‌شود. با استفاده از RouteConfig کار تنظیمات ابتدایی مسیریابی صورت خواهد گرفت. این decorator به کامپوننتی که قرار است کار میزبانی مسیریابی را انجام دهد، متصل می‌شود. پس از تعریف مسیریابی‌ها با ذکر یک نام منحصربفرد، مسیری که باید توسط کاربر وارد شود و نام کامپوننت مدنظر، با استفاده از دایرکتیو routerLink کار تعریف این آدرس‌ها، در رابط کاربری برنامه انجام می‌شود. این دایرکتیو جدید، جزئی از مجموعه‌ی ROUTER_DIRECTIVES است که باید به لیست دایرکتیوهای کامپوننت ریشه‌های سایت و هر کامپوننتی که از routeLink استفاده می‌کند، اضافه شود. برای بایند این دایرکتیو به مسیریابی‌های تعریف شده، سمت راست این اتصال باید به آرایه‌ای از مقادیر مقدار دهی شود که اولین عنصر آن، نام یکی از عناصر مسیریابی تعریف شده‌ی در RouteConfig است. از دومین عنصر آن برای مقدار دهی پارامترهای ارسالی به سیستم مسیریابی استفاده می‌شود. کار دایرکتیو router-outlet، مشخص سازی محل نمایش یک View است که عموما در قالب میزبان مسیریابی قرار می‌گیرد. برای تعیین پارامترهای مسیریابی، از الگوی paramName:/ استفاده می‌شود. برای دسترسی به این مقادیر در یک کامپوننت، می‌توان از سرویس RouteParams استفاده کرد. برای فعال سازی یک مسیریابی با کدنویسی، از سرویس Router و متد navigate آن کمک می‌گیریم.
مطالب
مروری بر پلاگین‌های چندسکویی مرورگرها
NPAPI
این عبارت مخفف Netscape Plugin Application Programming Interface هست و یک پلاگین چندسکویی است که بسیاری از مرورگرها از آن استفاده می‌کنند. معماری این پلاگین ابتدا در سال 1995 برای مرورگر netscape نسخه 2 آن توسعه پیدا کرد. ولی رفته رفته توسط دیگر مرورگرها هم استفاده و پیاده سازی شد و البته تعدادی هم بعدها استفاده از آن را رها کردند و از فناوری‌های دیگری استفاده کردند.
کار این پلاگین تعریف یک سری ContentType مانند audio/mp3 است و موقعی‌که مرورگر در رندر کردن این صفحات به چنین محتوایی برخورد کند، پلاگین مربوط به این محتوا را در حافظه بار می‌کند تا پلاگین را در حافظه رندر کرده و جابجایی داده‌ها با پلاگین صورت بگیرد. سپس آن پلاگین محتوای مربوطه را رندر می‌کند. امروزه پلاگین‌ها در همان قسمت از حافظه صفحه مرورگر بار می‌شوند و مانند مرورگرهای قدیمی مجبور به اجرای برنامه خارجی برای محتواهای ناشناخته نیستند.
این API نیاز دارد هر پلاگین تقریبا 15 تابع را پیاده سازی کند. این توابع برای پیاده سازی، ایجاد، نابودسازی آن و موقعیت مکانی آن به کار می‌روند. NPAPI همچنین امکاناتی از قبیل اسکریت نویسی، چاپ کردن، تمام صفحه شدن، پلاگین بدون پنجره، استریم کردن محتوا را نیز دارد.
مبداء و منشا ابتدایی این فناوری از شرکت Adobe و محصول Adobe Reader آن و خواندن PDF‌های تحت وب آغاز گشت. در آن زمان در وب، تنها فرمت HTML به همراه تصاویر به عنوان محتوا حساب میشد و مابقی نوع‌ها به دانلود ختم می‌شدند و شرکت ادوب قصد داشت کاربران تجربه‌ی جدیدی از خواندن فایل‌های PDF را بر روی مرورگر وب داشته باشند و برای دیدن حتما نیازی به دانلود نداشته باشند.
شرکت ادوب برای جلب نظر توسعه دهنگان netscape از یک نسخه‌ی دمو استفاده کرد و موقعی که روی لینک یک PDF کلیک میشد به جای دانلود آن، محتوا داخل صفحه مرورگر رندر میشد که مخلوطی از کدهای html و PDF بود ولی آن‌ها خواستار یک سیستم یکپارچه بودند تا دیگر مرورگر netscape درگیر آن نباشد و بدون وابستگی به مرورگر و به طور مستقل این کار انجام شود که کم کم باعث ایجاد این API شد و از آن موقع در طول این سال‌ها مرورگرهای زیادی از این فناوری استفاده کردند تا استاندارد عمومی در توسعه مرورگرها باشد.

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

پشتیبانی از اسکریپت نویسی
این ویژگی اجازه میدهد که شما با استفاده از کدهای جاوااسکریپت، در صفحات وب با پلاگین تعامل کنید. ابتدا netscape این امکان را اضافه کرد و بعدها موزیلا این ویژگی را با استفاده از فناوری هایی چون Live Connect ،  XP Connect و npRuntime ارتقاء بخشید.

Live Connect
از netscape 4 به بعد NPAPI برای اسکریپت نویسی توسعه یافت. این ویژگی به مرورگرها اجازه میدهد که برنامه‌های نوشته شده با جاوا و جاوااسکریپت، با صفحات وب به تعامل بپردازند. به عنوان مثال اپلت نوشته شده با جاوا می‌تواند با کدهای داخل صفحه ارتباط برقرار کند یا بیشتر از خود اسکریت‌های صفحه با محیط جاوااسکریت داخلی ارتباط برقرار کند.  با این ویژگی یک پلاگین میتواند یک نمونه کلاس جاوا را پیاده سازی و بازگرداند. این کلاس میتواند از طریق جاوااسکریت یا اپلت‌های جاوا صدا زده شود.

XP Connect
ابتدا قبل از هر چیز بگذارید با XPCOM اشنا شویم. XPCOM یا Cross Platform Component Object Model از طرف شرکت موزیلا ارائه شده است و اصلی‌ترین ویژگی آن اتصال چندین زبان به یکدیگر از طریق IDL یا یک زبان واسط است. بدین ترتیب برنامه نویس‌ها میتوانستند کدهای اختصاصی خود را با دیگر کامپوننت‌ها مرتبط کنند.
حال کار xpconnect برقراری ارتباط بین جاوااسکریپت با XPCOM یا کدهای نوشته شده توسعه گران است. XP Connect به اشیاء جاوااسکریپتی اجازه می‌دهد به طور مستقیم به اشیاء XPCom دسترسی داشته و آن‌ها را دستکاری کنند.

NPRuntime
در پایان سال 2004 بسیاری از شرکت‌های اصلی ارائه کننده مرورگرهای وب که از NPAPI استفاده می‌کردند، به این توافق رسیدند که از فناوری NPRuntime به عنوان یک اکستنشن (افزونه) برای تامین اسکریپت نویسی NPAPI استفاده کنند. اسکریپت نویسی این فناوری مستقل از دیگر فناوری‌هایی چون جاوا و XPCOM است و توسط گوگل (در آن زمان)، فایرفاکس، سافاری و اپرا (در آن زمان)  پشتیبانی می‌شود.

PPAPI
این فناوری در 12 آگوست 2009 معرفی شد. Pepper Plugin API مجموعه ای از تغییرات و اصلاحات روی NPAPI است که باعث انعطاف پذیری و امنیت بیشتر می‌شود. این افزونه جهت پیاده سازی آسان اجرای پلاگین در یک پروسه‌ی جداگانه است. هدف این پروژه تهیه یک فریمورک برای ایجاد پلاگین‌های مستقل یا Cross-Platform میباشد.
تعدادی از مواردی که در طراحی این افزونه در نظر گرفته شده است:
  • اجرای جداگانه از پروسه‌ی مرورگر
  • تعریف رویدادهای استاندارد و رسم تصاویر دو بعدی
  • تهیه گرافیک سه بعدی
  • ریجستری پلاگین
  • استاندارد سازی برای استفاده از سیستم رندر مرورگر Compositing Process 
  • تعریف مفهوم یا معنای واحد از NPAPI بین تمامی مروگرها
مرورگرهایی که در حال حاضر به این افزونه روی آورده اند طبعا مرورگر کروم و اپرا از نسخه 24 به بعد است.
شرکت موزیلا در سال 2011 اعلام کرد که فعلا علاقه ای به شرکت در این پروژه ندارد.
شرکت ادوب برای افزونه flash player اعلام کرد که دیگر تنها بر روی PPAPI فعالیت می‌کنند و از آخرین نسخه فلش پلیر 11.2 که برای NPAPI ایجاد شده است تنها به مدت پنج سال بسته‌های آپدیت آن را در دسترس قرار میدهد.

ActiveX
یکی دیگر از این پلاگین‌ها ActiveX است که توسط IE مورد استفاده قرار می‌گیرد ولی در مرورگر Edge  حذف شده است. به این دلیل، پشتیبانی از جاوا در این مرورگر قطع شده است و فلش پلیر را به صورت ذاخلی Built-in پشتیبانی می‌کند. امروزه بسیاری از تولیدکنندگان اعتقاد دارند که با Html5 بسیاری از مسائل حل می‌شود.