چند وقت پیش قرار بود به کمک SignalR، تغییرات روی دیتای موجود رو به صورت لایو نمایش بدم. برای این کار لازم بود به SignalR وصل بشم و منتظر اعلام تغییرات بمونم . بعد از اینکه تغییری اعلام شد، من دیتای اپلیکیشن سمت فرانت رو آپدیت کنم.
روش کار خیلی ساده است. یعنی در سطح فرانت اند، گرفتن نوتیفیکیشن از طرف SignalR خیلی ساده است.
در قدم اول ماژول SignalR رو نصب کردم:
در قدم دوم یک سرویس ساختم که اینجا بهش میگیم Notification Service
برای ادامه فعالیت سرویس، یک متغیر private تعریف کردم بنام hubConnection# از نوع HubConnection ( تایپ تعریف شده کانکشن سرور در ماژول SignalR ) و یک سیگنال بنام notify که تغییرات رو به بیرون اطلاع بده:
قدم بعدی رو با تعریف تنظیمات اتصال به SignalR به صورت زیر، در constructor سرویس، برداشتم:
قبل از اینکه ادامه بدیم، بریم ببینیم هر کدوم از این تنظیمات بالا چی هستند.
این تنظیم نحوه ارتباط کلاینت و سرور رو مشخص میکنه. لازم به ذکره که منظور از کلاینت الزاما جاوااسکریپت نیست و منظور از سرور الزاما IIS نیست. ولی در پروژه ما، با همین کلاینت و سرور سروکار کار داشتیم.
سرور SignalR چهار گزینه در اختیار ما قرار میده که میتوانیم یکی از آنها را انتخاب کنیم:
گزینه ForeverFrame بین گزینه های ماژول نصب شده npm نبود. بجاش گزینه None بود که با تنظیمش، انتخاب پروتکل رو به سیستم واگذار میکنیم.
بریم ببینیم این گزینه ها چی هستند و بر اساس چه مزایا و محدودیت هایی انتخاب میشن:
گزینه Long Polling
این گزینه یک ارتباط از نوع AJAX با سرور برقرار میکنه و بعد از گرفتن اطلاعات، ارتباط را قطع میکنه و دوباره ارتباط جدیدی میسازه. در بهترین حالت به اندازه زمان پیشفرض نگه داشتن ارتباط AJAX توسط کلاینت، ارتباط رو نگه میداره. این گزینه بیشترین فشار رو به سرور تحمیل میکنه. این گزینه رو تنها زمانی انتخاب کنید که:
گزینه ForeverFrame (یا FF، جزو انتخاب های ماژول نصب شده من نبود )
این گزینه فقط روی مرورگر IE پشتیبانی میشه. در این گزینه یک iframe مخفی روی صفحه ساخته میشه. داخل iframe صفحه خاصی باز میشه و ارتباط رو همیشه نگه میداره. اینجا هم ارتباط از جنس AJAX هست.
گزینه Server Side Events (یا SSE)
پروتکل استفاده شده در این گزینه از زمان Netscape بجا مونده. در این پروتکل یک آبجکت به نام EventSource ساخته میشه و هر وقت سرور نیاز به ارسال دیتا داشته باشه، اون رو صدا میکنه. این پروتکل روی همه مرورگرها پشتیبانی میشه بجز IE. در صورت انتخاب این گزینه اگر کلاینت بخواد با سرور ارتباط برقرار کنه، از AJAX استفاده میکنه.
گزینه WebSockets
بهترین گزینه انتخابی همینه! اگر:
گزینه None
در این حالت انتخاب نوع ارتباط به صورت اتوماتیک انجام میگیرد.
گزینه های موجود در این تنظیم عبارتند از: Critical، Debug، Error، Information، None، Trace، Warning
زمانی که فایل ILogger.d.ts داخل ماژول رو باز کنیم، به تعریف یک enum خاص بنام LogLevel برمیخوریم:
من شخصا یک متغیر در environment تعریف کردم و لاگ رو اونجا تعریف کردم و اپ انگولار مقدار داخل اون رو میخونه. اینطوری در environment حالت توسعه، مقدار Trace و در environment حالت پروداکشن مقدار None رو تعریف میکنم .
این تنظیم یک تابع فراخوانی میکنه که مقدار token را برمیگردونه. در اپلیکیشن من AuthService مسئول برگردوندن توکنه . به همین دلیل داخل تنظیماتم اون رو فراخوانی کردم.
در SignalR ابتدا کلاینت یک درخواست Negotiation به سرور میفرسته و سرور یک url ریدایرکت و یک توکن تحویل میگیره. برقراری کانکشن بین کلاینت و سرور فقط بعد از دریافت این جواب برقرار میشه. برای اینکه این Negotiation اتفاق نیفته، می تونیم از گزینه skipNegotiation استفاده کنیم و مقدارش رو true ست کنیم.
نکته : کلاینت برای true کردن این گزینه محدود به استفاده از WebSockets در تنظیم protocol هست که قبلا توضیح داده شده.
بریم سر ادامه داستان...
بعد از تعریف تنظیمات، در ادامه بلاک constructor، رفتم سراغ مقداردهی #hubConnection و تعریف آبجکت کانکشن:
خط دوم در واقع نیازی نیست. ولی صرفا اینجا نوشتم که ببینید میشه LogLevel رو اینجا هم پاس داد.
گزینه withUrl هم که مشخصه، لینک ارتباط به سرور رو دادم و تنظیمات رو بهش پاس دادم.
آخرش تابع build رو صدا کردم تا آبجکت کانکشن ساخته بشه و مقدارش در #hubConnection ذخیره بشه.
بعد از تعریف آبجکت سرور، بر اساس مراوداتی که با هم تیمی عزیزم، (مسئول پیاده سازی SignalR سمت سرور که دستپخت خوبی هم داره) داشتم، متوجه شدم الان وقت رجیستر کردن تابع برای دریافت نتیجه متدهای سمت سروره. برای مثال، سمت سرور یک متد تعریف شده به اسم updateItem که قراره یک آیتم برگردونه. رجیستر کردن برای دریافت پاسخ از سرور اینطوریه:
اول رفتم تایپ مربوط به اون Item رو که قراره از سمت سرور بیاد تعریف کردم. در ادامه بلاک constructor سرویسم، به کمک تابع on در آبجکت hubConnection ، برای متد updateItem سمت سرور، این handler رو رجیستر کردم.
کاری که داخل تابع handler انجام دادم، آپدیت کردن مقدار notify بود که اول constructor تعریف کرده بودم:
و در ادامه کانکشن رو برقرار کردم:
بعد از اینکه سمت سرور اکی شد، در اولین ارتباط همه چیز عالی کار کرد
هندل کردن خطا در ارتباط با سرور، شامل یک تنظیم و یک کال بک هست که همینجا توضیح میدم. تنظیم serverTimeoutInMilliseconds در دریافت پیام از سمت سرور و کال بک برای اطلاع در خطاهای پیش آمده
تنظیم serverTimeoutInMilliseconds
با این تنظیم میتونیم مشخص کنیم که کلاینت تا چند میلی ثانیه منتظر جواب سرور باشه و اگر جوابی نیومد خطای Timeout بده:
در مثال بالا، اگر یک ثانیه از سمت سرور پیامی دریافت نشه، خطای زیر بر میگرده:
حالا خطای timeout رو چطوری متوجه بشیم؟ جوابش در تنظیم هست.
کال بک بسته شدن کانکشن
به کمک این کال بک میتونیم از خطاهای مختلفی که پیش میاد با خبر بشیم:
من شخصا با دو خطا برخورد داشتم. یکیش خطای timeout که بالا توضیح دادم. یکی دیگه خطای قطع ارتباط اینترنت که زمان timeout خودش رو داره.
در این مقاله سعی کردم همه تجربه اولیه ام از ارتباط با SignalR رو توضیح بدم. با نحوه نصب پکیج سمت فرانت اند آشنا شدیم. تنظیماتش رو دیدیم و در نهایت کد پروژه رو کامل کردیم.
:)