هماهنگ سازی IndexedDB با استفاده از ASP.NET Web API

هماهنگ سازی IndexedDB با استفاده از ASP.NET Web API

بسم الله الرحمن الرحیم

در آموزش قبلی، عملیات CRUD را در پایگاه داده HTML5 IndexedDB اجرا کردیم. در این آموزش، ما قصد داریم هماهنگ سازی پایگاه های IndexedDB و SQL Server با استفاده از ASP.NET Web API انجام دهیم. بنابراین با ما همراه باشید.

html5 indexdb

بسم الله الرحمن الرحیم

توجه: برای درک این آموزش شما ابتدا باید مطلب مرتبط با این آموزش را بخوانید.

در آموزش قبلی، عملیات CRUD را در پایگاه داده HTML5 IndexedDB اجرا کردیم. در این آموزش، ما قصد داریم هماهنگ سازی پایگاه های IndexedDB و SQL Server با استفاده از ASP.NET Web API انجام دهیم.

ساختار Server DB

server db structure

  • در اینجا CustomerID بعنوان کلید اصلی و Email فیلد "منحصر به فرد" است.

Web API:

  •  یک پروژه asp.net mvc خالی ایجاد کنید
  • ADO.NET Entity Data Model ( که نام دیگر آن CustomerModel.edmx است) همراه با جدول Customer اضافه کنید
  • بر روی فولدر Controllers کلیک راست کنید و مراحل زیر را انجام دهید:

Add > Controller > Select Template “Empty API Controller” and give name “ServiceController” > Add

  • برای بدست آوردن داده های به روز و تغییر کرده، ما از پارامتر revision و متد Get action استفاده می کنیم.


public dynamic Get(int revision)
       {
           using (DBCustomerEntities context = new DBCustomerEntities())
           {
               int currentRevision = context.Customers.Max(x => x.Revision) ?? 0;
               if (revision == -1)
               {
                   return new
                   {
                       Revision = currentRevision,
                       Customers = context.Customers.Select(x => new
                       {
                           CustomerID = x.CustomerID,
                           Name = x.Name,
                           Email = x.Email,
                           Phone = x.Phone,
                           Revision = x.Revision ?? 0,
                           IsDeleted = x.IsDeleted ?? false
 
                       }).ToList()
                   };
               }
               else if (revision == currentRevision)
               {
                   return new { Revision = currentRevision };
               }
               else
               {
                   return new
                   {
                       Revision = currentRevision,
                       Customers = context.Customers.Where(x => x.Revision > revision).Select(x => new
                       {
                           CustomerID = x.CustomerID,
                           Name = x.Name,
                           Email = x.Email,
                           Phone = x.Phone,
                           Revision = x.Revision,
                           IsDeleted = x.IsDeleted ?? false
                       }).ToList()
                   };
               }
           }
       }







اگر تغییری در داده ها نباشد همان پارامتر revision را بر می گرداند. به این شکل که در قسمت client ما چک خواهیم کرد این پارامتر برای کاربرارسال شده یا نه که پیغام تغییری برای کاربر نشان داده نشود.

  • ما با استفاده از ایمیل چک خواهیم کرد که رکورد تکراری وارد نخواهد شد. چون ایمیل منحصر به فرد و یکتا است.


private readonly object _updatePointsLock = new object();
public dynamic Post(JObject data)
        {
            dynamic json = data;
            int revision = json.revision;
            int appID = json.appID;
            IList customers = ((JArray)json.customers).Select(t => new Customer
            {
                CustomerID = ((dynamic)t).CustomerID ?? -1,
                Name = ((dynamic)t).Name,
                Email = ((dynamic)t).Email,
                Phone = ((dynamic)t).Phone,
                Revision = ((dynamic)t).Revision,
                IsDeleted = ((dynamic)t).IsDeleted ?? false
            }).ToList(); ;
 
            lock (_updatePointsLock)
            {
                using (DBCustomerEntities context = new DBCustomerEntities())
                {
                    int currentRevision = context.Customers.Max(x => x.Revision) ?? 0;
                    //check version
                    if (currentRevision == revision)
                    {
                        foreach (Customer cust in customers)
                        {
                            Customer obj = context.Customers.Where(x => x.Email == cust.Email).FirstOrDefault();
                            if (obj == null)
                            {
                                cust.Revision = currentRevision + 1;
                                cust.LastModifiedDate = DateTime.Now;
                                cust.LastModifiedBy = appID;
                                context.Customers.AddObject(cust);
                            }
                            else
                            {
                                obj.Name = cust.Name;
                                obj.Email = cust.Email;
                                obj.Phone = cust.Phone;
                                obj.IsDeleted = cust.IsDeleted;
                                obj.Revision = currentRevision + 1;
                                obj.LastModifiedDate = DateTime.Now;
                                obj.LastModifiedBy = appID;
 
                            }
 
                        }
                        context.SaveChanges();
                        return new
                        {
                            Revision = currentRevision + 1,
                            Customers = context.Customers.Where(x => x.Revision > revision).Select(x => new
                            {
                                CustomerID = x.CustomerID,
                                Name = x.Name,
                                Email = x.Email,
                                Phone = x.Phone,
                                Revision = x.Revision,
                                IsDeleted = x.IsDeleted ?? false
                            }).ToList()
                        };
                    }
                    else
                    {
                        return new { Revision = revision };
                    }
                }
            }
 
        }


