مطالب دوره‌ها
نگاهی به SignalR Clients
در قسمت قبل موفق به ایجاد اولین Hub خود شدیم. در ادامه، برای تکمیل برنامه نیاز است تا کلاینتی را نیز برای آن تهیه کنیم.
مصرف کنندگان یک Hub می‌توانند انواع و اقسام برنامه‌های کلاینت مانند jQuery Clients و یا حتی یک برنامه کنسول ساده باشند و همچنین Hubهای دیگر نیز قابلیت استفاده از این امکانات Hubهای موجود را دارند. تیم SignalR امکان استفاده از Hubهای آن‌را در برنامه‌های دات نت 4 به بعد، برنامه‌های WinRT، ویندوز فون 8، سیلورلایت 5، jQuery و همچنین برنامه‌های CPP نیز مهیا کرده‌اند. به علاوه گروه‌های مختلف نیز با توجه به سورس باز بودن این مجموعه، کلاینت‌های iOS Native، iOS via Mono و Android via Mono را نیز به این لیست اضافه کرده‌اند.


بررسی کلاینت‌های jQuery

با توجه به پروتکل مبتنی بر JSON سیگنال‌آر، استفاده از آن در کتابخانه‌های جاوا اسکریپتی همانند jQuery نیز به سادگی مهیا است. برای نصب آن نیاز است در کنسول پاور شل نوگت، دستور زیر را صادر کنید:
 PM> Install-Package Microsoft.AspNet.SignalR.JS
برای نمونه به solution پروژه قبل، یک برنامه وب خالی دیگر را اضافه کرده و سپس دستور فوق را بر روی آن اجرا نمائید. در این حالت فقط باید دقت داشت که فرامین بر روی کدام پروژه اجرا می‌شوند:


با استفاده از افزونه SignalR jQuery، به دو طریق می‌توان به یک Hub اتصال برقرار کرد:
الف) استفاده از فایل proxy تولید شده آن (این فایل، در زمان اجرای برنامه تولید می‌شود و یا امکان استفاده از آن به کمک ابزارهای کمکی نیز وجود دارد)
نمونه‌ای از آن‌را در قسمت قبل ملاحظه کردید؛ همان فایل تولید شده در مسیر /signalr/hubs برنامه. به نوعی به آن Service contract نیز گفته می‌شود (ارائه متادیتا و قراردادهای کار با یک سرویس Hub). این فایل همانطور که عنوان شد به صورت پویا در زمان اجرای برنامه ایجاد می‌شود.
امکان تولید آن توسط برنامه کمکی signalr.exe نیز وجود دارد؛ برای دریافت آن می‌توان از طریق NuGet اقدام کرد (بسته Microsoft.AspNet.SignalR.Utils) که نهایتا در پوشه packages قرار خواهد گرفت. نحوه استفاده از آن نیز به صورت زیر است:
 Signalr.exe ghp http://localhost/
در این دستور ghp مخفف generate hub proxy است و نهایتا فایلی را به نام server.js تولید می‌کند.

ب) بدون استفاده از فایل proxy و به کمک روش late binding (انقیاد دیر هنگام)

برای کار با یک Hub از طریق jQuery مراحل ذیل باید طی شوند:
1) ارجاعی به Hub باید مشخص شود.
2) روال‌های رخدادگردان تنظیم گردند.
3) اتصال به Hub برقرار گردد.
4) متدی فراخوانی شود.

در اینجا باید دقت داشت که امکانات Hub به صورت خواص
 $.connection
در سمت کلاینت جی‌کوئری، در دسترس خواهند بود. برای مثال:
 $.connection.chatHub
و نام‌های بکارگرفته شده در اینجا مطابق روش‌های متداول نام گذاری در جاوا اسکریپت، camel case هستند.

خوب، تا اینجا فرض بر این است که یک پروژه خالی ASP.NET را آغاز و سپس فرمان نصب Microsoft.AspNet.SignalR.JS را نیز همانطور که عنوان شد، صادر کرده‌اید. در ادامه یک فایل ساده html را به نام chat.htm، به این پروژه جدید اضافه کنید (برای استفاده از کتابخانه جاوا اسکریپتی SignalR الزامی به استفاده از صفحات کامل پروژه‌های وب نیست).
<!DOCTYPE>
<html>
<head>
    <title></title>
    <script src="Scripts/jquery-1.6.4.min.js" type="text/javascript"></script>
    <script src="Scripts/jquery.signalR-1.0.1.min.js" type="text/javascript"></script>
    <script src="http://localhost:1072/signalr/hubs" type="text/javascript"></script>
</head>
<body>
    <div>
        <input id="txtMsg" type="text" /><input id="send" type="button" value="send msg" />
        <ul id="messages">
        </ul>
    </div>
    <script type="text/javascript">
        $(function () {
            var chat;
            $.connection.hub.logging = true; //اطلاعات بیشتری را در جاوا اسکریپت کنسول مرورگر لاگ می‌کند
            chat = $.connection.chat; //این نام مستعار پیشتر توسط ویژگی نام هاب تنظیم شده است
            chat.client.hello = function (message) {
                //متدی که در اینجا تعریف شده دقیقا مطابق نام متد پویایی است که در هاب تعریف شده است
                //به این ترتیب سرور می‌تواند کلاینت را فراخوانی کند
                $("#messages").append("<li>" + message + "</li>");
            };
            $.connection.hub.start(/*{ transport: 'longPolling' }*/); // فاز اولیه ارتباط را آغاز می‌کند

            $("#send").click(function () {
                // Hub's `SendMessage` should be camel case here
                chat.server.sendMessage($("#txtMsg").val());
            });
        });
    </script>
</body>
</html>
کدهای آن‌را به نحو فوق تغییر دهید.
توضیحات:
همانطور که ملاحظه می‌کنید ابتدا ارجاعاتی به jquery و jquery.signalR-1.0.1.min.js اضافه شده‌اند. سپس نیاز است مسیر دقیق فایل پروکسی هاب خود را نیز مشخص کنیم. اینکار با تعریف مسیر signalr/hubs انجام شده است.
<script src="http://localhost:1072/signalr/hubs" type="text/javascript"></script>
در ادامه توسط تنظیم connection.hub.logging سبب خواهیم شد تا اطلاعات بیشتری در javascript console مرورگر لاگ شود.
سپس ارجاعی به هاب تعریف شده، تعریف گردیده است. اگر از قسمت قبل به خاطر داشته باشید، توسط ویژگی HubName، نام chat را برگزیدیم. بنابراین connection.chat ذکر شده دقیقا به این هاب اشاره می‌کند.
سپس سطر chat.client.hello مقدار دهی شده است. متد hello، متدی dynamic و تعریف شده در سمت هاب برنامه است. به این ترتیب می‌توان به پیام‌های رسیده از طرف سرور گوش فرا داد. در اینجا، این پیام‌ها، به li ایی با id مساوی messages اضافه می‌شوند.
سپس توسط فراخوانی متد connection.hub.start، فاز negotiation شروع می‌شود. در اینجا حتی می‌توان نوع transport را نیز صریحا انتخاب کرد که نمونه‌ای از آن را به صورت کامنت شده جهت آشنایی با نحوه تعریف آن مشاهده می‌کنید. مقادیر قابل استفاده در آن به شرح زیر هستند:
 - webSockets
- forverFrame
- serverSentEvents
- longPolling
سپس به رویدادهای کلیک دکمه send گوش فرا داده و در این حین، اطلاعات TextBox ایی با id مساوی txtMsg را به متد SendMessage هاب خود ارسال می‌کنیم. همانطور که پیشتر نیز عنوان شد، در سمت کلاینت، تعریف متد SendMessage باید camel case باشد.

اکنون به صورت جداگانه یکبار برنامه hub را در مرورگر باز کنید. سپس بر روی فایل chat.htm کلیک راست کرده و گزینه مشاهده آن را در مرورگر نیز انتخاب نمائید (گزینه View in browser منوی کلیک راست).

