تغییرات فوری Database با استفاده از SignalR
سه شنبه 16 شهریور 1395تکنولوژی SignalR این قابلیت را به می دهد که ما توابع real time را در وب خود اضافه کنیم .این به آن معناست که زمان اضافه کردن داده یا محتوا به سرور بلافاصله پس از درخواست انجام می شود.
قسمت کدها
مرحله اول : ایجاد بانک اطلاعاتی و جدول ها
در این قسمت میخواهیم با استفاده از قطعه کد زیر یک بانک اطلاعاتی به نام ExperimentalDB و یک جدول به نام Student ایجاد کنیم :
USE [ExperimentalDB] GO /****** Object: Table [dbo].[Student] Script Date: 8/19/2016 9:12:29 AM ******/ SET ANSI_NULLS ON GO SET QUOTED_IDENTIFIER ON GO SET ANSI_PADDING ON GO CREATE TABLE [dbo].[Student]( [StudentID] [int] IDENTITY(1,1) NOT NULL, [StudentName] [varchar](50) NOT NULL, [DOB] [datetime] NOT NULL, [Weight] [int] NULL, CONSTRAINT [PK_Messages] PRIMARY KEY CLUSTERED ( [StudentID] ASC )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY] ) ON [PRIMARY] GO SET ANSI_PADDING OFF GO
فعال کردن Service Broker در بانک اطلاعاتی
Service Broker یکی از امکانات معرفی شده در SQL است که برای اولین بار در SQL Server 2005 معرفی شد.با استفاده از این ویژگی ، پردازش های داخلی و خارجی میتواند پیام هایی را به صورت نا همزمان ارسال و دریافت کنند که با استفاده از افزونه Transact-SQL Data Manipulation Language (DML) ایمن سازی شده اند.این عمل یک طبقه بندی و مکانیزیم پیام رسانی برای مدل برنامه نویسی نا همزمان است .
در این ویژگی زمانی که ما عملیات افزودن،ویرایش،حذف راانجام دهیم همان لحظه تغییرات اعمال می شود و SQLDependencباید قابل شناسایی باشد. (Servicen Broker) به جای یک معماری Broker که حین Publish شدن رویداد های SQL Dependency رابه عنوان یک subscriber فعال می شود و تغیرات را اعمال می کند . با استفاده از شی SqlDependency ، برنامه میتواند از طریق OnChangeEventHandler notification ها را ایجاد و ثبت کند .
همان طور که مشاهده کنید دستور زیر فعال یا غیر فعال بودن Service Broker را چک می کند.
[ExperimentalDB]
SELECT NAME, IS_BROKER_ENABLED FROM SYS.DATABASES WHERE NAME='ExperimentalDB' Result ------- NAME IS_BROKER_ENABLED -------------- ----------------- ExperimentalDB 0
حال Service Broker بر روی [ExperimentalDB] فعال شده است .
--Enable the Service Broker for ExperimentalDB ALTER DATABASE ExperimentalDB SET ENABLE_BROKER WITH ROLLBACK IMMEDIATE ;
مرحله سوم: یک پروژه از نوع MVC ایجاد می کنیم .
تصویر زیر ساختار پروژه ما را نشان می دهد:
فایل هایی که زیرشان خط کشیده شده است اصلاح شده اند .
حال میخواهیم از طریق Nuget package بسته SinalR را نصب کنیم ، کد زیر را در Package Manager Console وارد کنید تا بسته به پروژه اضافه شود .
Install-Package Microsoft.AspNet.SignalR
فایل StudentRepository.cs
using SignalRInstantDbChangesDemo.Hubs; using SignalRInstantDbChangesDemo.Models; using System; using System.Collections.Generic; using System.Configuration; using System.Data; using System.Data.SqlClient; using System.Linq; namespace SignalRInstantDbChangesDemo.DataAccess { public class StudentRepository { public static List<Student> GetStudentRecords() { var lstStudentRecords = new List<Student>(); string dbConnectionSettings = ConfigurationManager.ConnectionStrings["DefaultConnection"].ConnectionString; using (var dbConnection = new SqlConnection(dbConnectionSettings)) { dbConnection.Open(); var sqlCommandText = @"SELECT [StudentID],[StudentName],[DOB],[Weight] FROM [dbo].[Student]"; using (var sqlCommand = new SqlCommand(sqlCommandText, dbConnection)) { AddSQLDependency(sqlCommand); if (dbConnection.State == ConnectionState.Closed) dbConnection.Open(); var reader = sqlCommand.ExecuteReader(); lstStudentRecords = GetStudentRecords(reader); } } return lstStudentRecords; } /// <summary> /// Adds SQLDependency for change notification and passes the information to Student Hub for broadcasting /// </summary> /// <param name="sqlCommand"></param> private static void AddSQLDependency(SqlCommand sqlCommand) { sqlCommand.Notification = null; var dependency = new SqlDependency(sqlCommand); dependency.OnChange += (sender, sqlNotificationEvents) => { if (sqlNotificationEvents.Type == SqlNotificationType.Change) { StudentHub.SendUptodateInformation(sqlNotificationEvents.Info.ToString()); } }; } /// <summary> /// Fills the Student Records /// </summary> /// <param name="reader"></param> /// <returns></returns> private static List<Student> GetStudentRecords(SqlDataReader reader) { var lstStudentRecords = new List<Student>(); var dt = new DataTable(); dt.Load(reader); dt .AsEnumerable() .ToList() .ForEach ( i => lstStudentRecords.Add(new Student() { StudentID = (int)i["StudentID"] , StudentName = (string)i["StudentName"] , DOB = Convert.ToDateTime(i["DOB"]) , Weight = (int)i["Weight"] }) ); return lstStudentRecords; } } }
متد GetStudentRecords() رکورد های Student را از بانک اطلاعاتی واکشی می کند . برای انجام این کار میتوان از روش ADO.NET و روش های دیگر استفاده کرد ما در این قسمت از ADO.NET استفاده کرده ایم .
در متد AddSQLDependency ، ما SQLDependency را اضافه کرده ایم . OnChangeEventHandler زمانی اجرا می شود که notification هر دستور با، شی System.Data.SqlClient.SqlDependency دریافت شده باشد .به محض این که تغییری بر روی بانک اطلاعاتی ایجاد شود (افزودن،ویرایش،حذف)، OnChangeEventHandler به سرعت اطالاعات را به متد SendUptodateInformation در StudentHub ارسال می کند.
dependency.OnChange += (sender, sqlNotificationEvents) => { if (sqlNotificationEvents.Type == SqlNotificationType.Change) { StudentHub.SendUptodateInformation(sqlNotificationEvents.Info.ToString()); } };
فایل StudentHub.cs
using Microsoft.AspNet.SignalR; using Microsoft.AspNet.SignalR.Hubs; namespace SignalRInstantDbChangesDemo.Hubs { public class StudentHub : Hub { [HubMethodName("sendUptodateInformation")] public static void SendUptodateInformation(string action) { IHubContext context = GlobalHost.ConnectionManager.GetHubContext<StudentHub>(); // the updateStudentInformation method will update the connected client about any recent changes in the server data context.Clients.All.updateStudentInformation(action); } } }
کلاس StudentHun.cs را برای مقاوم ساختن اتصال بین Clident و Server استفاده می شود.این روند را Remote Procedure Call (RPC) مینامند که Client و Server و بلعکس را به هم متصل می کند .متد updateStudentInformation اتصال سمت Client و تغیراتی که به تازگی بر روی داده های سرور رخ داده است را بروزرسانی می کند.
پوشه Models شامل مدل Student و سروریس آن است .
فایل Student.cs شامل مدل Student است :
public class Student { [DisplayName("شماره")] public int StudentID { get; set; } [DisplayName("نام")] public string StudentName { get; set; } [DisplayName("زمان")] public DateTime DOB { get; set; } [DisplayName("وزن")] public int Weight { get; set; } }
IStudentService اینترفیسی است که شامل سرویس ها می شود:
public interface IStudentService { List<Student> GetStudentDetails(); }
پیاده سازی یک پارچه در فایل StudentService.cs مشاهده می شود:
public class StudentService : IStudentService { public List<Student> GetStudentDetails() { return StudentRepository.GetStudentRecords(); } }
کد زیر تشکیل دهنده HomeController است :
using SignalRInstantDbChangesDemo.Models; using System.Web.Mvc; namespace SignalRDbUpdates.Controllers { public class HomeController : Controller { public ActionResult Index() { return View(); } public ActionResult SendStudentNotification() { IStudentService studentService = new StudentService(); return PartialView("_StudentList", studentService.GetStudentDetails()); } } }
_StudentList یک Partial View است که رکورد ها را نمایش می دهد.
فایل Global.asax.cs حائز اهمیت است چون در این فایل ما SqlDependency ، را Start و Stop می کنیم .
using System.Configuration; using System.Data.SqlClient; using System.Web.Http; using System.Web.Mvc; using System.Web.Optimization; using System.Web.Routing; namespace SignalRDbUpdates { public class MvcApplication : System.Web.HttpApplication { string connString = ConfigurationManager.ConnectionStrings["DefaultConnection"].ConnectionString; protected void Application_Start() { AreaRegistration.RegisterAllAreas(); FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters); RouteConfig.RegisterRoutes(RouteTable.Routes); BundleConfig.RegisterBundles(BundleTable.Bundles); GlobalConfiguration.Configure(WebApiConfig.Register); //Start SqlDependency with application initialization SqlDependency.Start(connString); } protected void Application_End() { //Stop SqlDependency SqlDependency.Stop(connString); } } }
متد SqlDependency.Start(string connectionString زمانی که تغییر dependency ، از نمونه SQL Server که با connection string مشخص شده است اطلاع رسانی شود شروع با کار می کند.
متد SqlDependency.Stop(string connectionString) زمانی متوقف می شود که Connection مشخص شده در System.Data.SqlClient.SqlDependency.Start فراخوانی شود.
در مرحله بعد ما نیاز به ثبت SignalR در کلاس Startup.cs داریم . برای پیدا کردن کلاس Startup از ساختار زیر استفاده می کنیم :
[assembly: OwinStartupAttribute(typeof(SignalRDbUpdates.Startup))]
این کد نشان دهنده اجرا شدن کلاس به عنوان یک تابع دریافت یک نمونه از Microsoft.Owin.IowinContext است.هنگامی که سرور درخواست HTTP را دریافت می کند OWIN pipeline ، middleware را فراخوانی می کند. Middleware نوع محتوا را برای پاسخ و نوشتن پاسخ در body انتخاب می کند.
حال در داخل تابع Configuration ما نیاز به map SignalR hub داریم که در app builder قرار دارد . ما میتوان از روش زیر استفاده کنیم .
using Microsoft.Owin; using Owin; [assembly: OwinStartupAttribute(typeof(SignalRInstantDbChangesDemo.Startup))] namespace SignalRInstantDbChangesDemo { public partial class Startup { public void Configuration(IAppBuilder app) { app.MapSignalR(); } } }
دراین قسمت میخواهیم به View ها بپردازیم ، کد زیر تشکیل دهنده Index.cshtml است .
@{ ViewBag.Title = "Instant Database Changes Using SignalR Demo-RNA Team"; } <div class="row"> <div class="col-md-12"> <div id="divStudent"></div> </div> </div> @section Scripts{ <script src="~/Scripts/jquery.signalR-2.2.1.min.js"></script> <!--Reference the autogenerated SignalR hub script. --> <script src="/signalr/hubs"></script> <script type="text/javascript"> $(function () { // Create a proxy to signalr hub on web server. It reference the hub. var notifications = $.connection.studentHub; // Notify to client with the recent updates from hub that broadcast messages. notifications.client.updateStudentInformation = function (serverResponse) { alert('changes triggered by ' + serverResponse + ' operation'); getStudentInformation(); }; // Connect to signalr hub $.connection.hub.start().done(function () { getStudentInformation(); }).fail(function (error) { alert(error); }); }); debugger; function getStudentInformation() { var model = $('#divStudent'); $.ajax({ url: '/home/SendStudentNotification', contentType: 'application/html ; charset:utf-8', type: 'GET', dataType: 'html' }).success(function (result) { model.empty().append(result); }).error(function () { }); } </script> }
ابتدای کد نشان می دهد که یک Proxy در SignalR Hub روی Web Server ایجاد کرده ایم.پس از انجام این کار ما نیاز به یک Connection در Hub داریم. Server اطلاع می می دهد که Client رکورد های جدیدی که قرار داده شد است را با استفاده از متد updateStudentInformation برروزرسانی کند و علاوه بر این کار پاسخ سرور را دریافت کرده به عنوان رویداد (افزودن،ویرایش،حذف) ، تغییرات را اعمال می کند .
_StudentList.cshtml رکورد های Student را نمایش می دهد.
@model IEnumerable<SignalRInstantDbChangesDemo.Models.Student> <table class="table"> <tr> <th>@Html.DisplayNameFor(model => model.StudentID)</th> <th> @Html.DisplayNameFor(model => model.StudentName) </th> <th> @Html.DisplayNameFor(model => model.DOB) </th> <th> @Html.DisplayNameFor(model => model.Weight) </th> </tr> @foreach (var item in Model) { <tr> <td> @Html.DisplayFor(modelItem => item.StudentID) </td> <td> @Html.DisplayFor(modelItem => item.StudentName) </td> <th> @Html.DisplayFor(modelItem => item.DOB) </th> <td> @Html.DisplayFor(modelItem => item.Weight) </td> </tr> } </table>
حال میخواهیم برنامه را اجرا کنیم و عملیات را بر روی آن اجرا کنیم .
حال دستور زیر را اجرا کنید.
--Insert Script INSERT INTO [dbo].[Student] ([StudentName] ,[DOB] ,[Weight]) VALUES ('Iman' ,GETDATE() ,50)
نرم افزار انجام شدن عملیات را اطلاع رسانی می کند.
این پیام را نمایش می دهد : changes triggered by Insert operation
بعد از کلیک کردن بر روی دکمه ok تغیرات نمایش داده می شود.
دستور زیر را اجرا کنید :
INSERT INTO [dbo].[Student] ([StudentName] ,[DOB] ,[Weight]) VALUES ('Sajad' ,GETDATE() ,68)
دوباره همان عملیات انجام می شود .
دستور زیر را اجرا کنید
UPDATE [dbo].[Student] SET [Weight] = 25 WHERE [StudentName] = 'Iman'
همان لحظه اطلاع رسانی می شود.
این پیام را نمایش می دهد : changes triggered by Update operation
بعد از کلیک کردن بر روی دکمه ok تغیرات نمایش داده می شود.
دستور زیر را اجر کنید :
DELETE FROM [dbo].[Student] WHERE [StudentName] = 'Sajad'
همان لحظه اطلاع رسانی می شود.
این پیام را نمایش می دهد : changes triggered by Delete operation
بعد از کلیک کردن بر روی دکمه ok تغیرات نمایش داده می شود.
آموزش asp.net mvc
- ASP.net MVC
- 4k بازدید
- 8 تشکر