C# enthusiast. NET foundation member
ساخت چت روم با Blazor Web Assembly و SignalR قسمت اول: ساخت سرور
در این مقاله دو قسمتی قصد داریم که بوسیله SignalR در سرور ASP Net Core و Blazor Web Assembly یک چت روم بسازیم.
معماری کلی پروژه
برای ساده نگه داشتن پروژه، یک پروژه سرور که ASP Net Core Web Api هست داریم. برای کلاینت یک پروژه Blazor Web Assembly داریم و برای مشترکات بین دو پروژه که شامل مدل ها هست یک پروژه از نوع Class Libraryداریم. معماری کلی پروژه را میتوانید در شکل زیر مشاهده کنید. دقت داشته باشید که دو پروژه Server و Client به پروژه Shared رفرنس دارند.
ساخت و تکمیل سرور
افزودن Identity به سرور
ابتدا پکیج Microsoft.Extensions.Identity.Stores را از طریق Nuget دانلود و نصب میکنیم
از طریق Package Manager نیز میتوانیم با دستور زیر اقدام به نصب این پکیج بکنیم.
Install-Package Microsoft.Extensions.Identity.Stores -Version 5.0.9
سپس به سراغ نصب پکیج Microsoft.AspNetCore.Identity.EntityFrameworkCore می رویم
از طریق Package Manager نیز میتوانیم با دستور زیر اقدام به نصب این پکیج بکنیم.
Install-Package Microsoft.AspNetCore.Identity.EntityFrameworkCore -Version 5.0.9
ساخت مدل های Identity
پس از نصب Identity به سراغ ساخت مدل های آن می رویم. ابتدا در پروژه سرور یک فولدر با نام IdentityModels ایجاد میکنیم
برای ساخت مدل User به شکل زیر عمل میکنیم
سپس سایر مدل های Identity را به شکل زیر میسازیم
ساخت Database Context
پس از ساخت مدل های Identity به سراغ ساخت ApplicationDbContext می رویم و آن را به شکل زیر می سازیم.ابتدا یک فولدر با نام Context می سازیم و ApplicationDbContext را داخل آن قرار میدهیم.
برای استفاده از EF Core در پروژه و ایجاد Migration ها نیازمند پکیج های زیر هستیم که از طریق Package Manager و با دستورات زیر آنها را نصب میکنیم
Install-Package Microsoft.EntityFrameworkCore.SqlServer -Version 5.0.9
Install-Package Microsoft.EntityFrameworkCore.Design -Version 5.0.9
Install-Package Microsoft.EntityFrameworkCore.Tools -Version 5.0.9
سپس در متد ConfigureServices کلاس Startup این Database Context را رجیستر میکنیم.
سپس با ایجاد Migration جداول مربوطه را میسازیم.
تنظیم Identity
برای تنظیم Identity به شکل زیر عمل میکنیم.ابتدا یک فولدر با نام Extensions می سازیم و سپس یک کلاس داخل آن با نام IdentityConfigurationExtension ایجاد میکنیم.
در اینجا تنها یک پیاده سازی برای User Claim ها داریم که در آن میتوانیم Custom Claim ها را به توکن کاربر اضافه کنیم. پیاده سازی آن به شکل زیر می باشد
سپس در متد ConfigureServices کلاس Startup از این کلاس به شکل زیر استفاده میکنیم.
افزودن JWT به Identity
برای افزودن JWT به Identity نیازمند پکیج Microsoft.AspNetCore.Authentication.JwtBearer هستیم
این پکیج را از طریق دستور زیر نیز میتوانیم نصب کنیم.
Install-Package Microsoft.AspNetCore.Authentication.JwtBearer -Version 5.0.9
برای تنظیم JWT در فولدر Extensions یک کلاس با نام JWTConfigurationExtension به شکل زیر ایجاد میکنیم.
سپس در متد ConfigureServices کلاس Startup تغییرات زیر را اعمال میکنیم.
در متد Configure کلاس Startup نیز تغییرات زیر را اعمال میکنیم.
ایجاد سرویس های مربوط به ساخت JWT Token
برای ایجاد JWT Token ابتدا در پروژه Shared کلاس AccessToken را به شکل زیر میسازیم. ابتدا در پروژه Shared یک پوشه با نام JWT ایجاد میکنیم و در آن کلاس AccessToken را قرار میدهیم. برای استفاده از کلاس JwtSecurityToken نیازمند پکیج System.IdentityModel.Tokens.Jwt که آن را با دستور زیر از طریق Package Manager Console نصب میکنیم.
Install-Package System.IdentityModel.Tokens.Jwt -Version 6.12.2
این کلاس شامل اطلاعاتی است که برای احراز هویت کاربران مورد نیاز است. ابتدا تایپ توکن را بعنوان Bearer تعریف میکنیم و سپس مقدار زمانی که توکن معتبر است را بعنوان ثانیه نشان میدهیم.
در پروژه Server یک فولدر با نام Service ایجاد میکنیم و در آن یک فولدر دیگر با نام Jwt ایجاد میکنیم.
سپس در آن یک اینترفیس با نام IJwtService ایجاد میکنیم که به صورت زیر میباشد.
سپس کلاس JwtService را به شکل زیر که اینترفیس IJwtService را پیاده سازی میکند مینویسیم.
در این کد ما JWT Token را به صورت Encrypt شده در میاوریم. برای مطالعه بیشتر درباره نحوه Encrypt کردن JWT Token میتوانید به این مقاله از محمد جواد ابراهیمی عزیز مراجعه کنید.
سپس در متد ConfigureServices این سرویس را به شکل زیر رجیستر میکنیم.
ایجاد اکشن های Login و Register
ابتدا مدل های Login و Register را میسازیم. در پروژه Shared یک پوشه با نام Account ایجاد میکنیم و دو کلاس LoginViewModel و RegisterViewModel را به شکل زیر میسازیم.
سپس به سراغ ساخت AccountController می رویم. ابتدا این کنترلر را به شکل زیر می سازیم و سپس اکشن های Login و Register را به آن اضافه میکنیم.
برای ساخت اکشن Register به شکل زیر عمل میکنیم
برای ساخت اکشن Login نیز به شکل زیر عمل میکنیم.
سپس این دو اکشن را در پنل Swagger تست میکنیم.
ساخت جدول Chat History
ابتدا در پروژه Server یک فولدر با نام Models ایجاد میکنیم. و در آن یک کلاس با نام ChatHistory ایجاد میکنیم. این جدول رابطه یک به چند با جدول User دارد.
سپس تغییر زیر را در کلاس User ایجاد میکنیم.
سپس تغییر زیر در کلاس ApplicationDbContext ایجاد میکنیم.
سپس Migration مربوط به ایجاد جدول ChatHistory را ایجاد میکنیم و در نهایت دیتابیس را آپدیت میکنیم.
ساخت Chat Hub و Chat Controller
ابتدا در پروژه Shared یک فولدر با نام Chat ایجاد میکنیم و کلاس های مربوط به Chat Hub را در آن ایجاد میکنیم.
در این فولدر 3 کلاس با نام های UserMessageViewModel و UserIsTypingViewModel و UserJoinedChatViewModel و UserNewMessageViewModel قرار دارند.
از UserMessageViewModel برای نشان دادن پیام ها و همچنین Notify کردن سایر کاربران هنگام ایجاد پیام جدید استفاده میکنیم.
از UserIsTypingViewModel برای Notify کردن سایر کاربران هنگامی که یک کاربر در حال تایپ است استفاده میکنیم
از UserJoinedChatViewModel برای Notify کردن سایر کاربران هنگامی که یک کاربر به چت روم وصل میشود استفاده میکنیم.
از UserNewMessageViewModel هنگامی که کاربر یک پیام جدید به سرور میفرستد استفاده میکنیم.
سپس در پروژه Server یک پوشه با نام Hub ایجاد میکنیم. در آن یک اینترفیس با نام IChatHub به شکل زیر اضافه میکنیم.
سپس ChatHub را به شکل زیر ایجاد میکنیم.
متد OnConnectedAsync را Override کرده ایم و در خط 8 به محض اینکه یک کاربر به هاب متصل میشود نام کاربری آن را به سایر کلاینت ها نشان میدهیم.
سپس به Hub یک متد با نام OnNewMessage اضافه میکنیم که پیام های جدید را گرفته، به دیتابیس اضافه کرده و سپس سایر کلاینت ها را Notify کند.
سپس برای اینکه به سایر کاربران نشان دهیم که کاربر در حال تایپ است متد زیر به هاب اضافه میکنیم.
در متد ConfigureServices کلاس Startup سیگنال آر را به شکل زیر به پروژه اضافه میکنیم.
سپس ChatHub را به شکل زیر به URL مپ میکنیم.
در کلاس JwtConfigurationExtension برای اینکه ChatHub بتواند با JWTکار کند باید تغییرات زیر را اعمال کنیم. چون که در Web Socket نمیتوان مقدار AccessToken را از Header خواند، باید آن را تحت یک QueryString به سرور پاس دهیم. پس کلاس JwtConfigurationExtension به شکل زیر در میاید.
حال به سراغ ساخت ChatController میرویم. شکل ابتدایی ChatController به صورت زیر است.
در این کنترلر ما نیاز به یک اکشن داریم که پیام هایی که تا به حال منتشر شده است را دریافت کند
تنظیمات CORS
برای اینکه Web Api ساخته شده سمت Client در دسترس باشد، نیاز داریم که CORS را در آن فعال کنیم. برای فعال سازی CORS به شکل زیر عمل میکنیم.
ابتدا در متد ConfigureServices کلاس Startup قطعه کد زیر را اضافه میکنیم
برای اینکه بتوانیم از JWT Token در SignalR استفاده کنیم باید از متد AllowCredentials استفاده کنیم. سپس در متد Configure کلاس Startup قطعه کد زیر را اضافه میکنیم.
جمع بندی
در این قسمت از مقاله یک سرور برای اپلیکیشن چت روم با استفاده از Identity ، JWT Authentication و SignalR ساختیم. در قسمت بعد به سراغ ساخت بخش کلاینت با استفاده از Blazor Web Assembly و Signal R Client می رویم و در نهایت یک اپلیکیشن چت روم به صورت Real-Time خواهیم داشت
مقالات بیشتر در دات نت زوم
مطلبی دیگر از این انتشارات
معرفی RabbitMQ: بخش چهارم، آشنایی با رابط مدیریت تحت وب
مطلبی دیگر از این انتشارات
اهمیت Side-effect Free و Idempotency در کدنویسی
مطلبی دیگر از این انتشارات
بررسی نتایج کلیدی نظرسنجی Stackoverflow 2019 (قسمت اول)