خوب! پروژه کار نمی‌کند! برای اینکه مشکلات را بهتر بتوانید مشاهده کنید نیاز است به JavaScript Console مرورگر خود مراجعه نمائید. برای مثال در مرورگر کروم دکمه F12 را فشرده و برگه Console آن‌را باز کنید. در اینجا اعلام می‌کند که فاز negotiation قابل انجام نیست؛ چون مسیر پیش فرضی را که انتخاب کرده است، همین مسیر پروژه دومی است که اضافه کرده‌ایم (کلاینت ما در پروژه دوم قرار دارد و نه در همان پروژه اول هاب).
برای اینکه مسیر دقیق hub را در این حالت مشخص کنیم، سطر زیر را به ابتدای کدهای جاوا اسکریپتی فوق اضافه نمائید:
 $.connection.hub.url = 'http://localhost:1072/signalr'; //چون در یک پروژه دیگر قرار داریم
اکنون اگر مجدا سعی کنید، باز هم برنامه کار نمی‌کند و پیام می‌دهد که امکان دسترسی به این سرویس از خارج از دومین آن میسر نیست. برای اینکه این مجوز را صادر کنیم نیاز است تنظیمات مسیریابی پروژه هاب را به نحو ذیل ویرایش نمائیم:
using System;
using System.Web;
using System.Web.Routing;
using Microsoft.AspNet.SignalR;

namespace SignalR02
{
    public class Global : HttpApplication
    {
        protected void Application_Start(object sender, EventArgs e)
        {
            // Register the default hubs route: ~/signalr
            RouteTable.Routes.MapHubs(new HubConfiguration
            {
                EnableCrossDomain = true
            });
        }
    }
}
با تنظیم EnableCrossDomain به true اینبار فاز‌های آغاز ارتباط با سرور برقرار می‌شوند:
 SignalR: Auto detected cross domain url. jquery.signalR-1.0.1.min.js:10
SignalR: Negotiating with 'http://localhost:1072/signalr/negotiate'. jquery.signalR-1.0.1.min.js:10
SignalR: SignalR: Initializing long polling connection with server. jquery.signalR-1.0.1.min.js:10
SignalR: Attempting to connect to 'http://localhost:1072/signalr/connect?transport=longPolling&connectionToken…NRh72omzsPkKqhKw2&connectionData=%5B%7B%22name%22%3A%22chat%22%7D%5D&tid=3' using longPolling. jquery.signalR-1.0.1.min.js:10
SignalR: Longpolling connected jquery.signalR-1.0.1.min.js:10
مطابق این لاگ‌ها ابتدا فاز negotiation انجام می‌شود. سپس حالت long polling را به صورت خودکار انتخاب می‌کند.

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

یک نکته:
اگر از ویندوز 8 (یعنی IIS8) و VS 2012 استفاده می‌کنید، برای استفاده از حالت Web socket، ابتدا فایل وب کانفیگ برنامه را باز کرده و در قسمت httpRunTime، مقدار ویژگی targetFramework را بر روی 4.5 تنظیم کنید. اینبار اگر مراحل negotiation را بررسی کنید در همان مرحله اول برقراری اتصال، از روش Web socket استفاده گردیده است.


تمرین 1
به پروژه ساده و ابتدایی فوق یک تکست باکس دیگر به نام Room را اضافه کنید؛ به همراه دکمه join. سپس نکات قسمت قبل را در مورد الحاق به یک گروه و سپس ارسال پیام به اعضای گروه را پیاده سازی نمائید. (تمام نکات آن با مطلب فوق پوشش داده شده است و در اینجا باید صرفا فراخوانی متدهای عمومی دیگری در سمت هاب، صورت گیرد)

تمرین 2
در انتهای قسمت دوم به نحوه ارسال پیام از یک هاب به هابی دیگر اشاره شد. این MonitorHub را ایجاد کرده و همچنین یک کلاینت جاوا اسکریپتی را نیز برای آن تهیه کنید تا بتوان اتصال و قطع اتصال کلیه کاربران سیستم را مانیتور و مشاهده کرد.


پیاده سازی کلاینت jQuery بدون استفاده از کلاس Proxy

در مثال قبل، از پروکسی پویای مهیای در آدرس signalr/hubs استفاده کردیم. در اینجا قصد داریم، بدون استفاده از آن نیز کار برپایی کلاینت را بررسی کنیم.
بنابراین یک فایل جدید html را مثلا به نام chat_np.html به پروژه دوم برنامه اضافه کنید. سپس محتویات آن‌را به نحو زیر تغییر دهید:
<!DOCTYPE>
<html>
<head>
    <title></title>
    <script src="Scripts/jquery-1.6.4.min.js" type="text/javascript"></script>
    <script src="Scripts/jquery.signalR-1.0.1.min.js" type="text/javascript"></script>
</head>
<body>
    <div>
        <input id="txtMsg" type="text" /><input id="send" type="button" value="send msg" />
        <ul id="messages">
        </ul>
    </div>
    <script type="text/javascript">
        $(function () {                        
            $.connection.hub.logging = true; //اطلاعات بیشتری را در جاوا اسکریپت کنسول مرورگر لاگ می‌کند

            var connection = $.hubConnection();
            connection.url = 'http://localhost:1072/signalr'; //چون در یک پروژه دیگر قرار داریم
            var proxy = connection.createHubProxy('chat');

            proxy.on('hello', function (message) {
                //متدی که در اینجا تعریف شده دقیقا مطابق نام متد پویایی است که در هاب تعریف شده است
                //به این ترتیب سرور می‌تواند کلاینت را فراخوانی کند
                $("#messages").append("<li>" + message + "</li>");
            });

            $("#send").click(function () {
                // Hub's `SendMessage` should be camel case here
                proxy.invoke('sendMessage', $("#txtMsg").val());
            });

            connection.start();
        });
    </script>
</body>
</html>
در اینجا سطر مرتبط با تعریف مسیر اسکریپت‌های پویای signalr/hubs را دیگر در ابتدای فایل مشاهده نمی‌کنید. کار تشکیل proxy اینبار از طریق کدنویسی صورت گرفته است. پس از ایجاد پروکسی، برای گوش فرا دادن به متدهای فراخوانی شده از طرف سرور از متد proxy.on و نام متد فراخوانی شده سمت سرور استفاده می‌کنیم و یا برای ارسال اطلاعات به سرور از متد proxy.invoke به همراه نام متد سمت سرور استفاده خواهد شد.


کلاینت‌های دات نتی SignalR
تا کنون Solution ما حاوی یک پروژه Hub و یک پروژه وب کلاینت جی‌کوئری است. به همین Solution، یک پروژه کلاینت کنسول ویندوزی را نیز اضافه کنید.
سپس در خط فرمان پاور شل نوگت دستور زیر را صادر نمائید تا فایل‌های مورد نیاز به پروژه کنسول اضافه شوند:
 PM> Install-Package Microsoft.AspNet.SignalR.Client
در اینجا نیز باید دقت داشت تا دستور بر روی default project صحیحی اجرا شود (حالت پیش فرض، اولین پروژه موجود در solution است).
پس از نصب آن اگر به پوشه packages مراجعه کنید، نگارش‌های مختلف آن‌را مخصوص سیلورلایت، دات نت‌های 4 و 4.5، WinRT و ویندوز فون8 نیز می‌توانید در پوشه Microsoft.AspNet.SignalR.Client ملاحظه نمائید. البته در ابتدای نصب، انتخاب نگارش مناسب، بر اساس نوع پروژه جاری به صورت خودکار صورت می‌گیرد.
مدل برنامه نویسی آن نیز بسیار شبیه است به حالت عدم استفاده از پروکسی در حین استفاده از jQuery که در قسمت قبل بررسی گردید و شامل این مراحل است:
1) یک وهله از شیء HubConnection را ایجاد کنید.
2) پروکسی مورد نیاز را جهت اتصال به Hub از طریق متد CreateProxy تهیه کنید.
3) رویدادگردان‌ها را همانند نمونه کدهای جاوا اسکریپتی قسمت قبل، توسط متد On تعریف کنید.
4) به کمک متد Start، اتصال را آغاز نمائید.
5) متدها را به کمک متد Invoke فراخوانی نمائید.