View:

html5 indexeddb web api

  • jQuery, jQuery UI and Modernizr را به پروژه اضافه می کنیم. نصب NuGet نیز راحت است.
  • Linq2IndexedDB را نصب و Package Manager Console آن را به صورت زیر اجرا کنید:

Controllers > Add > Controller > Select Template “Empty MVC Controller” and give name “HomeController” > ADD

  • بر روی Index method کلیک راست کنید و مراحل زیر را انجام دهید:

Add View > clear “use a layout or master page” option > Add

  • کدهای HTML and JS خود را کپی و در HTML mark-up در view قرار دهید. (آموزش این قسمت را نیز به زودی در اختیار شما عزیزان قرار خواهیم داد) به این شکل که یک فایل Customers.js ایجاد کنید و کدهای JS را در آن کپی کنید. (در اینجا ما دو دکه برای کار هماهنگ سازی ایجاد کرده ایم)


<code class="language-csharp"><button id="btnAddCustomer">
       Add Customer</button><button id="btnDeleteDB">
       Clear Local DB</button><button id="btnSyncLocal">
       Sync Local DB from Server DB</button><button id="btnSyncServer">
       Sync Server DB from Local DB</button>



  • هماهنگ سازی local DB from Server DB


$('#btnSyncLocal').click(function () {
       $.ajax({
           url: 'api/service?revision=' + localStorage.customerRevision,
           type: 'GET',
           dataType: 'json',
           success: function (data) {
               if (data.Revision == localStorage.customerRevision) {
                   alert('You are already working on the latest version.');
               }
               else {
                   syncData(data);                   
               }
           }
       });
   });




  • هماهنگ سازی server DB from Local DB

$('#btnSyncServer').click(function () {
       var customers = [];
       db.linq.from(config.objectStoreName).select().then(function () {
           if (customers.length > 0) {
               var postData = { revision: parseInt(localStorage.customerRevision, 10), appID: config.appID, customers: customers };
               $.ajax({
                   url: 'api/service',
                   type: 'POST',
                   dataType: 'json',
                   contentType: "application/json",
                   data: JSON.stringify(postData),
                   success: function (data) {
                       if (data.Revision == localStorage.customerRevision) {
                           alert('There is newer version on the server. Please Sync from server first.');
                       }
                       else {
                           syncData(data);                           
                       }
                   }
               });
           }
           else {
               alert('There is no change in data after your last synchronization.');
           }
       }, handleError, function (data) {
           if (data.Revision == -1) {
               customers.push(data);
           }
       });
   });








در اینجا از متد syncData برای تغییر و به روز رسانی داده های local DB استفاده می کنیم


function syncData(data) {
    var emails = [];
    db.linq.from(config.objectStoreName).select(["Email"]).then(function () {
        $.each(data.Customers, function () {
            if ($.inArray(this.Email, emails) > -1) {
                //update
                db.linq.from(config.objectStoreName).update(this).then(function (data) {
                }, handleError);
            }
            else {
                //insert
                db.linq.from(config.objectStoreName).insert(this).then(function (data) {
                }, handleError);
            }
        });
        //Rebind Grid
        $('#tblCustomer').remove();
        InitializeData();
        localStorage.customerRevision = data.Revision;
        alert('The synchronization has been completed successfully.');
    }, handleError, function (data) {
        emails.push(data.Email);
    });  
}







