پیاده سازی CRUD با استفاده از SignalR و Entity Framework

در این مقاله قصد داریم با استفاده از Entity Framework و SignalR در ASP.NET MVC حذف ، افزودن ، ویرایش را به صورت realtime انجام دهیم و از روش Code First استفاده می کنیم .

پیاده سازی CRUD با استفاده از SignalR و Entity Framework

مقدمه

SignalR تکنولوژی است که به ما قابلیت افزودن توابع real time را به وب سایت خود اضافه کنیم . این بدان معنا است که افزودن ، حذف ، ویرایش محتوا با داده ها بلافاصله انجام می شود.

Entity Framework  یک ORM است که  کار با داده های رابطه ای را با استفاده از شی هایی با دامنه خاص ، آسان تر می کند برای دسترسی به داده ها ما از روش Code First استفاده می کنیم.

ASP.NET MVC یک فریم ورک برای پیاده سازی scalable ، مبتنی بر استاندارد های برنامه کاربردی وب است .

 

شروع کار به صورت مرحله ای

مرحله اول : یک پروژه MVC ایجاد می کنیم و رفرنس EF را با پروژه اضافه می کنیم .

در این قسمت ویژوال استودیو را اجرا کرده و یک پروژه mvc ایجاد می کنیم و دستور زیر را در Package Manager Console وارد می کنیم تا EF به پروژه اضافه شود .

using System.ComponentModel.DataAnnotations;

namespace WebApplication1.Models
{
    public class Employee
    {
        [Key]
        public int EmployeeID { get; set; }
        public string EmployeeName { get; set; }
        public string EmailAdress { get; set; }
        public string MobileNumber { get; set; }
    }
}

مرحله سوم : حال کلاس Context  را ایجاد می کنیم .

در این قسمت کلاس EmployeeContext را ایجاد کرده ایم کد زیر را مشاهده کنید :

using System.Data.Entity;
using WebApplication1.Models;

namespace WebApplication1
{
    public class EmployeeContext : DbContext
    {
        public EmployeeContext() : base("dbConnectionString")
        {
            Database.SetInitializer<EmployeeContext>(new CreateDatabaseIfNotExists<EmployeeContext>());
        }
        public DbSet<Employee> Employees { get; set; }
    }
}

مرحله چهارم : یک Connection String به Web.config اضافه می کنیم .

<connectionStrings>
    <add name="dbConnectionString" connectionString="Data Source=yourdatasource;Initial Catalog=EmployeeDB;User ID=youdbuserid;Password=yourdbpassword;pooling=false; MultipleActiveResultSets=True;pooling=false;" providerName="System.Data.SqlClient" />
</connectionStrings>

مرحله 5 : نصب SignalR  با استفاده از Nuget

با وارد کردن  دستور زیر در Package Manager Console ، SignalR به پروژه اضافه می شود .

Install-Package Microsoft.AspNet.SignalR

در این قسمت ما نیاز به ایجاد Startup.cs  داریم که هدف از ایجاد این فایل اضافه کردن یک middleware به جریان OWIN است . برای افزودن این فایل بر روی پروژه راست کلیک و در قسمت Add  ، OWIN Startup class را انتخاب می کنیم .

نام آن را Startup قرار می دهیم .

تصویر زیر شامل کد های  فایل startup.cs است .

کد زیر  کلاس Startup را پیدا می کند .

[assembly: OwinStartup(typeof(WebApp.Startup))]

این نشان دهده این است که این کلاس تابع دریافت ، Microsoft.Owin.IowinContext  را اجرا می کند .

هنگامی که سرور درخواست HTTP را دریافت می کند ، OWIN pipeline فراخوانی می شود و middleware را درخواست می کند .

Middleware نوع محتوا را برای پاسخ و نوشتن پاسخ در body  ، تعیین می کند .

در حال حاظر در تابع  Configuration ما به map SignalR hubs نیاز داریم . برای اضافه کردن آن میتوان از روش زیر استفاده کرد .

using Microsoft.Owin;
using Owin;

[assembly: OwinStartup(typeof(WebApplication1.Startup))]

namespace WebApplication1
{
    public class Startup
    {
        public void Configuration(IAppBuilder app)
        {
            app.MapSignalR();
        }
    }
}

دراین قسمت نیاز به ایجاد یک Hub داریم . کلاس Hub با استفاده از communication  بین Client و Server یک اتصال ایجاد می کند .این عمل باعث می شود که Server , Client از راه دور به هم متصل شوند . برای پیاده سازی این عمل یک کلاس به نام EmployeeHub.cs    ایجاد می کنیم و کد های زیر را وارد می کنیم .

using Microsoft.AspNet.SignalR;
using Microsoft.AspNet.SignalR.Hubs;

namespace WebApplication1
{
    public class EmployeeHub : Hub
    {
        [HubMethodName("NotifyClients")]
        public static void NotifyCurrentEmployeeInformationToAllClients()
        {
            IHubContext context = GlobalHost.ConnectionManager.GetHubContext<EmployeeHub>();

            // the update client method will update the connected client about any recent changes in the server data
            context.Clients.All.updatedClients();
        }
    }
}