using System;
using Microsoft.AspNet.SignalR.Client.Hubs;

namespace SignalR02.WinClient
{
    class Program
    {
        static void Main(string[] args)
        {
            var hubConnection = new HubConnection(url: "http://localhost:1072/signalr");
            var chat = hubConnection.CreateHubProxy(hubName: "chat");

            chat.On<string>("hello", msg => {
                Console.WriteLine(msg);
            });

            hubConnection.Start().Wait();

            chat.Invoke<string>("sendMessage", "Hello!");

            Console.WriteLine("Press a key to terminate the client...");
            Console.Read();
        }
    }
}
نمونه‌ای از این پیاده سازی را در کدهای فوق ملاحظه می‌کنید که از لحاظ طراحی آنچنان تفاوتی با نمونه ذهنی جاوا اسکریپتی ندارد.

نکته مهم
کلیه فراخوانی‌هایی که در اینجا ملاحظه می‌کنید غیرهمزمان هستند.
به همین جهت پس از متد Start، متد Wait ذکر شده‌است تا در این برنامه ساده، پس از برقراری کامل اتصال، کار invoke صورت گیرد و یا زمانیکه callback تعریف شده توسط متد chat.On فراخوانی می‌شود نیز این فراخوانی غیرهمزمان است و خصوصا اگر نیاز است رابط کاربری برنامه را در این بین به روز کنید باید به نکات به روز رسانی رابط کاربری از طریق یک ترد دیگر دقت داشت.
مطالب
نگاهی به اجزای تعاملی Twitter Bootstrap
پس از آشنایی با طرحبندی صفحات و امکانات متداول Twitter Bootstrap، در این قسمت به کامپوننت‌ها و اجزای تعاملی آن مانند منوها، برگه‌ها و امثال آن خواهیم پرداخت.

منوهای پایین افتادنی (Dropdown menus) در Twitter Bootstrap

برای کار با منوها، حداقل نیازهایی که باید به صفحه اضافه شوند، فایل css مرتبط با Twitter Bootstrap، فایل اسکریپت‌های جی‌کوئری و فایل bootstrap.min.js است.
در ادامه، ساختار متداول یک منوی نمونه ایجاد شده را ملاحظه می‌کنید:
    <div class="container-fluid">
        <div class="row-fluid">
            <div class="span12">
                <div class="dropdown">
                    <a class="dropdown-toggle" data-toggle="dropdown" href="#">منوی پایین افتادنی 
                    <span  class="caret"></span></a>
                    <ul class="dropdown-menu">
                        <li><a href="http://www.site1.com">site1</a></li>
                        <li><a href="http://www.site2.com">site2</a></li>
                        <li><a href="http://www.site3.com">site3</a></li>
                        <li class="divider"></li>
                        <li class="dropdown-submenu"><a href="#">سایر موارد</a>
                            <ul class="dropdown-menu">
                                <li><a href="http://www.site4.com">site4</a></li>
                                <li><a href="http://www.site5.com">site5</a></li>
                            </ul>
                        </li>
                    </ul>
                </div>
            </div>
        </div>
    </div>

در اینجا به یک div، کلاس dropdown نسبت داده شده است؛ از این جهت که می‌توان این منو را به انواع و اقسام المان‌های صفحه نیز نسبت داد. به این ترتیب، منو از محل قرارگیری این المان باز خواهد شد. در ادامه روال متداول تعریف منو را در Bootstrap، ملاحظه می‌کنید. کلاس dropdown-toggle سبب خواهد شد تا با کلیک ماوس بر روی لینک، منو ظاهر شود. کلاس caret نیز سبب نمایش مثلث رو به پایین، جهت مشخص سازی وجود منو در این محل خاص، تعریف شده است.
المان‌های منو، توسط لیست‌ها تعریف می‌شوند. این لیست باید با کلاس dropdown-menu شروع شود. سپس هر عضو این لیست، یک آیتم منو را تشکیل خوهد داد. اگر نیاز به خط جدا کننده‌ای در این میان باشد، باید از کلاس divider استفاده کرد.
در اینجا همچنین امکان تعریف منوهای تو در تو نیز وجود دارد. برای اینکار تنها کافی است یک لیست دیگر را در این میان اضافه کرد. کلاس dropdown-submenu به عضو لیست دربرگیرنده زیر منو، اضافه می‌شود. زیر منو نیز دارای کلاس dropdown-menu خواهد بود.

چند نکته تکمیلی در مورد منوها:
- همانطور که در قسمت بررسی دکمه‌های Bootstrap نیز عنوان شد، برای تبدیل یک المان به دکمه فقط کافی است کلاس btn را به آن انتساب دهیم. در اینجا نیز می‌توان کلاس لینک منوی پایین افتادنی را به صورت btn btn-primary dropdown-toggle تعریف کرد تا ظاهر آن تبدیل به یک دکمه Bootstrap شود.
- در اولین div مثال فوق، کلاس dropdown ذکر شده است. می‌توان این کلاس را به dropup تغییر داد تا نحوه باز شدن منوی تعریف شده رو به بالا باشد؛ بجای رو به پایین.
- برای ساخت split button که تشکیل شده است از دو دکمه اصلی و دکمه کوچکی در کنار آن که یک زیرمنو را نمایش می‌دهد، باید به نحو زیر عمل کرد:
    <div class="container-fluid">
        <div class="row-fluid">
            <div class="span12">
                <div class="btn-group">
                    <a class="btn btn-primary" href="#">Split button</a> <a class="btn btn-primary dropdown-toggle"
                        data-toggle="dropdown" href="#"><span class="caret"></span></a>
                    <ul class="dropdown-menu">
                        <li><a href="http://www.site1.com">site1</a></li>
                        <li><a href="http://www.site2.com">site2</a></li>
                    </ul>
                </div>
            </div>
        </div>
    </div>
تنها نکته‌ای که در اینجا نسبت به حالت قبل اضافه شده است، استفاده از کلاس btn-group است. این کلاس سبب می‌شود تا دکمه‌های تعریف شده در کنار هم به شکل یک toolbar مرتب شوند.



تعریف برگه‌ها در Twitter Bootstrap

برای تعریف منوهای راهبری سایت به شکل برگه، کار با استفاده از کلاس nav و تعریف یک لیست ساده شروع می‌شود:
    <div class="container">
        <div class="row">
            <h2>
                Navigational menus
            </h2>
            <div class="span3">
                <ul class="nav nav-tabs">
                    <li class="nav-header">nav nav-tabs</li>
                    <li class="active"><a href="#">Home</a></li>
                    <li><a href="#">Contact</a></li>
                    <li><a href="#">Login</a></li>
                </ul>
            </div>
            <div class="span3">
                <ul class="nav nav-tabs nav-stacked">
                    <li class="nav-header">nav nav-tabs nav-stacked</li>
                    <li class="active"><a href="#">Home</a></li>
                    <li><a href="#">Contact</a></li>
                    <li><a href="#">Login</a></li>
                </ul>
            </div>
            <div class="span3">
                <ul class="nav nav-pills">
                    <li class="nav-header">nav nav-pills</li>
                    <li class="active"><a href="#">Home</a></li>
                    <li><a href="#">Contact</a></li>
                    <li><a href="#">Login</a></li>
                </ul>
            </div>
            <div class="span3">
                <ul class="nav nav-list">
                    <li class="nav-header">nav nav-list</li>
                    <li class="active"><a href="#">Home</a></li>
                    <li><a href="#">Contact</a></li>
                    <li><a href="#">Login</a></li>
                    <li class="dropdown"><a class="dropdown-toggle" data-toggle="dropdown" href="#">Menu
                        ...<span class="caret"></span></a>
                        <ul class="dropdown-menu">
                            <li><a href="http://www.site1.com">site1</a></li>
                            <li><a href="http://www.site2.com">site2</a></li>
                        </ul>
                    </li>
                </ul>
            </div>
        </div>
    </div>


