مسیرراه‌ها
ASP.NET MVC
              نظرات مطالب
              چرا در سازمان‌ها برنامه‌های وب جایگزین برنامه‌های دسکتاپ شده‌اند (یا می‌شوند)؟
              نه. هر کدوم جایگاه خودشون رو دارند.
              بحث من مدیریت ساده‌تر بیش از 200 کاربر و کامپیوتر در یک شبکه بود. ساده‌تر شدن به روز رسانی‌ها، مدیریت و تهیه پشتیبان از اطلاعات، دسترسی ریموت به برنامه‌ها، امکان دسترسی به برنامه از سیستم‌ عامل‌های مختلف و کلیه مواردی که ذکر شد. در اینجاها windows application نویسی مقرون به صرفه نیست.
              و گرنه نوشتن windows service یا برنامه‌های تک کاربره یا حتی چندکاربره در مقایس کم مثلا یک شرکت 5 نفره ... و امثال آن لزومی ندارد که با وب اپلیکیشن باشد.
              نظرات مطالب
              بالا بردن سرعت بارگذاری اولیه EF Code first با تعداد مدل‌های زیاد
              در آغاز برنامه (مثلا در application_start برنامه‌های وب و یا ابتدای متد Main برنامه‌های دسکتاپ): «وادار کردن EF Code first به ساخت بانک اطلاعاتی پیش از شروع به کار برنامه»
              نظرات مطالب
              MVVM و فراخوانی متدهای اشیاء View از طریق ViewModel
              علتش رو اینجا توضیح دادم: (^).
              ASP.NET Webforms از نظر مایکروسافت در رده Done قرار دارد. فقط این اواخر کمی «ماله کشی و صافکاری» روی آن انجام شده و خواهد شد.
              ضمنا الگوی MVVM‌ به درد ASP.NET‌ نمی‌خوره. نیاز به سیستمی State full داره که سیستم‌های وب در این رده قرار نمی‌گیرند. ASP.NET اساسا Stateless است. به همین جهت در پروژه‌های وب تمایل به MVC بیشتر است تا هر الگوی دیگری.
              همچنین یکی از اعضای تیم ASP.NET MVC ، اخیرا فریم ورک MVVM‌  JavaScript ایی را به نام knockoutjs ارائه داده ((^)). علت ارائه برای جاوا اسکریپت هم دقیقا به State full آن بر می‌گردد، زمانیکه داخل مرورگر کاربر اجرا می‌شود. مانند Silverlight که آن هم State full است.
              مطالب
              پیاده سازی PWA در Angular
              امروزه طراحی اپلیکیشن‌های موبایل بخش زیادی از جامعه را در برگرفته است و روز به روز در حال توسعه میباشند. موازی با رشد روز افزون و نیاز بیشتر به این اپلیکیشن‌ها فریمورک‌های زیادی نیز  ابداع شده اند. از جمله این فریم ورک‌ها می‌توان به موارد زیر اشاره کرد:

              Ionic  , react native , flutter , xamarin ….

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

               
              مزایای نوشتن یک اپلیکیشن با  فریم ورک‌ها:

              1-  نوشتن کد به مراتب آسانتر است.
              ۲- چون اکثر فریم ورک‌ها، فریم ورک‌های جاوا اسکریپتی هستند، سرعت بالایی هنگام run کردن برنامه دارند ولی در build آخر و خروجی نهایی بر روی پلتفرم، این سرعت کندتر می‌شود.
              ۳- cossplatform بودن. با طراحی یک اپلیکیشن برای یک پلتفرم می‌توان همزمان برای پلتفرم‌های دیگر خروجی گرفت.


              معایب:

              ۱- برنامه نویس را محدود  میکند.
              ۲- سرعت اجرای پایینی دارد.
              ۳- حجم برنامه به مراتب بالاتر میباشد.
              ۴- از منابع سخت افزاری بیشتری استفاده می‌کند.

              اگر شما هم میخواهید از فریم ورک‌ها برای طراحی اپلیکیشن استفاده کنید در اینجا  می‌توانید اطلاعات بیشتری را درباره هر کدام از فریم ورک‌ها ببینید. هر کدام از این فریم ورک‌ها دارای مزایا معایب و همچنین رزومه کاری خوب می‌باشند. بیشتر فریم ورک‌های بالا در رندر آخر، همان کد native را تولید می‌کنند؛ مثلا اگر برنامه‌ای را با react native بنویسید، میتوانید همان برنامه را بر روی اندروید استودیو و کد native بالا بیارید. توضیحات  بالا مقایسه فریم ورک‌های Cross Platform با زبان‌های native بود. اما در این مقاله قصد آشنایی با تکنولوژی جدیدی را داریم که شما را قادر می‌سازد یک وب اپلیکیشن را با آن طراحی کنید.


               pwa چیست؟

              pwa مخفف Progressive Web Apps است و یک تکنولوژی برای طراحی وب اپلیکیشن‌های تحت مرورگر میباشد. شما با pwa میتوانید اپلیکیشن خود را بر روی پلتفرم‌های مختلفی اجرا کنید، طوری که کاربران متوجه نشوند با یک صفحه‌ی وبی دارند کار میکنند. شاید شما هم فکر کنید این کار را هم میتوان با html ,css و responsive کردن صفحه انجام داد! ولی اگر بخواهید کاربر متوجه استفاده‌ی از یک صفحه‌ی وبی نشود، باید حتما از pwa استفاده کنید! برای مثال یک صفحه‌ی وبی معمولی حتما باید در بستر اینترنت اجرا شود، ولی با pwa با یکبار وصل شدن به اینترنت و کش کردن داده‌ها، برای بار دوم دیگر نیازی به اینترنت ندارد و میتواند به صورت offline  کار کند. شما حتی با pwa می‌توانید اپلیکیشن را در background اجرا کنید و notification ارسال کنید.


              مزیت pwa

              ۱- یکی از مزیت‌های مهم pwa، حالت offline آن میباشد که حتی با قطع اینترنت، شما میتوانید همچنان با اپلیکیشن کار کنید.
              ۲- با توجه به اینکه شما در حقیقت با یک صفحه‌ی وبی کار میکنید، دیگر نیازی به دانلود و نصب ندارید.
              ۳- امکان به‌روز رسانی کردن، بدون اعلام کردن نسخه جدید.
              ۴- از سرعت بسیار زیادی برخوردار است.
              ۵- چون pwa از پروتکل https استفاده می‌کند، دارای امنیت بالایی میباشد.


              معایب

              ۱- محدود به مرورگر می‌باشد.
              ۲- هرچند امروزه اکثر مرورگر‌ها pwa را پشتیبانی میکنند، ولی در بعضی از مرورگر‌ها و مرورگر‌های با ورژن پایین، pwa پشتیبانی نمیشود.
              3- نمیتوان یک برنامه‌ی مبتنی بر os را نوشت و محدود به مرورگر میباشد


              چند نکته درباره pwa

              1- برای pwa  لزومی ندارد حتما از فریم ورک‌های spa استفاده کنید. شما از هر فریم ورک Client Side ای می‌توانید استفاده کنید.
              ۲- چون صفحات شما در پلتفرم‌های مختلف و با صفحه نمایش‌های مختلفی اجرا می‌شود، باید صفحات به صورت کاملا responsive شده طراحی شوند.
              ۳- باید از پروتکل https استفاده کنید.

              ما در این مقاله از فریم ورک angular  استفاده  خواهیم کرد.

              قبل از شروع، با شیوه کار pwa آشنا خواهیم شد. یکی از قسمت‌های مهم  Service Worker ،pwa میباشد که از جمله کش کردن، notification فرستادن و اجرای پردازش‌ها در پس زمینه را بر عهده دارد.


              با توجه به شکل بالا، Service Worker مانند یک لایه‌ی نرم افزاری مابین کلاینت و سرور قرار دارد که درخواست‌های داده شده از کلاینت را در صورت اتصال به اینترنت، ارسال کرده و مجددا response را برگشت میدهد‌. اگر به هر دلیلی اینترنت قطع باشد، درخواست به صورت آفلاین به کش مرورگر که توسط proxy ساخته شده است، فرستاده میشود و response را برگشت میدهد.


              چند نکته  در رابطه با Service Worker

              - نباید برای  نگهداری داده global از Service Worker استفاد کرد. برای استفاده از داده‌های Global میتوان از Local Storage یا IndexedDB استفاده کرد.
              - service worker  به dom دسترسی ندارند.


               سناریو

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


               قبل از شروع لازم است به چند نکته زیر توجه کرد

              1-  سرویس crud را به صورت کامل در پروژه قرار خواهیم داد، ولی چون از حوصله‌ی مقاله خارج است، فقط ثبت کاربران و نمایش کاربران را پیاده سازی خواهیم کرد.
              2 - هر اپلیکیشنی قطعا نیاز به یک وب سرویس دارد که واسط بین دیتابیس و اپلیکیشن باشد. ولی ما چون در این مثال به عنوان front end کار قصد طراحی  اپلیکیشن را داریم، برای حذف back end از firebase استفاده خواهیم کرد و مستقیما از انگولار به دیتابیس firebase کوئری خواهیم زد.


               شروع به کار

              پیش نیاز‌های یک پروژه‌ی انگیولاری را بر روی سیستم خود فراهم کنید. ما در این مثال از یک template آماده انگیولاری استفاده خواهیم کرد. پس برای اینکه با جزئیات و طراحی ui درگیر نشویم، از لینک github پروژه را دریافت کنید.
              سپس وارد root پروژه شوید و با دستور زیر پکیج‌های پروژه را نصب کنید:
               npm install
              پس از نصب پکیج‌ها، با دستور ng serve، پروژه را اجرا کنید.

              پس از اجرا باید خروجی بالا را داشته باشید. می‌خواهیم یکی از قابلیت‌های pwa را بررسی کنیم. بر روی صفحه کلیک راست کرده و وارد inspect شوید. وارد تب Application  شوید و Service Worker را انتخاب کنید.
               


              قبل از اینکه کاری را انجام دهید، چند بار صفحه را refresh کنید! صفحه بدون هیچ تغییری refresh میشود. اینبار گزینه‌ی offline را فعال کنید و مجددا صفحه را refresh کنید.
              این بار صفحه No internet به معنی قطع بودن اینترنت نمایش داده میشود و شما دیگر نمی‌توانید بر روی اپلیکیشن خود فعالیتی داشته باشید! 


              نصب pwa  بر روی پروژه

              برای اضافه کردن pwa به پروژه وارد ریشه‌ی پروژه شوید و دستور زیر را وارد کنید:
               ng add @angular/PWA
              پس از  اجرای دستور بالا، تغییراتی در پروژه لحاظ میشود از جمله در فایل‌هایindex.html,app-module,angular.json، همچنین یک پوشه‌ی جدید به نام icons در assets و دو فایل جیسونی زیر به روت پروژه اضافه شده‌اند:
               Manifest.json : اگر محتویات فایل را مشاهده کرده باشید، شامل تنظیمات فنی وب اپلیکیشن می‌باشد؛ از جمله Home Screen Icon و نام وب اپلیکیشن و سایر تنظیمات دیگر.
               Nsgw-config.json : این فایل نسبت به فایل manifest فنی‌تر میباشد و بیشتر به کانفیگ مد آفلاین و کش کردن مرتبط میشود. در ادامه با این فایل بیشتر کار داریم.

              بعد از نصب pwa  بر روی پروژه، همه تنظیمات به صورت خودکار انجام می‌شود. البته می‌توانید تنظیمات مربوط به کش کردن داده‌ها را به صورت پیشرفته‌تر کانفیگ کنید.


                اجرا کردن وب اپلیکیشن

               برای اجرا کردن و نمایش خروجی از وب اپلیکیشن، ابتدا باید از پروژه build گرفت. با استفاده از دستور زیر از پروژه خود build بگیرید:
               ng build -- prod
              سپس  با دستور زیر وارد پوشه‌ای که فایل‌های Build  شده در آن قرار دارند، شوید:
               cd dist/Web Application  Pwa
              بعد با دستور زیر برنامه را اجرا کنید:
               Http-server -o
              اگر چنانچه با دستور بالا به خطا برخوردید، با دستور زیر پکیج npm آن را نصب کنید:
               npm i http-server
              اگر تا به اینجای کار درست پیش رفته باشید، پروژه را بدون هیچ تغییری مشاهده خواهیم کرد. inspect گرفته و وارد تب Application شوید. اینبار گزینه‌ی offline را فعال کنید و مجددا صفحه را refresh کنید! اینبار برنامه بدون هیچ مشکلی کار میکند. حتی شما میتوانید در کنسول، برنامه را به صورت کامل stop کنید.


              برسی فایل Nsgw-config.json 

              وارد فایل Nsgw-config.json شوید: 

              "$schema": "./node_modules/@angular/service-worker/config/schema.json",
                "index": "/index.html",
                "assetGroups": [
                  {
                    "name": "app",
                    "installMode": "prefetch",
                    "resources": {
                      "files": [
                        "/favicon.ico",
                        "/index.html",
                        "/*.css",
                        "/*.js"
                      ]
                    }
                  }, {
                    "name": "assets",
                    "installMode": "lazy",
                    "updateMode": "prefetch",
                    "resources": {
                      "files": [
                        "/assets/**",
                        "/*.(eot|svg|cur|jpg|png|webp|gif|otf|ttf|woff|woff2|ani)"
                      ]
                    }
              
                  }
                ],
                "dataGroups": [
                  {
                    "name": "api-performance",
                    "urls": [
                      "https://api/**"
                    ],
                    "cacheConfig": {
                      "strategy": "performance",
                      "maxSize": 100,
                      "maxAge": "3d"
                    }
                  }
                ]
              }
               این فایل مربوط به کش کردن داده‌ها میباشند و میتواند شامل چند object زیر باشد. مهمترین آنها را بررسی خواهیم کرد:
                ۱- assetGroups : کش کردن اطلاعات مربوط به اپلیکیشن
                ۲- Index : کش کردن  فایل مربوط به index.html
                ۳-  assetGroups : کش کردن فایل‌های مربوط به asset، شامل فایل‌های js، css  و  غیره
                ۴- dataGroups : این object مربوط به وقتی است که برنامه در حال اجرا است. میتوان داده‌های در حال اجرای اپلیکیشن را کش کرد. داده‌ی در حال اجرا میتواند شامل فراخوانی apiها باشد. برای مثال فرض کنید شما در حالت کار کردن online با اپلیکیشن، لیستی از اسامی کاربران را از api گرفته و نمایش میدهید. وقتی دفعه‌ی بعد در حالت offline  اپلیکیشن را باز کنیم، اگر api را کش کرده باشیم، اپلیکیشن داده‌ها را از کش فراخوانی میکند. این عمل درباره post کردن داده‌ها هم صدق میکند.

              خود dataGroups شامل چند object زیر میباشد:
                ۱- name :  یک نام انتخابی برای Groups  میباشد.
               ۲- urls  : شامل آرایه‌ای از آدرس‌ها میباشد. میتوان آدرس یک دومین را همراه با کل apiها به صورت زیر کش کرد:
              "https://api/**"
              ۳- cacheConfig  : که شامل
                ۱- maxSize  : حداکثر تعداد کش‌های مربوط به Groups .
                ۲- maxAge  : حداکثر  lifetime مربوط به کش.
                ۳- strategy  : که میتواند یکی از مقادیر freshness به معنی Network-First یا performance  به معنی Cache-First باشد.


               پیاده سازی پیغام نمایش به‌روزرسانی جدید وب اپلیکیشن

              در اپلیکیشن‌های native  وقتی به‌روزرسانی جدیدی برای app اعلام میشود، در فروشگاهای اینترنتی پیغامی مبنی بر به‌روزرسانی جدید app برای کاربران ارسال میشود که کاربران میتوانند app خود را به‌روزرسانی کنند. ولی در pwa تنها با یک رفرش صفحه میتوان اپلیکیشن را به جدیدترین امکانات به‌روزرسانی کرد! برای اینکه بتوانیم با هر تغییر، پیغامی را جهت به‌روزرسانی نسخه یا هر  پیغامی دیگری را نمایش دهیم، از کد زیر استفاده میکنم:
              if(this.swUpdate.isEnabled)
                  {
                    this.swUpdate.available.subscribe(()=> {
              
                      if(confirm("New Version available.Load New Version?")){
                        window.location.reload();
                      }
                    })
                  }


              وصل شدن به دیتابیس

              برای اینکه بتوانیم یک وب اپلیکیشن کامل را طراحی کنیم، قطعا نیاز به دیتابیس داریم. برای دیتابیس از firebase استفاده میکنیم. قبل از شروع، وارد سایت firebase  شوید. پس از لاگین، بر روی Add Project کلیک کنید. بعد از انتخاب نام مناسب، create Project را انتخاب کنید. ساختار دیتابیس‌های firebase  شبیه nosqlها می‌باشد و بر پایه‌ی json کار میکنند. پس از ساخت پروژه و دریافت کد جاواسکریپتی زیر شروع به طراحی فیلد‌های دیتابیس خواهیم کرد.


              در منوی سمت چپ، بر روی database کلیک کنید و یک دیتابیس را در حالت test mode  ایجاد نماید. سپس یک collection را به نام user ایجاد کرده و فیلد‌های زیر را به آن اضافه کنید:
              Age :number
              Fullname :string
              Mobile : string
              مرحله‌ی بعد، config پروژه‌ی انگیولاری میباشد. وارد  vscode شوید و با دستور زیر پکیج firebase را اضافه کنید:
                npm install --save firebase @angular/fire
              سپس وارد appmodule شوید و آن‌را به صورت زیر کانفیگ کنید:

              @NgModule({
                declarations: [AppComponent, RegisterComponent,AboutComponent, UserListComponent],
                imports: [
                  BrowserModule,
                  FormsModule,
                  HttpClientModule,
                  HttpClientModule,
                  SharedModule,
                  AppRoutingModule,
                  AngularFireModule.initializeApp(environmentFirebase.firebase),
                  AngularFireDatabaseModule,
                  ServiceWorkerModule.register('ngsw-worker.js', { enabled: environment.production }),
                ],
                providers: [FirebaseService],
                bootstrap: [AppComponent]
              })
              export class AppModule {}
              خط ۱۰ مربوط به pwa است که هنگام نصب pwa اضافه شده‌است و خط ۸ و مربوط به apiKey فایربیس میباشد. می‌شود گفت environmentFirebase.firebase شبیه  connection string می‌باشد که به صورت زیر کانفیگ شده است:
              export const environment ={
                 production: true,
                 firebase: {
                   apiKey: "AIz×××××××××××××××××××××××××××××××××8",
                   authDomain: "pwaangular-6c041.firebaseapp.com",
                   databaseURL: "https://pwaangular-6c041.firebaseio.com",
                   projectId: "pwaangular-6c041",
                   storageBucket: "pwaangular-6c041.appspot.com",
                   messagingSenderId: "545522081966"
                 }
              
              }

              FirebaseService در قسمت providers مربوط به سرویس crud میباشد. اگر وارد فایل مربوطه شوید، چند عمل اصلی به صورت زیر در آن پیاده سازی شده است:

              import { Injectable } from '@angular/core';
              import { Observable } from 'rxjs';
              import * as firebase from 'firebase';
              import { AngularFireDatabase } from '@angular/fire/database';
              import { HttpClient } from '@angular/common/http';
              import { map } from 'rxjs/operators';
              import { ThrowStmt } from '@angular/compiler';
              @Injectable({
                providedIn: 'root'
              })
              export class FirebaseService {
              
                ref = firebase.firestore().collection('users');
                constructor(public db: AngularFireDatabase,public _http:HttpClient) { 
               
                }
              
                getUsers(): Observable<any> {
                  return new Observable((observer) => {
                    this.ref.onSnapshot((querySnapshot) => {
                      let User = [];
                      querySnapshot.forEach((doc) => {
                        let data = doc.data();
                        User.push({
                          key: doc.id,
                          fullname: data.fullname,
                          age: data.age,
                          mobile: data.mobile
                        });
                      });
                      observer.next(User);
                    });
                  });
                }
              
                getUser(id: string): Observable<any> {
                  return new Observable((observer) => {
                    this.ref.doc(id).get().then((doc) => {
                      let data = doc.data();
                      observer.next({
                        key: doc.id,
                        title: data.title,
                        description: data.description,
                        author: data.author
                      });
                    });
                  });
                }
              
                postUser(user): Observable<any> {
                  return new Observable((observer) => {
                    
                    this.ref.add(user).then((doc) => {
                      observer.next({
                        key: doc.id,
                      });
                    });
                  });
                }
              
                updateUser(id: string, data): Observable<any> {
                  return new Observable((observer) => {
                    this.ref.doc(id).set(data).then(() => {
                      observer.next();
                    });
                  });
                }
              
                deleteUser(id: string): Observable<{}> {
                  return new Observable((observer) => {
                    this.ref.doc(id).delete().then(() => {
                      observer.next();
                    });
                  });
                }
              
              getDataOnApi(){
                return this._http.get('https://site.com/api/General/Getprovince')
                .pipe(
                    map((res: Response) => {
              return res;
              
                    })
                );
              }
              
              getOnApi(){
                return  this._http.get("https://site.com/api/General/Getprovince",).pipe(
                  map((response:any) => {
                     
              return  response
                  } )
                  );
              }
              }
              اگر دقت کرده باشید، خیلی شبیه به کد نویسی سمت سرور میباشد.

              با دستورات زیر میتوانید مجددا پروژه را اجرا کنید:
              ng build --prod
              cd dist/Pwa-WepApp
              Http-server -o


              تست وب اپلیکیشن بر روی پلتفرم‌های مختلف

              برای اینکه بتوانیم خروجی وب اپلیکیشن را بر روی پلتفرم‌های مختلفی تست کنیم، میتوانیم آن را آپلود کرده و مثل یک سایت اینترنتی، با وارد کردن دومین، وارده پروژه شد. ولی کم هزینه‌ترین راه، استفاده از ابزار ngrok میباشد. میتوانید توسط این مقاله پروژه خودتان در لوکال بر روی https سوار کنید.

              نکته! توجه کنید apiهای مربوط به firebase را نمیتوان کش کرد.


              کد‌های مربوط به این قسمت را میتوانید از این repository دریافت کنید .
              نظرات مطالب
              بررسی روش آپلود فایل‌ها در ASP.NET Core
              یک برنامه‌ی React، یک برنامه‌ی سمت کلاینت هست؛ یعنی بر روی مرورگر کاربر اجرا می‌شود و نه بر روی سرور و ما فایل را به سمت سرور ارسال می‌کنیم. مطابق مطلب «آپلود فایل‌ها توسط برنامه‌های React به یک سرور ASP.NET Core به همراه نمایش درصد پیشرفت» می‌توان با استفاده از یک کتابخانه‌ی ثالث مانند axios، این فایل را به سمت سرور ASP.NET Core ارسال کرد و ذخیره کرد. امکان یکی کردن پورت برنامه‌های React و ASP.NET Core هم در زمان توسعه وجود دارد: «روش یکی کردن پروژه‌های React و ASP.NET Core». اگر پورت‌ها یکی نباشند، نیاز به تنظیمات CORS هست.
              مطالب
              SignalR
              چند وقتی هست که در کنار بدنه اصلی دات‌نت فریم‌ورک چندین کتابخونه به صورت متن‌باز در حال توسعه هستند. این مورد در ASP.NET بیشتر فعاله و مثلا دو کتابخونه SignalR و WebApi توسط خود مایکروسافت توسعه داده میشه.
              SignalR همونطور که در سایت بسیار خلاصه و مفید یک صفحه‌ای! خودش توضیح داده شده (^) یک کتابخونه برای توسعه برنامه‌های وب «زمان واقعی»! (real-time web) است:
              Async library for .NET to help build real-time, multi-user interactive web applications.
              برنامه‌های زمان واقعی به صورت خلاصه و ساده به‌صورت زیر تعریف میشن (^):
              The real-time web is a set of technologies and practices that enable users to receive information as soon as it is published by its authors, rather than requiring that they or their software check a source periodically for updates.
              یعنی کاربر سیستم ما بدون نیاز به ارسال درخواستی صریح! برای دریافت آخرین اطلاعات به روز شده در سرور، در برنامه کلاینتش از این تغییرات آگاه بشه. مثلا برنامه‌هایی که برای نمایش نمودارهای آماری داده‌ها استفاده میشه (بورس، قیمت ارز و طلا و ...) و یا مهمترین مثالش میتونه برنامه «چت» باشه. متاسفانه پروتوکل HTTP مورد استفاده در وب محدودیت‌هایی برای پیاده‌سازی این گونه برنامه‌ها داره. روش‌های گوناگونی برای پیاده‌سازی برنامه‌های زمان واقعی در وب وجود داره که کتابخونه SignalR فعلا از موارد زیر استفاده میکنه:
              1. تکنولوژی جدید WebSocket (^) که خوشبختانه پشتیبانی کاملی از اون در دات نت 4.5 (چهار نقطه پنج! نه چهار و نیم!) وجود داره. اما تمام مرورگرها و تمام وب سرورها از این تکنولوژی پشتیبانی نمیکنند و تنها برخی نسخه‌های جدید قابلیت استفاده از آخرین ورژن WebSocket رو دارند که میشه به کروم 16 به بالا و فایرفاکس 11 به بالا و اینترنت اکسپلورر 10 اشاره کرد (برای استفاده از این تکنولوژی در ویندوز نیاز به IIS 8.0 است که متاسفانه فقط در ویندوز 8.0 موجوده):
                Chrome 16, Firefox 11 and Internet Explorer 10 are currently the only browsers supporting the latest specification (RFC 6455).
              2.  یه روش دیگه Server-sent Events نام داره که داده‌های جدید رو به فرم رویدادهای DOM به سمت کلاینت میفرسته(^).
              3. روش دیگه‎‌ای که موجوده به Forever Frame معروفه که در این روش یک iframe مخفی درون کد html مسئول تبادل داده‌هاست. این iframe مخفی به‌صورت یک بلاک Chunked (^) به سمت کلاینت فرستاده میشه. این iframe که مسئول رندر داده‌های جدید در سمت کلاینت هست ارتباط خودش رو با سرور تا ابد! (برای همین بهش forever میگن) حفظ میکنه. هر وقت رویدادی سمت سرور رخ میده با استفاده از این روش داده‌ها به‌صورت تگ‌های script به این فریم مخفی فرستاده می‌شوند و چون مرورگرها محتوای html رو به صورت افزایشی (incrementally) رندر میکنن بنابراین این اسکریپتها به‌ترتیب زمان دریافت اجرا می‌شوند. (البته ظاهرا عبارت forever frame در صنعت عکاسی! معروف‌تره بنابراین در جستجو در زمینه این روش ممکنه کمی مشکل داشته باشین) (^).
              4. روش آخر که در کتابخونه SignalR ازش استفاده میشه long-polling نام داره. در روش polling معمولی پس از ارسال درخواست توسط کلاینت، سرور بلافاصله نتیجه حاصله رو به سمت کلاینت میفرسته و ارتباط قطع میشه. بنابراین برای داده‌های جدید درخواست جدیدی باید به سمت سرور فرستاده بشه که تکرار این روش باعث افزایش شدید بار بر روی سرور و کاهش کارآمدی اون می‌شه. اما در روش long-polling پس از برقراری ارتباط کلاینت با سرور این ارتباط تا مدت زمان معینی (که توسط یه مقدار تایم اوت مشخص میشه و مقدار پیش‌فرضش 2 دقیقه است) برقرار میمونه. بنابراین کلاینت میتونه بدون ایجاد مشکلی در کارایی، داده‌های جدید رو از سرور دریافت کنه. به این روش در برنامه‌نویسی وب اصطلاحا برنامه‌نویسی کامت (Comet Programming) میگن (^ ^).
              (البته روش‌های دیگری هم برای پیاده‌سازی برنامه‌های زمان اجرا وجود داره مثل کتابخونه node.js که جستجوی بیشتر به خوانندگان واگذار میشه)
              SignalR برای برقراری ارتباط ابتدا بررسی میکنه که آیا هر دو سمت سرور و کلاینت قابلیت پشتیبانی از WebSocket رو دارند. در غیراینصورت سراغ روش Server-sent Events میره. اگر باز هم موفق نشد سعی به برقراری ارتباط با روش forever frame میکنه و اگر باز هم موفق نشد در آخر سراغ long-polling میره.
              با استفاده از SignalR شما میتونین از سرور، متدهایی رو در سمت کلاینت فراخونی کنین. یعنی درواقع با استفاده از کدهای سی شارپ میشه متدهای جاوااسکریپت سمت کلاینت رو صدا زد!
              بطور خلاصه در این کتابخونه دو کلاس پایه وجود داره:
              1. کلاس سطح پایین PersistentConnection
              2. کلاس سطح بالای Hub
              علت این نامگذاری به این دلیله که کلاس سطح پایین پیاده‌سازی پیچیده‌تر و تنظیمات بیشتری نیاز داره اما امکانات بیشتری هم در اختیار برنامه‌نویس قرار می‌ده.
              خوب پس از این مقدمه نسبتا طولانی برای دیدن یک مثال ساده میتونین با استفاده از نوگت (Nuget) مثال زیر رو نصب و اجرا کنین (اگه تا حالا از نوگت استفاده نکردین قویا پیشنهاد میکنم که کار رو با دریافتش از اینجا آغاز کنین) :
              PM> Install-Package SignalR.Sample
              پس از کامل شدن نصب این مثال اون رو اجرا کنین. این یک مثال فرضی ساده از برنامه نمایش ارزش آنلاین سهام برخی شرکتهاست. میتونین این برنامه رو همزمان در چند مرورگر اجرا کنین و نتیجه رو مشاهده کنین.
              حالا میریم سراغ یک مثال ساده. میخوایم یک برنامه چت ساده بنویسیم. ابتدا یک برنامه وب اپلیکیشن خالی رو ایجاد کرده و با استفاده از دستور زیر در خط فرمان نوگت، کتابخونه SignalR رو نصب کنین:
              PM> Install-Package SignalR
              پس از کامل شدن نصب این کتابخونه، ریفرنس‌های زیر به برنامه اضافه میشن:
              Microsoft.Web.Infrastructure
              Newtonsoft.Json
              SignalR
              SignalR.Hosting.AspNet
              SignalR.Hosting.Common
              برای کسب اطلاعات مختصر و مفید از تمام اجزای این کتابخونه به اینجا مراجعه کنین.
              همچنین اسکریپت‌های زیر به پوشه Scripts اضافه میشن (این نسخه‌ها مربوط به زمان نگارش این مطلب است):
              jquery-1.6.4.js
              jquery.signalR-0.5.1.js
              بعد یک کلاس با نام SimpleChat به برنامه اضافه و محتوای زیر رو در اون وارد کنین:
              using SignalR.Hubs;
              namespace SimpleChatWithSignalR
              {
                public class SimpleChat : Hub
                {
                  public void SendMessage(string message)
                  {
                    Clients.reciveMessage(message);
                  }
                }
              } 
              
              دقت کنین که این کلاس از کلاس Hub مشتق شده و همچنین خاصیت Clients از نوع dynamic است. (در مورد جزئیات این کتابخونه در قسمت‌های بعدی توضیحات مفصل‌تری داده میشه)
              سپس یک فرم به برنامه اضافه کرده و محتوای زیر رو در اون اضافه کنین:
              <input type="text" id="msg" />
              <input type="button" value="Send" id="send" /><br />
              <textarea id='messages' readonly="true" style="height: 200px; width: 200px;"></textarea>
              <script src="Scripts/jquery-1.6.4.min.js" type="text/javascript"></script>
              <script src="Scripts/jquery.signalR-0.5.1.min.js" type="text/javascript"></script>
              <script src="signalr/hubs" type="text/javascript"></script>
              <script type="text/javascript">
                var chat = $.connection.simpleChat;
                chat.reciveMessage = function (msg) {
                 $('#messages').val($('#messages').val() + "-" + msg + "\r\n"); 
                };
                $.connection.hub.start();
                $('#send').click(function () {
                  chat.sendMessage($('#msg').val());
                });
              </script>
              همونطور که میبینین برنامه چت ما آماده شد! حالا برنامه رو اجرا کنین و با استفاده از دو مرورگر مختلف نتیجه رو مشاهده کنین.
              نکته کلیدی کار SignalR در خط زیر نهفته است:
              <script src="signalr/hubs" type="text/javascript"></script>
              اگر محتوای آدرس فوق رو دریافت کنین می‌بینین که موتور این کتابخانه تمامی متدهای موردنیاز در سمت کلاینت رو با استفاده از کدهای جاوااسکریپت تولید کرده. البته در این کد تولیدی از نامگذاری camel Casing استفاده میشه، بنابراین متد SendMessage در سمت سرور به‌صورت sendMessage در سمت کلاینت در دسترسه.
              امیدوارم تا اینجا تونسته باشم علاقه شما به استفاده از این کتابخونه رو جلب کرده باشم. در قسمت‌های بعد موارد پیشرفته‌تر این کتابخونه معرفی میشه.
              اگه علاقه‌مند باشین میتونین از این ویکی اطلاعات بیشتری بدست بیارین.


              به روز رسانی
              در دوره‌ای به نام SignalR در سایت، به روز شده‌ای این مباحث را می‌توانید مطالعه کنید.
              مطالب
              استفاده از Web Fonts در اپلیکیشن های ASP.NET MVC

              Typography در طراحی وب

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

              به همین دلیل است که فریم ورک‌های HTML/CSS هر روزه محبوب‌تر می‌شوند. فریم ورک هایی مانند Twitter Bootstrap, HTML5 Boilerplate, Foundation و غیره. این فریم ورک‌ها طراحی و ساخت اپلیکیشن‌های وب را ساده‌تر و سریع‌تر می‌کنند، چرا که بسیاری از نیازهای رایج در طراحی وب پیاده سازی شده اند و دیگر نیازی به اختراع مجدد آنها نیست. اما به غیر از طراحی وب سایتی با ظاهری شیک و پسندیده، مقوله Typography شاید آخرین چیزی باشد که توسعه دهندگان به آن فکر می‌کنند.

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

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

              طراحان وب طی سالیان متمادی، از فونت هایی استفاده می‌کردند که احتمال وجود آنها روی بازه گسترده ای از کامپیوتر‌ها زیاد بود. اینگونه فونت‌ها با عنوان 'web-safe' یاد می‌شوند:
              • Arial
              • Courier New
              • Helvetica
              • Times New Roman
              • Trebuchet
              • Georgia
              • Verdana
              این لیست کوتاه، تنوع بسیار محدودی را در اختیار طراحان قرار می‌داد. برای رفع این محدودیت تکنیک‌های مختلفی استفاده می‌شد. مثلا متون مورد نظر را بصورت تصویر درج می‌کردند، یا با استفاده از افزونه ای در مرورگر از فونت خاصی استفاده می‌شد. مشکل عمده این روش‌ها این بود که متون مورد نظر قابل انتخاب و جستجو نبودند.

              Web Fonts
              یکی از راه حل‌ها برای رفع این محدودیت، توسعه فونت‌های وب بود. فونت‌های وب روی هر پلفترمی قابل استفاده هستند و توسط یک درخواست HTTP بارگذاری می‌شوند. با استفاده از فونت‌های وب، متون ما قابل انتخاب، جستجو و ترجمه به زبان‌های دیگر هستند. ناگفته نماند که بازه type-face‌‌های بسیار گسترده‌تری هم در دست داریم. از طرف دیگر به دلیل اینکه اکثر مرورگرهای وب امروزی از Web Fonts پشتیبانی می‌کنند، می‌توان اطمینان داشت که خروجی مورد نظر تقریبا روی تمام پلتفرم‌ها یکسان خواهد بود.

              استفاده از فونت‌های وب در اپلیکیشن‌های ASP.NET MVC
              خوب، چگونه می‌توانیم از فونت‌های وب در اپلیکیشن‌های MVC استفاده کنیم؟ در ادامه یک نمونه را بررسی میکنیم.
              1. یک سرویس فونت انتخاب کنید. سرویس دهندگان زیادی وجود دارند که فونت‌های وب رایگان و پولی متنوعی را فراهم می‌کنند. برخی از سرویس دهندگان محبوب:
              در مثال جاری از سرویس Typekit استفاده خواهیم کرد. نحوه استفاده از دیگر سرویس‌ها هم تقریبا یکسان است.
              2. فونت مورد نظر را انتخاب کنید. سرویس‌های مذکور کتابخانه‌های بزرگی از فونت‌های وب دارند، که توسط رابط کاربری قوی آنها می‌توانید رندر نهایی فونت‌ها را مشاهده کنید. همچنین می‌توانید لیست فونت‌های موجود را بر اساس پارامترهای مختلفی مانند خواص، طبقه بندی، توصیه شده‌ها و غیره فیلتر کنید. برای مثال جاری فونت Bistro Script Web را انتخاب می‌کنیم.

              3. کد جاوا اسکریپت خود را تولید کنید (تمام سرویس دهندگان این امکان را پیاده سازی کرده اند).

              4. قطعه کد جاوا اسکریپت تولید شده را، در قسمت <head> فایل (Layout.cshtml (Razor_ یا (Site.Master (ASPX کپی کنید.

              5. CSS Selector‌‌های لازم برای فونت مورد نظر را تولید کنید.

              6. کد css تولید شده را در فایل Site.css کپی کنید. در مثال جاری فونت کل اپلیکیشن را تغییر می‌دهیم. برای اینکار، خانواده فونت "bistro-script-web" را به تگ body اضافه می‌کنیم.

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

              همین! حالا می‌توانیم تغییرات اعمال شده را مشاهده کنیم. بصورت پیش فرض قالب پروژه‌ها از فونت "Segoe UI" استفاده می‌کنند، که خروجی زیر را رندر می‌کند.

              استفاده از فونت جدید "Bistro Script Web" وب سایت را مانند تصویر زیر رندر خواهد کرد.

              همانطور که می‌بینید استفاده از فونت‌های وب بسیار ساده است. اما بهتر است از اینگونه فونت‌ها برای کل سایت استفاده نشود و تنها روی المنت‌های خاصی مانند سر تیتر‌ها (h1,h2,etc) اعمال شوند.

              مطالب
              جایگزین کردن jQuery با JavaScript خالص - قسمت ششم - رخدادهای مرورگرها
              واکنش نشان دادن به تغییرات صفحات وب، قسمت مهم و عمده‌ای از کار توسعه‌ی برنامه‌های وب را تشکیل می‌دهد. مفاهیم مرتبط با DOM events از زمان IE 4.0 و Netscape Navigator version 2 به مرورگرها اضافه شدند و به مرور تکامل یافتند. پیش از ظهور مرورگرهای مدرن (به IE 9.0 و مرورگرهای پیش از آن، مرورگرهای «باستانی» گفته می‌شود) به علت عدم هماهنگی آن‌ها با استانداردهای وب و تفاوت روش‌های رخدادگردانی، jQuery نقش مهمی را در زمینه‌ی یکدست سازی کدهای مدیریت رخدادها در بین مرورگرهای مختلف ارائه کرد. اما با پیش‌رفت‌های صورت گرفته و هماهنگی بیشتر مرورگرها با استانداردهای وب، دیگر نیازی به jQuery برای ارائه‌ی کدهای یکدست رخدادگردانی نیست و کار مستقیم با API وب مرورگرها برای این منظور کافی است.


              انواع رخدادها: بومی و سفارشی

              دو رده بندی عمومی رخدادها در مرورگرها وجود دارند: بومی و سفارشی.
              بومی‌ها همان‌هایی هستند که در مستندات رسمی استانداردهای وب ذکر شده‌اند؛ مانند click که توسط ماوس و یا صفحه کلید فعال می‌شود و یا load که در زمان بارگذاری کامل صفحه، تصاویر و یا یک iframe رخ می‌دهد.
              رخدادهای سفارشی مواردی هستند که توسط یک کتابخانه‌ی خاص و یا جهت یک برنامه‌ی خاص تهیه شده‌اند. مانند یک رخداد سفارشی که زمان شروع آپلود یک فایل را اعلام می‌کند.
              رخدادهای سفارشی که بدون jQuery ایجاد و رخ‌می‌دهند، توسط jQuery نیز قابل بررسی و مدیریت هستند و نه برعکس. به عبارتی رخدادهای سفارشی ایجاد شده‌ی توسط jQuery غیراستاندارد بوده و صرفا مختص به API آن هستند.
              در این بین، شیء استاندارد Event کار اتصال رخدادهای سفارشی و استاندارد را انجام می‌دهد. هر نوع رخداد DOM (سفارشی و یا بومی)، توسط یک شیء Event بیان می‌شود که آن نیز به همراه تعدادی خاصیت و متد، جهت مدیریت این رخداد است. برای مثال رخداد click دارای خاصیت type ایی به نام click است که در شیء Event متناظر با آن تعریف شده‌است.


              انتشار رخدادها در صفحه

              در روزهای آغازین وب، Netscape روش event capturing را برای انتشار رخدادها در صفحه ارائه داد و در مقابل آن IE روش event bubbling را معرفی کرد که متضاد یکدیگر بودند. در سال 2000 با ارائه استاندارد DOM Level 2 Events Specification، این وضعیت تغییر کرد و شامل هر دو مورد event capturing و event bubbling است و در حال حاضر تمام مرورگرهای مدرن این استاندارد را پیاده سازی کرده‌اند. بر اساس این استاندارد، زمانیکه رویدادی خلق می‌شود، فاز capturing آغاز می‌گردد که از شیء window شروع، سپس به شیء document منتشر می‌شود و این روند تا رسیدن به المانی که سبب بروز رخداد شده‌است ادامه پیدا می‌کند. پس از پایان فاز capturing، فاز جدید bubbling شروع می‌شود. در این فاز، رخداد از تمام والدین شیء هدف عبور می‌کند تا به شیء window برسد.
              برای مثال اگر سند HTML ما چنین تعریفی را داشته باشد و بر روی المان «child of child of one» کلیک شده باشد:
                 <!DOCTYPE html> 
                 <html>
                 <head>
                   <title>event propagation demo</title>
                 </head>
                 <body>
                   <section>
                     <h1>nested divs</h1>
                     <div>one
                      <div>child of one
                        <div>child of child of one</div>
                      </div>
                    </div>
                  </section>
                </body>
                </html>
              این رخداد در فاز capturing از این المان‌ها عبور می‌کند:
              1.window
              2.document
              3.<html>
              4.<body>
              5.<section>
              6.<div>one
              7.<div>child of one
              8.<div>child of child of one
              و در فاز Bubbling از این المان‌ها:
              9.<div>child of child of one
              10.<div>child of one
              11.<div>one
              12.<section>
              13.<body>
              14.<html>
              15.document
              16.window
              هرچند به دلایل تاریخی و همچنین عدم پشتیبانی jQuery از فاز capturing، بیشتر از فاز Bubbling به صورت پیش‌فرض در رخدادگردانی استفاده می‌شود. همچنین صدور رخداد از المانی که آن‌را ایجاد کرده‌است، بیشتر منطقی به نظر می‌رسد تا عکس آن.
              البته باید درنظر داشت که jQuery از روش ارائه شده‌ی توسط مرورگر برای فاز Bubbling استفاده نمی‌کند و این مسیر را خودش مجددا محاسبه و رخدادگردان‌های این مسیر را به صورت دستی اجرا می‌کند. به همین جهت کارآیی آن نسبت به روش توکار و بومی مرورگرها کمتر است.


              ایجاد رخدادهای DOM و صدور آن‌ها در jQuery

              برای نمایش ایجاد و صدور رخدادهای DOM با و بدون jQuery، از قطعه کد HTML زیر استفاده می‌کنیم:
                 <div>
                   <button type="button">do something</button>
                 </div>
               
                <form method="POST" action="/user">
                   <label>Enter user name:
                     <input name="user">
                   </label>
                   <button type="submit">submit</button>
                </form>
              jQuery به همراه دو متد trigger و triggerHandler برای ایجاد و انتشار رخدادها در طول DOM است. متد trigger سبب ایجاد، صدور و انتشار یک رخداد به تمام والدهای شیء صادر کننده‌ی رخداد می‌شود. نوع این انتشار نیز bubbling است. متد triggerHandler، فقط بر روی المانی که فراخوانی می‌شود، عمل کرده و سبب انتشار این رخداد از طریق bubbling نمی‌شود:
                 // submits the form 
                 $('FORM').trigger('submit');
               
                 // submits the form by clicking the button 
                 $('BUTTON[type="submit"]').trigger('click');
               
                 // focuses the text input 
                 $('INPUT').trigger('focus');
               
                // removes focus from the text input 
                $('INPUT').trigger('blur');
              در این مثال‌ها توسط متد trigger، به دو روش سبب submit یک فرم و همچنین در ابتدا سبب focus یک تکست باکس و سپس رفع آن شده‌ایم.
              هرچند روش دومی نیز در jQuery API برای انجام همینکارها نیز پیش بینی شده‌است:
                 // submits the form 
                 $('FORM').submit();
               
                 // submits the form by clicking the button 
                 $('BUTTON[type="submit"]').click();
               
                 // focuses the text input 
                 $('INPUT').focus();
               
                // removes focus from the text input 
                $('INPUT').blur();
              در اینجا به ازای هر رخداد، یک نام مستعار در jQuery API تدارک دیده شده‌است.

              در ادامه فرض کنید یک دکمه داخل یک div قرار گرفته‌است و آن div نیز به همراه یک مدیریت کننده‌ی رخداد کلیک است. در این حالت اگر بخواهیم با کلیک بر روی دکمه سبب اجرای رویدادگردان div والد نشویم، می‌توان از متد triggerHandler استفاده کرد:
                // clicks the first button - the click event does not bubble 
                $('BUTTON[type="button"]').triggerHandler('click');


              ایجاد رخدادهای DOM و صدور آن‌ها در جاوا اسکریپت (بدون استفاده از jQuery)

              در web API مرورگرها، برای انجام بروز رخدادهای معادل مثالی که با jQuery مطرح شد، می‌توان متدهای بومی متناظر با این رخدادها را بر روی المان‌ها فراخوانی کرد:
                 // submits the form 
                 document.querySelector('FORM').submit();
               
                 // submits the form by clicking the button 
                 document.querySelector('BUTTON[type="submit"]').click();
               
                 // focuses the text input 
                 document.querySelector('INPUT').focus();
               
                // removes focus from the text input 
                document.querySelector('INPUT').blur();
              قطعه کد فوق به علت استفاده‌ی از querySelector، با IE 8.0 و تمام مرورگرهای پس از آن سازگار است.
              متدهای توکار و بومی click ،focus و blur بر روی تمام عناصر DOM که از اینترفیس HTMLElement مشتق شده باشند، وجود دارند. متد submit فقط بر روی المان‌هایی از نوع <form> وجود دارد و قابل فراخوانی است.
              باید دقت داشت که فراخوانی متدهای click و submit از نوع bubbling است؛ اما متدهای focus و blur خیر. از این جهت که این دو رخداد فاز capturing را سبب می‌شوند.

              متدهای یاد شده را توسط سازنده‌ی شیء Event و یا متد createEvent شیء document نیز می‌توان ایجاد کرد. یکی از کاربردهای آن، ارائه‌ی رفتاری سفارشی مانند triggerHandler جی‌کوئری است:
                 var clickEvent;
              
                 if (typeof Event === 'function') {
                   clickEvent = new Event('click', {bubbles: false});
                 }
                 else {
                     clickEvent = document.createEvent('Event');
                    clickEvent.initEvent('click', false, true);
                }
              
                document.querySelector('BUTTON[type="button"]').dispatchEvent(clickEvent);
              کار با سازنده‌ی شیء Event در تمام مرورگرهای جدید، منهای IE (تمام نگارش‌های آن) پشتیبانی می‌شود. در اینجا اگر این پشتیبانی وجود داشت، از خاصیت bubbles: false شیء Event استفاده می‌شود و اگر مرورگری قدیمی بود، از متد document.createEvent برای این منظور کمک گرفته می‌شود. در این حالت دومین پارامتر متد initEvent، همان bubbles است.


              ایجاد و صدور رخدادهای سفارشی

              فرض کنید در حال تهیه‌ی کتابخانه‌ای هستیم که افزودن و حذف آیتم‌ها را به یک گالری عکس ارائه می‌دهد. می‌خواهیم روشی را در اختیار مصرف کننده قرار دهیم تا بتواند به این رخدادهای سفارشی (غیر استانداردی که جزو W3C نیستند) گوش فرا دهد.
              در جی‌کوئری برای ایجاد رخدادهای سفارشی به صورت زیر عمل می‌شود:
                // Triggers a custom "image-removed" element, 
                // which bubbles up to ancestor elements.
              $libraryElement.trigger('image-removed', {id: 1});
              در اینجا نیز صدور رخدادها همانند قبل و توسط همان متد trigger است. اما مشکلی که با آن وجود دارد این است که گوش فرا دهنده‌ی به این رخداد نیز باید توسط جی‌کوئری ارائه شود و خارج از این کتابخانه قابل دریافت و پیگیری نیست.
              در خارج از جی‌کوئری و توسط web API استاندارد مرورگرها ایجاد و صدور رخدادهای سفارشی به همراه bubbling آن به صورت زیر است:
                var event = new CustomEvent('image-removed', {
                  bubbles: true,
                  detail: {id: 1}
                });
                libraryElement.dispatchEvent(event);
              البته باید به‌خاطر داشته باشید این روش صرفا با مرورگرهای جدید (منهای تمام نگارش‌های IE) کار می‌کند. در اینجا اگر نیاز به ارائه‌ی راه حلی سازگار با IE نیز وجود داشت می‌توان از document.createEvent استفاده کرد:
                var event = document.createEvent('CustomEvent');
                event.initCustomEvent('image-removed', false, true, {id: 1});
                libraryElement.dispatchEvent(event);
              و اگر بخواهیم بررسی وجود IE و یا پشتیبانی از CustomEvent را نیز قید کنیم، به قطعه کد زیر خواهیم رسید که با تمام مرورگرهای موجود کار می‌کند:
                var event;
               
                 // If the `CustomEvent` constructor function is not supported, 
                 // fall back to `createEvent` method. 
                 if (typeof CustomEvent === 'function') {
                   event = new CustomEvent('image-removed', {
                     bubbles: true,
                     detail: {id: 1}
                   });
                }
                else {
                    event = document.createEvent('CustomEvent');
                    event.initCustomEvent('image-removed', false, true, {
                      id: 1
                    });
                }
              
                libraryElement.dispatchEvent(event);


              گوش فرادادن به رخدادهای صادر شده، توسط jQuery

              در جی‌کوئری با استفاده از متد on آن می‌توان به تمام رخدادهای استاندارد و همچنین سفارشی گوش فرا داد:
                $(window).on('resize', function() {
                   // react to new window size 
                });
              در ادامه برای حذف تمام گوش فرا دهنده‌های به رخداد resize می‌توان از متد off آن استفاده کرد:
                // remove all resize listeners - usually a bad idea 
                $(window).off('resize');
              اما مشکلی را که این روش به همراه دارد، از کار انداختن تمام قسمت‌های دیگری است که هم اکنون به صدور این رخداد گوش فرا می‌دهند.
              روش بهتر انجام اینکار، ذخیره‌ی ارجاعی به متدی است که قرار است این رویداد گردانی را انجام دهد:
                var resizeHandler = function() {
                    // react to new window size 
                };
              
                $(window).on('resize', resizeHandler);
              
                // ...later 
                // remove only our resize handler 
                $(window).off('resize', resizeHandler);
              و در آخر تنها این گوش فرا دهنده‌ی خاص را در صورت نیاز غیرفعال می‌کنیم و نه تمام گوش فرادهنده‌های سراسر برنامه را.

              همچنین اگر یک گوش فراهنده‌ی به رخدادی تنها قرار است یکبار در طول عمر برنامه اجرا شود، می‌توان از متد one استفاده کرد:
              $(someElement).one('click', function() {
                  // handle click event 
              });
              پس از یکبار اجرای رخدادگردان کلیک در اینجا، از کلیک‌های بعدی صرفنظر خواهد شد.


              گوش فرادادن به رخدادهای صادر شده، توسط جاوا اسکریپت خالص (یا همان web API مرورگرها)

              ابتدایی‌ترین روش گوش فرادادن به رخدادها که از زمان آغاز معرفی آن‌ها در دسترس بوده‌است، روش تعریف inline آن‌ها است:
                <button onclick="handleButtonClick()">click me</button>
              در اینجا متد رویدادگردان به یکی از ویژگی المان انتساب داده می‌شود. مشکل این روش، نیاز به سراسری تعریف کردن متد handleButtonClick است و دیگر نمی‌توان آن‌را در فضای نامی خاص و یا سفارشی قرار داد.
              روش دیگر ثبت رویدادگردان click، انتساب متد آن به خاصیت رخداد متناظری در آن المان ویژه است:
                buttonEl.onclick = function() {
                  // handle button click 
                };
              مزیت این روش، عدم نیاز به استفاده‌ی از متدهای سراسری است.
              البته باید دقت داشت که یکی از دو روش یاد شده را می‌توانید استفاده کنید. در اینجا آخرین رویدادگردان متصل شده‌ی به المان، همواره تمام نمونه‌های موجود دیگر را بازنویسی می‌کند.
              اگر نیاز به معرفی رویدادگردان‌های متعددی برای یک المان در ماژول‌های مختلف برنامه وجود داشت، از زمان IE 9.0 به بعد، متد addEventListener برای این منظور تدارک دیده شده‌است و syntax آن بسیار شبیه به متد on جی‌کوئری است:
                buttonEl.addEventListener('click', function() {
                  // handle button click 
                });
              در این حالت دیگر مشکل نیاز به متدهای سراسری و یا عدم امکان تعریف بیش از یک رویدادگردان خاص برای المانی مشخص، دیگر وجود ندارد.
              برای نمونه معادل قطعه کد جی‌کوئری که پیشتر با متد on نوشتیم، با جاوا اسکریپت خالص به صورت زیر است:
                window.addEventListener('resize', function() {
                  // react to new window size 
                });
              در اینجا برای حذف یک رویدادگردان می‌توان از متد removeEventListener استفاده کرد. تفاوت مهم آن با متد off جی‌کوئری این است که در اینجا حتما باید مشخص باشد کدام رویدادگردان را می‌خواهید حذف کنید:
                var resizeHandler = function() {
                    // react to new window size 
                };
              
                window.addEventListener('resize', resizeHandler);
              
                // ...later 
                // remove only our resize handler 
                window.removeEventListener('resize', resizeHandler);
              یعنی روش حذف رویدادگردان‌ها در اینجا شبیه به مثال دومی است که برای متد off جی‌کوئری ارائه کردیم. ابتدا باید ارجاعی را به متد رویدادگردان تهیه کنیم و سپس بر اساس این ارجاع، امکان حذف آن وجود خواهد داشت.
              در اینجا حتی امکان تعریف متد one جی‌کوئری نیز پیش بینی شده‌است (البته جزو استانداردهای جدید وب از سال 2016 است):
                someElement.addEventListener('click', function(event) {
                   // handle click event 
                }, { once: true });
              اگر بخواهیم متد one سازگار با مرورگرهای قدیمی‌تر را نیز ارائه کنیم، چنین شکلی را پیدا می‌کند:
                var clickHandler = function() {
                  // handle click event 
                  // ...then unregister handler 
                  someElement.removeEventListener('click', clickHandler);
                };
                someElement.addEventListener('click', clickHandler);
              در اینجا پس از بروز رخداد، کار removeEventListener آن به صورت خودکار صورت می‌گیرد.


              کنترل انتشار رخدادها

              فرض کنید می‌خواهیم جلوی انتخاب المان‌های صفحه مانند تصاویر و متن را توسط ماوس بگیریم. روش انجام اینکار با jQuery به صورت زیر است:
              $(window).on('mousedown', function(event) {
                  event.preventDefault();
              });
              و یا توسط web API مرورگرها به این صورت:
                window.addEventListener('mousedown', function(event) {
                  event.preventDefault();
                });
              مطابق «W3C DOM Level 3 Events specification» عملکرد پیش‌فرض رخداد mousedown با انتخاب متون و یا کشیدن و رها کردن المان‌ها آغاز می‌شود. متد preventDefault یکی از متدهای شیء event است که به رویدادگردان‌های تعریف شده ارسال می‌شود و توسط آن عملکرد پیش‌فرض آن رخداد لغو می‌شود.

              برای جلوگیری کردن از انتشار رخدادی مانند click جهت رسیدن به سایر رویدادگردان‌های ثبت شده‌ی در بین راه فاز bubbling، می‌توان از متد stopPropagation استفاده کرد. روش انجام اینکار در جی‌کوئری:
                $someElement.on('click', function(event) {
                    event.stopPropagation();
                });
              البته jQuery صرفا فاز انتشار از نوع bubbling را پشتیبانی می‌کند.
              و با web Api جهت جلوگیری از انتشار رخدادها در فاز capturing (این تنها راه مدیریت فاز capturing است):
                // stop propagation during capturing phase 
                someElement.addEventListener('click', function(event) {
                    event.stopPropagation();
                }, true);
              و یا استفاده از web API برای جلوگیری از انتشار رخدادها در فاز bubbling:
                // stop propagation during bubbling phase 
                someElement.addEventListener('click', function(event) {
                    event.stopPropagation();
                });
              البته باید درنظر داشت که متد stopPropagation از انتشار رخدادها به سایر گوش فرا دهنده‌های همان المان صادر کننده‌ی رخداد جلوگیری نمی‌کند. برای این منظور باید از متد stopImmediatePropagation استفاده کرد؛ در جی‌کوئری:
                $someElement.on('click', function(event) {
                    event.stopImmediatePropagation();
                });
              و توسط web API مرورگرها:
                someElement.addEventListener('click', function(event) {
                    event.stopImmediatePropagation();
                });

              یک نکته: در این حالت اگر متد رویدادگردانی مقدار false را برگرداند، به معنای فراخوانی هر دوی متد preventDefault و stopPropagation است.


              ارسال اطلاعات به رویدادگردان‌ها

              روش ارسال اطلاعات اضافی به رویداد گردان‌ها در جی‌کوئری به صورت زیر است:
                $uploaderElement.trigger('uploadError', {
                  filename: 'picture.jpeg'
                });
              و رویدادگردان گوش فرا دهنده‌ی به آن، به این نحو می‌تواند به filename دسترسی پیدا کند:
                $uploaderParent.on('uploadError', function(event, data) {
                   showAlert('Failed to upload ' + data.filename);
                });
              در اینجا دومین پارامتر تعریف شده، امکان دسترسی به تمام خواص سفارشی ارسالی را میسر می‌کند.

              روش انجام اینکار با web API مرورگرها به صورت زیر است:
                 // send the failed filename w/ an error event
                var event = new CustomEvent('uploadError', {
                   bubbles: true,
                   detail: {filename: 'picture.jpeg'}
                 });
                 uploaderElement.dispatchEvent(event);
               
                 // ...and this is a listener for the event 
                 uploaderParent.addEventListener('uploadError', function(event) {
                    showAlert('Failed to upload ' + event.detail.filename);
                });
              این روش با تمام مرورگرهای مدرن (منهای تمام نگارش‌های IE) کار می‌کند و روش دسترسی به خاصیت detail سفارشی تعریف و ارسال شده، از طریق همان خاصیت event ارسالی به رویدادگردان است.
              و اگر می‌خواهید از IE هم پشتیبانی کنید، روش جایگزین کردن شیء CustomEvent با createEvent به صورت زیر است:
                // send the failed filename w/ an error event 
                 var event = document.createEvent('CustomEvent');
                 event.initCustomEvent('uploadError', true, true, {
                   filename: 'picture.jpeg'
                 });
                 uploaderElement.dispatchEvent(event);
               
                 // ...and this is a listener for the event 
                 uploaderParent.addEventListener('uploadError', function(event) {
                  showAlert('Failed to upload ' + event.detail.filename);
                });


              متوجه شدن زمان بارگذاری یک شیء در صفحه

              در حین توسعه‌ی برنامه‌های وب، با این نوع سؤالات زیاد مواجه خواهید شد: چه زمانی تمام و یا بعضی از المان‌های صفحه کاملا بارگذاری و رندر شده‌اند؟
              پاسخ به این نوع سؤالات در W3C UI Events specification توسط رویداد استاندارد load داده شده‌است.

              - چه زمانی تمام المان‌های موجود در صفحه کاملا بارگذاری و رندر شده و همچنین شیوه‌نامه‌های تعریف شده نیز به آن‌ها اعمال گردیده‌اند؟
              روش انجام اینکار با jQuery:
                $(window).on('load', function() {
                  // page is fully rendered 
                });
              و توسط web API بومی مرورگرها که بسیار مشابه نمونه‌ی jQuery است:
                window.addEventListener('load', function() {
                  // page is fully rendered 
                });

              - چه زمانی markup استاتیک صفحه‌ی جاری در جای خود قرار گرفته‌اند؟
              اهمیت این موضوع، به دسترسی به زمان مناسب و امن ایجاد تغییرات در DOM بر می‌گردد. برای این منظور رویداد استاندارد DOMContentLoaded پیش‌بینی شده‌است که زودتر از رویداد load، در دسترس برنامه نویس قرار می‌گیرد. در جی‌کوئری توسط یکی از دو روش معروف زیر به رویداد یاد شده دسترسی خواهید داشت:
                $(document).ready(function() {
                  // markup is on the page 
                });
              
                //or
                $(function() {
                  // markup is on the page 
                });
              و معادل web API آن در تمام مرورگرهای جدید، همان تعریف رویدادگردانی برای DOMContentLoaded استاندارد است:
                document.addEventListener('DOMContentLoaded', function() {
                  // markup is on the page 
                });

              یک نکته: بهتر است این تعریف web API را پیش از تگ‌های <link> قرار دهید. زیرا بارگذاری آن‌ها، اجرای هر نوع اسکریپتی را تا زمان پایان عملیات، سد می‌کند.

              - چه زمانی المانی خاص در صفحه بارگذاری شده‌است و چه زمانی بارگذاری یک المان با شکست مواجه شده‌است؟
              در جی‌کوئری توسط بررسی رویدادهای load و error می‌توان به وضعیت نهایی بارگذاری المان‌هایی خاص دسترسی یافت:
                 $('IMG').on('load', function() {
                   // image has successfully loaded 
                 });
               
                 $('IMG').on('error', function() {
                   // image has failed to load 
                 });
              روش انجام اینکار با web API مرورگرها نیز یکی است:
                document.querySelector('IMG').addEventListener('load', function() {
                  // image has successfully loaded 
                });
              
                document.querySelector('IMG').addEventListener('error', function() {
                  // image has failed to load 
                });

              - جلوگیری از ترک اتفاقی صفحه‌ی جاری
              گاهی از اوقات نیاز است برای از جلوگیری از تخریب صفحه‌ی جاری و از دست رفتن اطلاعات ذخیره نشده‌ی کاربر، اگر بر روی دکمه‌ی close بالای صفحه کلیک کرد و یا کاربر به اشتباه به صفحه‌ی دیگری هدایت شد، جلوی اینکار را بگیریم. برای این منظور رخداد استاندارد beforeunload درنظر گرفته شده‌است. روش استفاده‌ی از این رویداد در جی‌کوئری:
                $(window).on('beforeunload', function() {
                  return 'Are you sure you want to unload the page?';
                });
              و در web API مرورگرها:
                window.addEventListener('beforeunload', function(event) {
                  var message = 'Are you sure you want to unload the page?';
                  event.returnValue = message;
                  return message;
                });
              در حالت web API بعضی از مرورگرها از نتیجه‌ی متد استفاده می‌کنند و بعضی دیگر از مقدار خاصیت event.returnValue. به همین جهت هر دو مورد در اینجا مقدار دهی شده‌اند.