Hub  یک کلاس abstract است که متد های SignalR را ارجاع می دهد . و با ارتباط برقرار کردن با SignalR به Microsoft.AspNet.SignalR.Hub. متصل می شود .

IHubContext context = GlobalHost.ConnectionManager.GetHubContext<EmployeeHub>();

Context   ، Employee را دریافت می کند . متد updatedClients میخواهد  متد Client را بروزرسانی کند و تغییراتی که برروی داده های انجام شده بر روی سرور اعمال کند .

context.Clients.All.updatedClients();

قسمت SignalR client فراخوانی می شود و متد جاوا اسکریپتی updatedClients() اجرا می شود . Hub در ارسال پیام و داده بین Client و سرور بسیار مهم است .

مرحله ششم : ایجاد Controller

کد های  تشکیل دهنده   Controller  است .

using System.Collections.Generic;
using System.Data.Entity;
using System.Linq;
using System.Web.Mvc;
using WebApplication1.Models;

namespace WebApplication1.Controllers
{
    public class HomeController : Controller
    {
        List<Employee> empList;

        //Fetch Employee Records
        public ActionResult Index()
        {
            return View();
        }
        [HttpGet]
        public ActionResult GetAllEmployeeRecords()
        {
            using (var context = new EmployeeContext())
            {
                empList = context
                .Employees
                .ToList();
            }          
            return PartialView("_EmployeeList", empList);
        }


        //Insert Employee Record
        public ActionResult Insert()
        {
            return View();
        }
        [HttpPost]
        public ActionResult Insert(Employee employee)
        {  
                if (ModelState.IsValid)
                {
                    //Insert into Employee table 
                    using (var context = new EmployeeContext())
                    { 
                            context.Employees.Add(employee);
                            context.SaveChanges();                       
                    }                                       
                }
           
            //Once the record is inserted , then notify all the subscribers (Clients)
            EmployeeHub.NotifyCurrentEmployeeInformationToAllClients();
            return RedirectToAction("Index");
        }

        //Update Employee Record
        public ActionResult Update()
        {
            return View();
        }
        [HttpPost]
        public ActionResult Update(Employee employee)
        {
            using (var context = new EmployeeContext())
            {
                var empRecord = context.Employees.Find(employee.EmployeeID);

                empRecord.EmployeeName = employee.EmployeeName;
                empRecord.EmailAdress = employee.EmailAdress;
                empRecord.MobileNumber = employee.MobileNumber;

                context.Employees.Add(empRecord);

                context.Entry(empRecord).State = EntityState.Modified;
                context.SaveChanges();
            }

            //Once the record is inserted , then notify all the subscribers (Clients)
            EmployeeHub.NotifyCurrentEmployeeInformationToAllClients();
            return RedirectToAction("Index");
        }

        //Delete Employee Record
        [HttpPost]
        public ActionResult Delete(Employee employee)
        {
            using (var context = new EmployeeContext())
            {
                var empRecord = context.Employees.Find(employee.EmployeeID); 
                context.Employees.Remove(empRecord);
                context.SaveChanges();
            }

            //Once the record is inserted , then notify all the subscribers (Clients)
            EmployeeHub.NotifyCurrentEmployeeInformationToAllClients();
            return RedirectToAction("Index");
        }
    }
}

مرحله هفتم : ایجاد View

در نهایت ، به طراحی UI و درخواست API های Controller و وارد کردن اطلاعات کاربران به صورت real time و بروزرسانی آنها میپردازیم . کد های زیر تشکیل دهنده فایل Index.cshtml است :

@model IList<SignalRSample.Models.Employee>
@{
 
}
<link href="~/Content/bootstrap.min.css" rel="stylesheet" />
 
<div>
    <table border="1">
        <tr>
            <td>
                <h1 style="color:blueviolet">برنامه نویسان</h1>
                <table border="1">
                    <tr>
                        <td>شماره</td>
                        <td><input id="txtEmployeeId" type="text" /></td>
                    </tr>
                    <tr>
                        <td>نام کاربری</td>
                        <td><input id="txtEmployeeName" type="text" /></td>
                    </tr>
                    <tr>
                        <td>ایمیل</td>
                        <td><input id="txtEmail" type="text" /></td>
                    </tr>
                    <tr>
                        <td>شماره موبایل</td>
                        <td><input id="txtMobile" type="text" /></td>
                    </tr>
                </table>
                <table border="1">
                    <tr>
                        <td><button id="btnPostEmployee" onclick="InsertEmployee()">افزودن</button></td>
                        <td>
                            <button id="btnPutEmployee" onclick="UpdateEmployee()">ویرایش</button>
                            <button id="btnDeleteEmployee" onclick="DeleteEmployee();return false;">حذف</button>
                        </td>
                    </tr>
                </table>
            </td>
        </tr>
    </table>
    <br /><br />
    <div id="dataTable"></div>