- اضافه شدن کلاس nav، بولت‌های لیست را حذف و ویژگی تغییر رنگ زمینه هر یک از عناصر لیست را با حرکت اشاره‌گر ماوس بر روی آن فعال می‌کند.
- برای اعمال اشکال مختلف به کلاس nav، می‌توان از سایر کلاس‌های مرتبط استفاده کرد. اگر از nav-tabs استفاده شود، این لیست عمودی تبدیل به یک لیست افقی خواهد شد. اگر کلاس active به یکی از آیتم‌های آن نسبت داده شود (بیانگر صفحه جاری)، این گزینه حالت انتخاب شده را پیدا می‌کند.
- در هر حالت، برای تبدیل چیدمان افقی به عمودی، از کلاس nav-stacked استفاده نمائید.
- کلاس nav-pills، برای نمایش عنصر فعال، از یک مستطیل با گوشه‌های گرد استفاده می‌کند.
- اگر می‌خواهید این گوشه‌ها گرد نباشند، از nav-list استفاده کنید.
- در هر کدام از حالت‌ها می‌توان از یک گزینه اختیاری با کلاس nav-header برای نمایش متنی خاکستری بالای منوی راهبری استفاده کرد.
- همانطور که در آخرین لیست اضافه شده در مثال فوق ملاحظه می‌کنید، امکان تعریف منوهای پایین افتادنی در اینجا نیز میسر است. در این حالت کلاس li تعریف شده باید dropdown تعریف شود. مابقی نکات آن مانند قبل است.


تعریف یک Tab به همراه محتوای برگه‌های آن در داخل یک صفحه

در حالت تعریف منوهای راهبری فوق، هر عنصر برگه‌های تعریف شده به یک صفحه جدید لینک شده بود. اگر نیاز باشد تا هر برگه، محتوایی داخل همان صفحه داشته باشد باید به نحو ذیل عمل کرد:
    <div class="container">
        <div class="row">
            <div class="span12">
                <div class="tabbable">
                    <ul class="nav nav-tabs">
                        <li class="active"><a data-toggle="tab" href="#tab1">Home</a></li>
                        <li><a data-toggle="tab" href="#tab2">About</a></li>
                    </ul>
                    <div class="tab-content">
                        <div class="tab-pane active" id="tab1">
                            data ... data ...
                        </div>
                        <div class="tab-pane" id="tab2">
                            data2 ... data2 ...
                        </div>
                    </div>
                </div>
            </div>
        </div>
    </div>

در اینجا کار با کلاس tabbable شروع می‌شود. سپس از یک لیست با کلاس nav nav-tabs برای تعریف سرتیترهای برگه‌ها استفاده می‌کنیم.
اگر به مثال فوق دقت کنید، اینبار hrefهای تعریف شده به tab1 و tab2 اشاره می‌کنند. ایندو در حقیقت id محتوای متناظر هستند که در قسمت div ایی با کلاس tab-content به div هایی با id مساوی tab1 و tab2 انتساب داده شده‌اند.


شیوه دوم تعریف منوی راهبری سایت به کمک Twitter Bootstrap

اگر علاقمند باشید که منوی راهبری بالای سایت دارای یک حاشیه به همراه مسایل طراحی واکنش‌گرا باشد، می‌توان از کامپوننت navbar مجموعه Bootstrap استفاده کرد:
    <div class="container">
        <div class="row">
            <div class="span12">
                <nav class="navbar navbar-inverse">
                    <div class="navbar-inner">
                        <a href="/" class="brand">نام سایت در اینجا</a> 
                        <a class="btn btn-navbar" data-toggle="collapse" data-target=".nav-collapse">
                            <span class="icon-bar"></span>
                            <span class="icon-bar"></span>
                            <span class="icon-bar"></span>
                        </a>
                        <div class="nav-collapse collapse">
                            <ul class="nav">
                                <li><a href="/about">درباره</a></li>
                                <li><a href="/contact">تماس</a></li>
                                <li class="dropdown"><a class="dropdown-toggle" data-toggle="dropdown" href="#">Menu
                                    ...<span class="caret"></span></a>
                                    <ul class="dropdown-menu">
                                        <li><a href="http://www.site1.com">site1</a></li>
                                        <li><a href="http://www.site2.com">site2</a></li>
                                    </ul>
                                </li>
                            </ul>
                            <form class="navbar-search pull-right input-append" action="/search">
                            <input class="span2" type="search" />
                            <button class="btn" type="button">
                                جستجو</button>
                            </form>
                        </div>
                    </div>
                </nav>
            </div>
        </div>
    </div>


navbar نیز همانند بسیاری از کامپوننت‌های Bootstrap، بر اساس ul و liها کار می‌کند. در ابتدای کار، کلاس nav را به تگ ul انتساب می‌دهیم. این مورد با مباحث قسمت قبلی در مورد تدارک برگه‌ها، تفاوتی نمی‌کند. به این ترتیب بولت‌های لیست حذف شده و همچنین تغییر رنگ پس زمینه، با حرکت اشاره‌گر ماوس بر روی آیتم‌ها را سبب می‌شود. سپس کل این ul و li ها، داخل تگ nav قرار می‌گیرند با کلاسی مساوی navbar. تا اینجا لیست عمودی تبدیل به یک لیست افقی می‌شود.
در ادامه برای اضافه کردن حاشیه‌ای به اطراف این منوی راهبری و تمایز آن از سایر قسمت‌های صفحه، یک div با کلاس navbar-inner را اضافه خواهیم کرد.
عموما مرسوم است که در منوی راهبری اصلی سایت، نام سایت یا متنی مشخص نیز در قسمتی از این منو ظاهر شود. برای انجام اینکار، کافی است یک لینک را با کلاس brand اضافه کنیم.
این موارد، اصول کلی تهیه یک منوی راهبری اصلی سایت را توسط Bootstrap بیان می‌کنند. در ادامه به چند نکته تکمیلی خواهیم پرداخت:
- اگر به تگ nav، کلاس navbar-static-top را اضافه کنیم، فاصله بین منو و اطراف صفحه را حذف می‌کند.
- اگر علاقمند هستیم که منوی بالای صفحه حتی با اسکرول به پایین محتوای نمایش داده شده، همواره نمایان باشد و بر روی محتوا قرار گیرد، می‌توان به تگ nav، کلاس navbar-fixed-top را اضافه کرد. یا اگر نیاز است این منو در پایین صفحه به صورت ثابت نمایش داده شود از navbar-fixed-bottom می‌شود استفاده کرد.
در این حالت خاص ممکن است منو، قسمتی از ابتدای محتوای صفحه را مخفی کند و این محتوا زیر منو واقع شود. برای بهبود آن باید margin-top مرتبط با body را مقدار دهی کنید (حدود 40px کافی است).
- استفاده از کلاس navbar-inverse (همانند مثال فوق)، سبب معکوس شدن رنگ زمینه منوی راهبری می‌شود.
- همچنین در اینجا نیز می‌توان یک dropdown-menu را به نحوی که ملاحظه می‌کنید، به منوی اصلی سایت افزود.
- امکان قرار دادن فرم‌های خاصی مانند فرم جستجو نیز در منوی راهبری وجود دارد. در این حالت از کلاس navbar-search مانند مثال فوق استفاده خواهد شد. کلاس pull-right این المان را به سمت راست صفحه (در اینجا به سمت چپ با توجه به RTL بودن قالب)، هدایت می‌کند و کلاس input-append سبب می‌شود تا دکمه و تکست باکس تعریف شده در یک سطر و کنار هم قرارگیرند تا ظاهر بهتری حاصل شود. در حالت کلی کلاس navbar-form نیز برای این نوع فرم‌ها درنظر گرفته شده است.
- اگر دقت کرده باشید، کل محتوای منو، به همراه فرم تعریف شده، در یک div با کلاس nav-collapse قرار گرفته است. هدف از اینکار ناپدید شدن خودکار قسمت‌های طولانی یا نچندان مهم، در حین مرور سایت با اندازه‌های مرورگر کوچکتر مانند مرورگرهای موبایل است. همچنین اگر بخواهیم در این حالت که قسمت‌هایی ناپدید شده‌اند، یک دکمه با سه سطر که بیانگر منویی مخفی است را نمایش دهیم می‌توان از کلاس btn-navbar استفاده کرد؛ که نمونه‌ای از آن‌را در مثال فوق ملاحظه می‌کنید. این دکمه بر اساس data-target مشخص شده، سبب مخفی یا ظاهر شدن قسمتی از صفحه می‌گردد.