هماهنگ سازی داده ها:

html5 client server architecture diagram

جریان درخواست را از چپ به راست در نمودار بالا در نظر بگیرید.

  • فرض کنید server DB و Client A در ابتدا با Revision 3 همگام هستند و دارای رکورد P و Q هستند. در سمت client، revision با استفاده از localstorage ذخیره می شود.
  • حال Client A مقدار Q را به Revision = -1 تغییر می دهد
  • Client A رکورد جدیدی به نام R ایجاد می کند و مقادیر آن را به Revision = -1 and CustomerID = -1 تغییر می دهد
  • سپس Client A بر روی Sync Server DB from LocalDB کلیک می کند و مقادیر تمام داده ها از Revision = -1 در web api با مقدار Revision = 3 تغییر می یابد.
  • حال در سرور، این Revision با Revision اصلی مقایسه می شود و وقتی که دید مقادیر یکی است شروع به ذخیره کردن داده ها می کند.
  • در سرور، ایمیل برای تمام رکوردها چک می شود. برای ایمیل جدید یک رکورد جدید و برای ایمیل های موجود مقدار revision = 4 بررسی می شود.
  • سرور، Revision های جدید را همراه با رکوردهای ثبت شده به client ارسال می کند.
  • Client این Revision های جدید را بررسی و سپس داده ها را بروز می کند و revision(4) را در localstorage ذخیره می کند.
  • کلاینت بعدی به نام client B رکوردی به نام S ایجاد و مقدار آن را Revision = -1 تعریف می کند.
  • سپس Client B بر روی Sync Server DB from LocalDB کلیک می کند و مقادیر تمام داده ها (اینجا فقط S) از Revision = -1 در web api با همان مقدار Revision = -1 تغییر می یابد.
  • سرور مقدار Revision را با Revision اصلی مقایسه می کند و متوجه می شود که مقادیر یکی نیست.

به این شکل:

Server Revision = 4, Client Revision = -1))

  • بنابراین همان Revision = -1 را باز به کلاینت بر میگرداند.
  • کلاینت مقدار Revision فعلی را با Revision اصلی چک می کند و متوجه می شود که مقادیر یکی هستند و کاربر پیغام بروز رسانی داده ها را دریافت می کند.
  • حال Client B بر روی Sync Client DB from Server DB کلیک می کند و باز سرور مقادیر Revision را چک می کند. اگر که -1 باشد تمام مقادیر همراه با شماره ی آن ها را باز می گرداند.
  • Client B چک می کند و اگر مقادیر داده ها یکی بود پیغام no change را به کاربر نشان می دهد. اما اگر یکی نبود بروز رسانی را انجام نمی دهد و همان مقدار اصلی Revision در localstorage باقی می ماند.
  • سپس باز Client B بر روی Sync Server DB from LocalDB کلیک می کند و مقادیر تمام داده ها (اینجا فقط S) از Revision = -1 در web api با مقدار Revision = 4 تغییر می یابد.
  • سرور مقادیر Revision ها را چک و رکورد S را با مقدار Revision =5 اضافه می کند.
  • حال Client B باز Revision چک می کند و متوجه می شود که Revision آخری بزرگتر از Revision فعلی است. بنابراین Revision جدید را با مقدار revision(5) در localstorage ذخیره می کند.
  • حال اگر Client A بر روی Sync Client DB from Server DB کلیک کند با Revision 5 بروز خواهد شد.

حذف کوردها:

فرض کنید که Client A رکورد Q را حذف کرده است. از آنجایی که این رکورد در پایگاه داده قبلاً ذخیره شده است بنابراین به عنوان IsDeleted = 1 در Local DB مشخص می شود. با کلیک بر روی Sync Server DB from LocalDB این رکورد نیز آپدیت خواهد شد. ولی وقتی کاملاً حذف خواهد شد که با Client B نیز همگام سازی شود و سپس از کل شبکه حذف خواهد شد.

شما می توانید source code این آموزش را از اینجا دانلود کنید

" اگر این مقاله مورد توجه شما قرار گرفته است با دوستان خود به اشتراک بگذارید"

" با تشکر، مجموعه ABLY"

نظرات یا سوالات خودرا با ما درمیان بگذارید

0912 097 5516 :شماره تماس
0713 625 1757 :شماره تماس