</div>
 
@section Scripts{
 
    
    <script type="text/javascript">
        $(function () {
          
            // Create a proxy to signalr hub on web server. It reference the hub.
            var notificationFromHub = $.connection.employeeHub;
 
            // Connect to signalr hub
            $.connection.hub.start().done(function () {
                                FetchEmployees();

            });
 
            // Notify to client with the recent updates
            notificationFromHub.client.updatedClients = function () {
                FetchEmployees();
            };
        });
 
        function FetchEmployees() {
            var model = $('#dataTable');
            $.ajax({
                    url: '/home/GetAllEmployeeRecords',
                    contentType: 'application/html ; charset:utf-8',
                    type: 'GET',
                    dataType: 'html'
                })
                .success(function(result) { model.empty().append(result); });
        }
 
        // Insert Employee Record
        function InsertEmployee()
        {
 
                    var employee = {
                        EmployeeID: $('#txtEmployeeId').val(),
                        EmployeeName: $('#txtEmployeeName').val(),
                        EmailAdress: $('#txtEmail').val(),
                        MobileNumber: $('#txtMobile').val()
                    };
 
 
                    $.ajax({
                    url: '/home/Insert',
                    type: 'POST',
                    data: JSON.stringify(employee),
                    contentType: "application/json;charset=utf-8",
                    success: function (data) {
                        alert('Employee added Successfully');
                    },
                    error: function () {
                        alert('Employee not Added');
                    }
                    });
                  
 
        }
 
        // Update Employee Record
        function UpdateEmployee() {
 
            var employee = {
                EmployeeID: $('#txtEmployeeId').val(),
                EmployeeName: $('#txtEmployeeName').val(),
                EmailAdress: $('#txtEmail').val(),
                MobileNumber: $('#txtMobile').val()
            };
 
            $.ajax({
                url: '/home/Update',
                type: 'POST',
                data: JSON.stringify(employee),
                contentType: "application/json;charset=utf-8",
                success: function (data) {
                    alert('Employee updated Successfully');
                },
                error: function (e) {
                    alert('Employee could not be updated');
                }
            });
            
        }
 
        // Delete Employee Record
        function DeleteEmployee() {
 
            var employee = {
                EmployeeID: $('#txtEmployeeId').val()
            };
 
            $.ajax({
                url: '/home/Delete',
                type: 'POST',
                data: JSON.stringify(employee),
                contentType: "application/json;charset=utf-8",
                success: function (data) {
                    alert('Employee deleted Successfully');
                },
                error: function (x, y, z) {
                    alert(x + '\n' + y + '\n' + z);
                }
            });
        
        }
    </script>
}

قطعه کد

            // Create a proxy to signalr hub on web server. It reference the hub.
            var notificationFromHub = $.connection.employeeHub;
            
            // Connect to signalr hub
            $.connection.hub.start().done(function () {
                FetchEmployees();
            });

            // Notify to client with the recent updates
            notificationFromHub.client.updatedClients = function () {
                FetchEmployees();
            };
        });

در ابتدا یک Proxy در  SignalR Hub  روی وب سرور ایجاد کرده ایم . و پس از انجام شدن عملیات ما نیاز به اتصال به Hub داریم .سرور،  بروزرسانی رکورد ها را با استفاده از متد  updatedClients اطلاع رسانی می کند .

حال یکم Patial View به نام   _Employee.cshtml  برای نمایش سوابق کارمندها ایجاد می کنیم.

<table class="table table-bordered table-striped">
    <thead>
        <tr>
            <th>شماره</th>
            <th>نام کاربری</th>
            <th>ایمیل</th>
            <th>شماره موبایل</th>
        </tr>
    </thead>
    <tbody>
        @if (Model != null)
            {
                foreach (var item in Model)
                {
 
                <tr>
                    <td>@item.EmployeeID</td>
                    <td>@item.EmployeeName</td>
                    <td>@item.EmailAdress</td>
                    <td>@item.MobileNumber</td>
                </tr>
            }
        }
 
    </tbody>
</table>

تمامی عملیاتی که انجام داده ایم میتوان در زیر مشاهده کنید .

مرحله هشتم : برنامه را اجرا می کنیم.

برنامه را با دو مرورگر مختلف اجرا می کنیم .

حال یک کارمند در هر دو مرورگر اضافه می کنیم .

میتوان مشاهده کنید که عملیات به صورت real time انجام می شود .

میتوان با استفاده از کد زیر  جدول های خود را تغییر دهید :

1. Enable-Migrations first,
                2. then add-migration
                3. followed by update-database commands from package manager console.

دانلود فایل های ضمیمه مخصوص اعضای سایت می باشد !
کاربر مهمان! جهت دانلود و استفاده از امکانات سایت لطفا وارد سایت شوید و یا ثبت نام کنید
دانلود نسخه ی PDF این مطلب