تعیین موقعیت کاربر در صفحه به کمک breadcrumbs در Bootstrap

    <div class="container">
        <div class="row">
            <div class="span12">
                <ul class="breadcrumb">
                    <li><a href="/level1">سطح یک</a> <span class="divider">/</span></li>
                    <li><a href="/level2">سطح دو</a> <span class="divider">/</span></li>
                    <li class="active">سطح سه</li>
                </ul>
            </div>
        </div>
    </div>
عموما مرسوم است در یک سایت چند سطحی، موقعیت جاری کاربر، به نحوی به او اعلام شود. یکی از این روش‌ها استفاده از breadcrumbs است که نمونه‌ای از آن‌را در مثال فوق ملاحظه می‌کنید.
- در اینجا نیز برای تعریف breadcrumbs از ul و li استفاده شده است به همراه کلاس breadcrumb.
- برای ایجاد فاصله و نمایش یک خط جداکننده، از کلاس divider کمک گرفته شده است.
- صفحه جاری با کلاس active مشخص گردیده؛ بدون تعریف لینک.


تعریف قسمت صفحه بندی یک لیست یا گرید به کمک Bootstrap

<div class="container">
        <div class="row">
            <div class="span12">
                <div class="pagination pagination-centered pagination-large">
                    <ul>
                        <li class="disabled"><a href="#">Prev</a></li>
                        <li class="active"><a href="/page/1">1</a></li>
                        <li><a href="/page/2">2</a></li>
                        <li><a href="/page/3">3</a></li>
                        <li><a href="/page/4">4</a></li>
                        <li><a href="#">Next</a></li>
                    </ul>
                </div>
            </div>
        </div>
    </div>

برای نمایش زیباتر قسمت صفحه بندی یک لیست یا گرید می‌توان از یک سری ul و li مزین شده با کلاس pagination استفاده کرد. کلاس pagination-centered، آن‌را در وسط صفحه قرار خواهد داد (حالت‌های چپ و راست نیز وجود دارند). کلاس pagination-large، این قسمت را اندکی بزرگتر از معمول نمایش می‌دهد.
در اینجا کلاس disabled، سبب غیرفعال نمایش داده شدن لینک به یک صفحه و کلاس active، بیانگر نمایش صفحه جاری است.


نمایش برچسب‌ها و اعلانات با زمینه‌های مختلف به کمک Bootstrap

برای نمایش برچسب‌های کوتاه با زمینه‌ای متفاوت از کلاس label استفاده می‌شود. افزودن کلاس‌هایی مانند  label-success و امثال آن که در مثال ذیل ذکر شده‌اند، رنگ‌های متفاوتی را سبب خواهند شد. برای گرد کردن بیش از حد گوشه این برچسب‌ها از کلاس badge استفاده می‌شود.
    <div class="container">
        <div class="row">
            <div class="span12">
                <section>
                    <ul class="unstyled">
                        <li><span class="label">پیش فرض</span></li>
                        <li><span class="label label-success">موفقیت آمیز</span></li>
                        <li><span class="label label-warning">اخطار</span></li>
                        <li><span class="label label-importatnt">مهم است</span></li>
                        <li><span class="label label-info">اطلاعات</span></li>
                        <li><span class="label label-inverse">رنگ معکوس</span></li>
                    </ul>
                </section>
                <section>
                    <ul class="unstyled">
                        <li><span class="badge">پیش فرض</span></li>
                        <li><span class="badge badge-success">موفقیت آمیز</span></li>
                        <li><span class="badge badge-warning">اخطار</span></li>
                        <li><span class="badge badge-importatnt">مهم است</span></li>
                        <li><span class="badge badge-info">اطلاعات</span></li>
                        <li><span class="badge badge-inverse">رنگ معکوس</span></li>
                    </ul>
                </section>
                <div>
                    <div class="alert">
                        <button class="close" data-dismiss="alert">&times;</button>
                        نمایش اعلانات
                    </div>
                    <div class="alert alert-danger">
                        <button class="close" data-dismiss="alert">&times;</button>
                        نمایش اعلانات
                    </div>
                    <div class="alert alert-info">
                        <button class="close" data-dismiss="alert">&times;</button>
                        نمایش اعلانات
                    </div>
                    <div class="alert alert-success">
                        <button class="close" data-dismiss="alert">&times;</button>
                        نمایش اعلانات
                    </div>
                    <div class="alert alert-error">
                        <button class="close" data-dismiss="alert">&times;</button>
                        نمایش اعلانات
                    </div>
                </div>
            </div>
        </div>
    </div>

همانطور که ملاحظه می‌کنید برای نمایش اعلانی به کاربر می‌توان از کلاس alert استفاده کرد. افزودن کلاس‌هایی مانند alert-danger، رنگ‌های متفاوتی را ارائه خواهند داد و اگر علاقمندید که کاربر بتواند این اخطار را با کلیک بر روی دکمه ضربدر کنار آن حذف کند، از یک دکمه با کلاس close و data-dismiss مساوی alert استفاده کنید. این اطلاعات به صورت خودکار توسط اسکریپت‌های bootstrap پردازش می‌شوند.
مطالب دوره‌ها
نگاهی به گزینه‌های مختلف مهیای جهت میزبانی SignalR
حداقل چهار گزینه برای Hosting سرویس‌های Hub برنامه‌های مبتنی بر SignalR وجود دارند که تا به اینجا، مورد دوم آن بیشتر بررسی گردید:
1) OWIN
2) ASP.NET Hosting
3) Self Hosting
4) Cloud و ویندوز Azure

1) OWIN
اگر به اسمبلی‌های همراه با SignalR دقت کنید، یکی از آن‌ها Microsoft.AspNet.SignalR.Owin.dll نام دارد. OWIN مخفف Open web server interface for .NET است و کار آن ایجاد لایه‌ای بین وب سرورها و برنامه‌های وب می‌باشد. یکی از اهداف مهم آن ترغیب دنیای سورس باز به تهیه ماژول‌های مختلف قابل استفاده در وب سرورهای دات نتی است. نکته‌ی مهمی که در SignalR و کلیه میزبان‌های آن وجود دارد، بنا شدن تمامی آن‌ها برفراز OWIN می‌باشد.

2) ASP.NET Hosting
بدون شک، میزبانی ASP.NET از هاب‌های SignalR، مرسوم‌ترین روش استفاده از این فناوری می‌باشد. این نوع میزبانی نیز برفراز OWIN بنا شده است. نصب آن توسط اجرای دستور پاور شل ذیل در یک پروژه وب صورت می‌گیرد:
 PM> Install-Package Microsoft.AspNet.SignalR

3) خود میزبانی یا Self hosting
خود میزبانی نیز برفراز OWIN تهیه شده است و برای پیاده سازی آن نیاز است وابستگی‌های مرتبط با آن، از طریق NuGet به کمک فرامین پاور شل ذیل دریافت شوند:
 PM> Install-Package Microsoft.AspNet.SignalR.Owin
PM> Install-Package Microsoft.Owin.Hosting -Pre
PM> Install-Package Microsoft.Owin.Host.HttpListener -Pre
مواردی که با پارامتر pre مشخص شده‌اند، در زمان نگارش این مطلب هنوز در مرحله بتا قرار دارند اما برای دموی برنامه کفایت می‌کنند.
مراحل تهیه یک برنامه ثالث (برای مثال خارج از IIS یا یک وب سرور آزمایشی) به عنوان میزبان Hubs مورد نیاز به این شرح هستند:
الف) کلاس آغازین میزبان باید با پیاده سازی اینترفیسی به نام IAppBuilder تهیه شود.
ب) مسیریابی‌های مورد نیاز تعریف گردند.
ج) وب سرور HTTP یا HTTPS توکار برای سرویس دهی آغاز گردد.

باید توجه داشت که در این حالت برخلاف روش ASP.NET Hosting، سایر اسمبلی‌های برنامه جهت یافتن Hubهای تعریف شده، اسکن نمی‌شوند. همچنین هنگام کار با jQuery مباحث عنوان شده در مورد تنظیم دسترسی‌های Cross domain نیز باید در اینجا اعمال گردند. به علاوه اجرای وب سرور توکار آن به دلایل امنیتی، نیاز به دسترسی مدیریتی دارد.

برای پیاده سازی یک نمونه، به برنامه‌ای که تاکنون تهیه کرده‌ایم، یک پروژه کنسول دیگر را به نام ConsoleHost اضافه کنید. البته باید درنظر داشت در دنیای واقعی این نوع برنامه‌ها را عموما از نوع سرویس‌های ویندوز NT تهیه می‌کنند.
در ادامه سه فرمان پاور شل یاد شده را برای افزودن وابستگی‌های مورد نیاز فراخوانی نمائید. همچنین باید دقت داشت که این دستور بر روی پروژه جدید اضافه شده باید اجرا گردد.
using System;
using Microsoft.AspNet.SignalR;
using Microsoft.AspNet.SignalR.Hubs;
using Microsoft.Owin.Hosting;
using Owin;

namespace SignalR02.ConsoleHost
{
    public class Startup
    {
        public void Configuration(IAppBuilder app)
        {
            app.MapHubs(new HubConfiguration { EnableCrossDomain = true });
        }
    }

    [HubName("chat")]
    public class ChatHub : Hub
    {
        public void SendMessage(string message)
        {
            var msg = string.Format("{0}:{1}", Context.ConnectionId, message);
            Clients.All.hello(msg);
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            using (WebApplication.Start<Startup>("http://localhost:1073/"))
            {
                Console.WriteLine("Press a key to terminate the server...");
                Console.Read();
            }
        }
    }
}
سپس یک کلاس Startup را با امضایی که مشاهده می‌کنید تهیه نمائید. در اینجا مسیریابی و تنظیمات دسترسی از سایر دومین‌ها مشخص شده‌اند. در ادامه یک Hub نمونه، تعریف و نهایتا توسط WebApplication.Start، این وب سرور راه اندازی می‌شود. اکنون اگر برنامه را اجرا کرده و به مسیر http://localhost:1073/signalr/hubs مراجعه کنید، فایل پروکسی تعاریف متادیتای مرتبط با سرور قابل مشاهده خواهد بود.
سمت کلاینت استفاده از آن هیچ تفاوتی نمی‌کند و با جزئیات آن پیشتر آشنا شده‌اید؛ برای مثال در کلاینت جی‌کوئری خاصیت connection.hub.url باید به مسیر جدید سرور هاب تنظیم گردد تا اتصالات به درستی برقرار شوند.


دریافت پروژه کامل مرتبط با این 4 قسمت (البته بدون فایل‌های باینری آن، جهت کاهش حجم 32 مگابایتی)
  SignalRSamples.zip
مطالب
روش استفاده از Async&Await در Portable Class Library دات نت 4
چند وقت پیش زمانی که قصد داشتم از یک Portable Class Library  که تحت دات نت 4 بود توی پروژه ام استفاده کنم متوجه شدم که این نوع Class Library از فضای نام System.Threading.Task پشتیبانی نمی‌کنه. قصد داشتم که از این فضای نام برای بحث TPL توی پروژه ام استفاده کنم و چند تا متد Async بنویسم. زمانی که سعی کردم  با استفاده از Nuget؛ AsyncAwaitCTP رو نصب کنم با خطای زیر روبرو شدم.

دستور مورد نظر در Nuget :
PM> install-package AsyncAwaitCtp
و اما خطا
Install failed. Rolling back...
install-package : Could not install package 'AsyncAwaitCTP 1.0'. You are trying to install this package into a project that targets '.NETPortable,Version=v4.0,Profile=Profile3', 
but the package does not contain any assembly references that are compatible with that framework. For more information, contact the package author.
At line:1 char:1
دستور بالا برای نصب AsyncAwaitCTP در Class Library تحت دات نت 4.5 استفاده می‌شه.
خلاصه بعد از یکم جستجو متوجه شدم که باید از دستور زیر برای نصب TPL توی Portable Class Library تحت دات نت 4 استفاده کنم.
PM > install-Package Microsoft-BCL-Async -Pre
که بازم با خطای زیر مواجه شدم.
Install failed. Rolling back...
install-package : Could not install package 'Microsoft.Bcl 1.0.16-rc'. You are trying to install this package into a project that targets 
'.NETPortable,Version=v4.0,Profile=Profile3', but the package does not contain any assembly references that are compatible with that framework. For more information, contact the 
package author.
At line:1 char:1
+ install-package Microsoft.BCL.Async -Pre
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : NotSpecified: (:) [Install-Package], InvalidOperationException
    + FullyQualifiedErrorId : NuGetCmdletUnhandledException,NuGet.PowerShell.Commands.InstallPackageCommand
از اونجا که از دستور بالا مطمئن بودم و می‌دونستم که باید درست کار کنه فهمیدم اشکال کار از یه جای دیگه است. خلاصه بعد از یه جستجوی 25 دقیقه ای متوجه شدم که
Nuget نصب شده روی سیستم من Update نیست. برای همین به روش زیر عمل کردم .
از منوی Tools گزینه Extension And Updates رو انتخاب کردم. بعد از صفحه مورد نظر گزینه Updates روز از منوی سمت چپ انتخاب کردم و درنهایت گزینه Nuget Package Manager. مثل شکل زیر:


بعد از اتمام عملیات Update دوباره دستورات مورد نظر رو وارد کردم که به خوبی عملیات نصب CTP به اتمام رسید.





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


پیوست و بازیابی فایل‌های باینری

امکان پیوست فایل‌های باینری نیز به اسناد RavenDB وجود دارد. برای مثال به کلاس سؤالات قسمت اول این سری، خاصیت FileId را اضافه کنید:
public class Question
{
    public string FileId { set; get; }
}
اکنون برای ذخیره فایلی و همچنین انتساب آن به یک سند، به روش ذیل باید عمل کرد:
            using (var store = new DocumentStore
            {
                Url = "http://localhost:8080"
            }.Initialize())
            {
                using (var session = store.OpenSession())
                {
                    store.DatabaseCommands.PutAttachment(key: "file/1",
                                                         etag: null,
                                                         data: System.IO.File.OpenRead(@"D:\Prog\packages.config"),
                                                         metadata: new RavenJObject
                                                         { 
                                                            { "Description", "توضیحات فایل" }
                                                         });
                    var question = new Question
                    {
                        By = "users/Vahid",
                        Title = "Raven Intro",
                        Content = "Test....",
                        FileId = "file/1"
                    };
                    session.Store(question);

                    session.SaveChanges();
                }
            }
کار متد store.DatabaseCommands.PutAttachment، ارسال اطلاعات یک استریم به سرور RavenDB است که تحت کلید مشخصی ذخیره خواهد شد. متد استاندارد System.IO.File.OpenRead روش مناسبی است برای دریافت استریم‌ها و ارسال آن به متد PutAttachment. در قسمت metadata این فایل، توسط شیء RavenJObject، یک دیکشنری از key-valueها را جهت درج اطلاعات اضافی مرتبط با هر فایل می‌توان مقدار دهی کرد. پس از آن، جهت انتساب این فایل ارسال شده به یک سند، تنها کافی است کلید آن‌را به خاصیت FileId انتساب دهیم.
در این حالت اگر به خروجی دیباگ سرور نیز دقت کنیم، مسیر ذخیره سازی این نوع فایل‌ها مشخص می‌شود:
 Request # 2: PUT   - 200 ms - <system> - 201 - /static/file/1
بازیابی فایل‌های همراه با اسناد نیز بسیار ساده است:
            using (var store = new DocumentStore
            {
                Url = "http://localhost:8080"
            }.Initialize())
            {
                using (var session = store.OpenSession())
                {
                    var question = session.Load<Question>("questions/97");
                    var file1 = store.DatabaseCommands.GetAttachment(question.FileId);
                    Console.WriteLine(file1.Size);
                }
            }
فقط کافی است سند را یکبار Load کرده و سپس از متد store.DatabaseCommands.GetAttachment برای دستیابی به فایل پیوست شده استفاده نمائیم.


وصله کردن اسناد

سند سؤالات قسمت اول و پاسخ‌های آن، همگی داخل یک سند هستند. اکنون برای اضافه کردن یک آیتم به این لیست، یک راه، واکشی کل آن سند است و سپس افزودن یک آیتم جدید به لیست پاسخ‌ها و یا در این حالت، جهت کاهش ترافیک سرور و سریعتر شدن کار، RavenDB مفهوم Patching یا وصله کردن اسناد را ارائه داده است. در این روش بدون واکشی کل سند، می‌توان قسمتی از سند را وصله کرد و تغییر داد.
            using (var store = new DocumentStore
            {
                Url = "http://localhost:8080"
            }.Initialize())
            {
                using (var session = store.OpenSession())
                {
                    store.DatabaseCommands.Patch(key: "questions/97",
                                                 patches: new[]
                                                          {
                                                             new PatchRequest
                                                             {
                                                                Type = PatchCommandType.Add,
                                                                Name = "Answers",
                                                                Value = RavenJObject.FromObject(new Answer{ By= "users/Vahid", Content="data..."})
                                                             }
                                                          });
                }
            }
برای وصله کردن اسناد از متد store.DatabaseCommands.Patch استفاده می‌شود. در اینجا ابتدا Id سند مورد نظر مشخص شده و سپس آرایه‌ای از تغییرات لازم را به صورت اشیاء PatchRequest ارائه می‌دهیم. در هر PatchRequest، خاصیت Type مشخص می‌کند که حین عملیات وصله کردن چه کاری باید صورت گیرد؛ برای مثال اطلاعات ارسالی اضافه شوند یا ویرایش و امثال آن. خاصیت Name، نام خاصیت در حال تغییر را مشخص می‌کند. برای مثال در اینجا می‌خواهیم به مجموعه پاسخ‌های یک سند، آیتم جدیدی را اضافه کنیم. خاصیت Value، مقدار جدید را دریافت خواهد کرد. این مقدار باید با فرمت JSON تنظیم شود؛ به همین جهت از متد توکار RavenJObject.FromObject برای اینکار استفاده شده است.


افزونه‌های RavenDB

قابلیت‌های ذکر شده فوق جهت کار با اسناد به صورت توکار در RavenDB مهیا هستند. این سیستم افزونه پذیر است و تاکنون افزونه‌های متعددی برای آن تهیه شده‌اند که در اینجا به آن‌ها Bundles گفته می‌شوند. برای استفاده از آن‌ها تنها کافی است فایل DLL مرتبط را درون پوشه Plugins سرور، کپی کنیم. دریافت آن‌ها نیز از طریق NuGet پشتیبانی می‌شود؛ و یا سورس آن‌ها را دریافت کرده و کامپایل کنید. در ادامه تعدادی از این افزونه‌ها را بررسی خواهیم کرد.


حذف آبشاری اسناد

 PM> Install-Package RavenDB.Bundles.CascadeDelete -Pre
فایل افزونه حذف آبشاری اسناد را از طریق دستور نیوگت فوق می‌توان دریافت کرد. سپس فایل Raven.Bundles.CascadeDelete.dl دریافتی را درون پوشه plugins کنار فایل exe سرور RavenDB کپی کنید تا قابل استفاده شود.
استفاده مهم این افزونه، حذف پیوست‌های باینری اسناد و یا حذف اسناد مرتبط با یک سند، پس از حذف سند اصلی است (که به صورت پیش فرض انجام نمی‌شود).
یک مثال:
var comment = new Comment
{
   PostId = post.Id
};
session.Store(comment);

session.Advanced.GetMetadataFor(post)["Raven-Cascade-Delete-Documents"] = RavenJToken.FromObject(new[] { comment.Id });
session.Advanced.GetMetadataFor(post)["Raven-Cascade-Delete-Attachments"] =  RavenJToken.FromObject(new[] { "picture/1" });

session.SaveChanges();
برای استفاده از آن باید از متد session.Advanced.GetMetadataFor استفاده کرد. در اینجا شیء post که دارای تعدادی کامنت است، مشخص می‌شود. سپس با مشخص سازی Raven-Cascade-Delete-Documents و ذکر Id کامنت‌های مرتبطی که باید حذف شوند، تمام این اسناد با هم پس از حذف post، حذف خواهند شد. همچنین دستور Raven-Cascade-Delete-Attachments سبب حذف فایل‌های مشخص شده با Id مرتبط با یک سند، می‌گردد.


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

 PM> Install-Package RavenDB.Bundles.Versioning
فایل افزونه Versioning اسناد را از طریق دستور نیوگت فوق می‌توان دریافت کرد. سپس فایل dll دریافتی را درون پوشه plugins کنار فایل exe سرور RavenDB کپی کنید تا قابل استفاده شود. فایل Raven.Bundles.Versioning.dll باید در پوشه افزونه‌ها کپی شود و فایل Raven.Client.Versioning.dll به برنامه ما ارجاع داده خواهد شد.
با استفاده از قابلیت document versioning می‌توان تغییرات اسناد را در طول زمان، ردیابی کرد؛ همچنین حذف یک سند، این سابقه را از بین نخواهد برد.
 تنظیمات اولیه آن به این صورت است که توسط شیء VersioningConfiguration به سشن جاری اعلام می‌کنیم که چند نگارش از اسناد را ذخیره کند. اگر Exclude آن به true تنظیم شود، اینکار صورت نخواهد گرفت.
session.Store(new VersioningConfiguration
{
  Exclude = false,
  Id = "Raven/Versioning/DefaultConfiguration",
  MaxRevisions = 5
});
تنظیم Id به Raven/Versioning/DefaultConfiguration، سبب خواهد شد تا VersioningConfiguration فوق به تمام اسناد اعمال شود. اگر نیاز است برای مثال تنها به BlogPosts اعمال شود، این Id را باید به Raven/Versioning/BlogPosts تنظیم کرد.
بازیابی نگارش‌های مختلف یک سند، صرفا از طریق متد Load میسر است و در اینجا شماره Id نگارش به انتهای Id سند اضافه می‌شود. برای مثال "blogposts/1/revisions/1" به نگارش یک مطلب شماره یک اشاره می‌کند.
برای بدست آوردن سه نگارش آخر یک سند باید از متد ذیل استفاده کرد:
 var lastThreeVersions = session.Advanced.GetRevisionsFor<BlogPost>(post.Id, 0, 3);
مطالب
قابلیت های جدید VisualStudio.NET 2012 - قسمت یکم
شاید خیلی از برنامه نویسان با نظر من هم عقیده باشند، Visual Studio.NET بهترین ابزار و IDE جهت توسعه نرم افزار است. در این سری از مطالب قصد داریم نگاهی اجمالی به قابلیت‌های جدید VS.NET 2012 بیاندازیم.

پنجره New Project:
شاید بارزترین تغییراتی که در این پنجره به چشم می‌خورد اضافه شدن Template‌های جدید باشد. البته نباید از ظاهر گرافیکی به سبک Metro چشم پوشی کرد. یکی از این Template‌ها Portable Class Library است. توسط این گرینه می‌توان dll‌های قابل استفاده در Windows، Windows Phone،  Silverlight و البته  XBox 360 ایجاد کرد.
  
 
 
Template جدید دیگری که در VS.NET 2012 اضافه شده است گروه مربوط به Visual Studio Light Switch است. توسط این گزینه امکان ایجاد برنامه‌های Light Switch، بدون نیاز به نصب Visual Studio Light Switch بصورت جداگانه، فراهم است و جهت توسعه این دسته از برنامه‌ها می‌توانید از VS.NET 2012 استفاده کنید.
 


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

نظرات مطالب
تفاوت Desktop Application با Web Application
بله، منظور روش‌های ارائه شده مبتنی بر پلتفرم Xamarin است، البته در نظر بگیرید این کار بدون کمک‌های فنی ارائه شده توسط مایکروسافت و همچنین رفع مشکل لایسنس Portable Class Library‌ها و ... از سوی مایکروسافت امکانپذیر نبود.
مایکروسافت بنظر قصد پشتیبانی فنی و مالی و در نهایت خرید Xamarin رو داره، و بنظر نمی‌آد که بخواد این مسیر رو از نو پیش بره، چون واقعا کار زیادی می‌بره
اشتراک‌ها
نگاهی به DevExpress ORM مخصوص NET Core 2.0.

In this webinar, we will show the benefits of using DevExpress Object-Relational Mapping Library - the eXpress Persistent Objects - with .NET Core 2. The presentation will quickly cover the basics for those new to DevExpress products, and will show how you can use our ORM to manage data in ASP.NET Core or Xamarin apps. 

نگاهی به DevExpress ORM مخصوص NET Core 2.0.
مطالب دوره‌ها
نگاهی به اجزای سیستم راهبری بوت استرپ 3
در مطلب «نگاهی به اجزای تعاملی Twitter Bootstrap» مباحث سیستم راهبری بوت استرپ 2 بررسی شدند. در ادامه قصد داریم، نکات جدیدی را در اینباره خصوصا جهت ارتقاء به بوت استرپ 3، بررسی کنیم.


تعیین موقعیت کاربر در صفحه به کمک breadcrumbs در Bootstrap

در مورد قسمت breadcrumb، مطالب مانند قبل و پیشنیاز ذکر شده است. با این تفاوت که بهتر است بجای ul از ol استفاده شود؛ چون ترتیب این عناصر مهم است. ol به معنای ordered list می‌باشد:
            <ol class="breadcrumb">
                <li><a href="#">خانه</a></li>
                <li><a href="#">خدمات</a></li>
                <li class="active">محصولات</li>
            </ol>


یک سؤال: اگر نخواهیم این خطوط مورب ظاهر شوند و برای مثال علاقمند باشیم تا از گلیف آیکن‌های معرفی شده در قسمت قبل استفاده کنیم، چه باید کرد؟
برای این منظور نیاز است با نحوه رندر خطوط مورب در بوت استرپ آشنا شویم. بنابراین فایل bootstrap-rtl.css را گشوده و چند سطر ذیل را جستجو کنید:
.breadcrumb > li + li:before {
  content: "/\00a0";
  padding: 0 5px;
  color: #cccccc;
}
همانطور که ملاحظه می‌کنید، تفسیر عبارت ذکر شده در قسمت content سبب نمایش این خط مورب است. برای حذف آن، به فایل custom.css پروژه مراجعه و تعاریف ذیل را اضافه خواهیم کرد (این فایل همانطور که در قسمت اول ذکر شد، باید پس از ذکر لینک فایل CSS اصلی بوت استرپ، تعریف شود):
.breadcrumb > li + li:before {
  content: none;
}
به این ترتیب خطوط مورب breadcrumb حذف می‌شوند. اکنون برای افزودن گلیف آیکن‌ها به صورت زیر می‌توان عمل کرد:
            <ol class="breadcrumb">
                <li><a href="#">خانه</a> <span class="glyphicon glyphicon-circle-arrow-left"></span></li>
                <li><a href="#">خدمات</a> <span class="glyphicon glyphicon-circle-arrow-left"></span></li>
                <li class="active">محصولات</li>
            </ol>


اگر از رنگ گلیف آیکن‌‌های نمایش داده شده راضی نیستید، آن‌ها را نیز می‌توانید در فایل CSS سفارشی خود تغییر دهید. برای مثال:
.glyphicon {
color: #cdae51;
}



تعریف برگه‌ها در Twitter Bootstrap
در مورد تعریف برگه‌ها، بوت استرپ 3 با نگارش 2 آن، تفاوتی ندارد و تمام نکات مطلب «نگاهی به اجزای تعاملی Twitter Bootstrap» در اینجا نیز صادق هستند. یک ul باید تعریف شود و سپس برای نمونه کلاس‌های nav nav-tabs را به آن‌ها اضافه خواهیم کرد تا به شکل tab به نظر برسند. برگه فعال نیز با کلاس active مشخص می‌شود.
یک نکته جدید: در بوت استرپ 3 می‌توان یک برگه را کاملا در عرض صفحه کشید و امتداد داد:
                <ul class="nav nav-pills nav-justified">
                    <li><a href="#">Home</a></li>
                    <li><a href="#">About</a></li>
                    <li class="active"><a href="#">Services</a></li>
                    <li><a href="#">Photo Gallery</a></li>
                    <li><a href="#">Contact</a></li>
                </ul>
با اضافه کردن nav-justified، بجای شکل زیر


به تصویر ذیل خواهیم رسید که در آن tab، در امتداد صفحه کشیده شده است:




تعریف navbar در بوت استرپ 3

اصول کلی navbar بوت استرپ 3 همانند بوت استرپ 2 است؛ با چند تفاوت کوچک:
- کلاس btn-navbar بوت استرپ 2 به کلاس navbar-btn در بوت استرپ 3 تغییر نام یافته است.
- کلاس navbar-inner بوت استرپ 2 کلا حذف شده است.
- کلاس‌های nav-list به کلاس‌های list-group تغییر نام یافته‌اند.
- کلاس brand با navbar-brand جایگزین شده است.
- کلاس‌های navbar-brand و navbar-toggle باید داخل المانی با کلاس navbar-header محصور شوند.
- کلاس nav باید به همراه navbar-nav باشد.
- کلاس‌های جدید navbar-default  navbar-text  navbar-btn  navbar-header اضافه شده‌اند.

یک مثال:
    <div class="container">
        <h4 class="alert alert-info">
            nav</h4>
        <div class="row">
            <nav class="navbar navbar-default navbar-inverse navbar-fixed-top" role="navigation">
                <div class="navbar-header">
                    <button type="button" class="navbar-toggle" data-toggle="collapse" data-target="#collapse">
                        <span class="sr-only">Toggle navigation</span> <span class="icon-bar"></span><span
                            class="icon-bar"></span><span class="icon-bar"></span>
                    </button>
                </div>
                <div class="collapse navbar-collapse" id="collapse">
                    <ul class="nav navbar-nav">
                        <li><a href="#">Home</a></li>
                        <li><a href="#">About</a></li>
                        <li class="active"><a href="#">Services</a></li>
                        <li><a href="#">Photo Gallery</a></li>
                        <li><a href="#">Contact</a></li>
                    </ul>
                </div>
            </nav>
        </div>
        <!-- end row -->
    </div>
    <!-- /container -->
به همراه CSS سفارشی:
 body { padding-top: 70px; }






توضیحات:
- CSS سفارشی، سبب خواهد شد تا تگ h4 بالای صفحه، زیر navbar مخفی نشده و قابل مشاهده باشد.
- کار با المان nav دارای کلاس navbar navbar-default شروع می‌شود. همچنین role=navigation نیز به این المان اضافه شده‌است. این مورد  کمکی خواهد بود به افرادی با قدرت بینایی کم که از screen readers استفاده می‌کنند.
- داخل navbar-default یک div دیگر با کلاس navbar-header اضافه شده است. این مورد قابلیت‌های واکنشگرای navbar را فراهم می‌سازد. به این ترتیب زمانیکه عرض صفحه کمتر می‌شود، مانند تصویر دوم، یک دکمه ویژه نمایش داده خواهد شد.
- هرجایی در بوت استرپ ویژگی‌های data- را ملاحظه کردید، یعنی قرار است اطلاعاتی در اختیار اجزای جاوا اسکریپتی آن قرار گیرند. برای نمونه data-target به یک div با آی دی مساوی collapse اشاره می‌کند. به این معنا که اگر در زمان کم بودن عرض صفحه، دکمه ویژه واکنشگرای navbar ظاهر شد، با کلیک بر روی آن دکمه، div یاد شده را نمایش بده.
- span تعریف شده با کلاس sr-only به معنای اطلاعاتی است که صرفا جهت screen readers تدارک دیده شده‌اند.


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