Bagikan melalui


High-Frequency Realtime dengan SignalR 1.x

oleh Patrick Fletcher

Peringatan

Dokumentasi ini bukan untuk versi terbaru SignalR. Lihat ASP.NET Core SignalR.

Tutorial ini menunjukkan cara membuat aplikasi web yang menggunakan ASP.NET SignalR untuk menyediakan fungsionalitas olahpesan frekuensi tinggi. Olahpesan frekuensi tinggi dalam hal ini berarti pembaruan yang dikirim pada tingkat tetap; dalam kasus aplikasi ini, hingga 10 pesan per detik.

Aplikasi yang akan Anda buat dalam tutorial ini menampilkan bentuk yang dapat diseret pengguna. Posisi bentuk di semua browser terhubung lainnya kemudian akan diperbarui agar sesuai dengan posisi bentuk yang diseret menggunakan pembaruan berwaktu.

Konsep yang diperkenalkan dalam tutorial ini memiliki aplikasi dalam game real-time dan aplikasi simulasi lainnya.

Komentar pada tutorial dipersilakan. Jika Anda memiliki pertanyaan yang tidak terkait langsung dengan tutorial, Anda dapat mempostingnya ke forum ASP.NET SignalR atau StackOverflow.com.

Gambaran Umum

Tutorial ini menunjukkan cara membuat aplikasi yang berbagi status objek dengan browser lain secara real time. Aplikasi yang akan kita buat disebut MoveShape. Halaman MoveShape akan menampilkan elemen Html Div yang dapat diseret pengguna; ketika pengguna menyeret Div, posisi barunya akan dikirim ke server, yang kemudian akan memberi tahu semua klien lain yang terhubung untuk memperbarui posisi bentuk agar cocok.

Cuplikan layar memperlihatkan halaman aplikasi MoveShape.

Aplikasi yang dibuat dalam tutorial ini didasarkan pada demo oleh Damian Edwards. Video yang berisi demo ini dapat dilihat di sini.

Tutorial akan dimulai dengan menunjukkan cara mengirim pesan SignalR dari setiap peristiwa yang diaktifkan saat bentuk diseret. Setiap klien yang terhubung kemudian akan memperbarui posisi versi lokal bentuk setiap kali pesan diterima.

Meskipun aplikasi akan berfungsi menggunakan metode ini, ini bukan model pemrograman yang direkomendasikan, karena tidak akan ada batas atas jumlah pesan yang dikirim, sehingga klien dan server bisa kewalahan dengan pesan dan performa akan menurun. Animasi yang ditampilkan pada klien juga akan terputus-putus, karena bentuk akan dipindahkan langsung oleh setiap metode, daripada bergerak dengan lancar ke setiap lokasi baru. Bagian tutorial selanjutnya akan menunjukkan cara membuat fungsi timer yang membatasi laju maksimum di mana pesan dikirim oleh klien atau server, dan cara memindahkan bentuk dengan lancar di antara lokasi. Versi akhir aplikasi yang dibuat dalam tutorial ini dapat diunduh dari Galeri Kode.

Tutorial ini berisi bagian-bagian berikut:

Prasyarat

Tutorial ini memerlukan Visual Studio 2012 atau Visual Studio 2010. Jika Visual Studio 2010 digunakan, proyek akan menggunakan .NET Framework 4 daripada .NET Framework 4,5.

Jika Anda menggunakan Visual Studio 2012, disarankan agar Anda menginstal pembaruan ASP.NET dan Web Tools 2012.2. Pembaruan ini berisi fitur baru seperti penyempurnaan penerbitan, fungsionalitas baru, dan templat baru.

Jika Anda memiliki Visual Studio 2010, pastikan NuGet diinstal.

Membuat proyek

Di bagian ini, kita akan membuat proyek di Visual Studio.

  1. Dari menu File klik Proyek Baru.

  2. Dalam kotak dialog Proyek Baru , perluas C# di bawah Templat dan pilih Web.

  3. Pilih templat Aplikasi Web Kosong ASP.NET , beri nama proyek MoveShapeDemo, dan klik OK.

    Membuat proyek baru

Menambahkan Paket NuGet SignalR dan JQuery.UI

Anda dapat menambahkan fungsionalitas SignalR ke proyek dengan menginstal paket NuGet. Tutorial ini juga akan menggunakan paket JQuery.UI untuk memungkinkan bentuk diseret dan dianimasikan.

  1. Klik Alat | Manajer Paket NuGet | Konsol Manajer Paket.

  2. Masukkan perintah berikut di manajer paket.

    Install-Package Microsoft.AspNet.SignalR -Version 1.1.3
    

    Paket SignalR menginstal sejumlah paket NuGet lainnya sebagai dependensi. Setelah penginstalan selesai, Anda memiliki semua komponen server dan klien yang diperlukan untuk menggunakan SignalR dalam aplikasi ASP.NET.

  3. Masukkan perintah berikut ke konsol manajer paket untuk menginstal paket JQuery dan JQuery.UI.

    Install-Package jQuery.ui.combined
    

Membuat aplikasi dasar

Di bagian ini, kita akan membuat aplikasi browser yang mengirim lokasi bentuk ke server selama setiap peristiwa pemindahan mouse. Server kemudian menyiarkan informasi ini ke semua klien lain yang terhubung saat diterima. Kami akan memperluas aplikasi ini di bagian selanjutnya.

  1. Di Penjelajah Solusi, klik kanan pada proyek dan pilih Tambahkan, Kelas.... Beri nama kelas MoveShapeHub dan klik Tambahkan.

  2. Ganti kode di kelas MoveShapeHub baru dengan kode berikut.

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using Microsoft.AspNet.SignalR;
    using Microsoft.AspNet.SignalR.Hubs;
    using Newtonsoft.Json;
    
    namespace MoveShapeDemo
    {
        public class MoveShapeHub : Hub
        {
            public void UpdateModel(ShapeModel clientModel)
            {
                clientModel.LastUpdatedBy = Context.ConnectionId;
                // Update the shape model within our broadcaster
                Clients.AllExcept(clientModel.LastUpdatedBy).updateShape(clientModel);
            }
        }
        public class ShapeModel
        {
            // We declare Left and Top as lowercase with 
            // JsonProperty to sync the client and server models
            [JsonProperty("left")]
            public double Left { get; set; }
    
            [JsonProperty("top")]
            public double Top { get; set; }
    
            // We don't want the client to get the "LastUpdatedBy" property
            [JsonIgnore]
            public string LastUpdatedBy { get; set; }
        }
    }
    

    Kelas MoveShapeHub di atas adalah implementasi dari hub SignalR. Seperti dalam tutorial Memulai SignalR , hub memiliki metode yang akan dipanggil klien secara langsung. Dalam hal ini, klien akan mengirim objek yang berisi koordinat X dan Y baru dari bentuk ke server, yang kemudian disiarkan ke semua klien lain yang terhubung. SignalR akan secara otomatis menserialisasikan objek ini menggunakan JSON.

    Objek yang akan dikirim ke klien (ShapeModel) berisi anggota untuk menyimpan posisi bentuk. Versi objek di server juga berisi anggota untuk melacak data klien mana yang disimpan, sehingga klien tertentu tidak akan dikirimi data mereka sendiri. Anggota ini menggunakan atribut untuk mencegahnya diserialisasikan JsonIgnore dan dikirim ke klien.

  3. Selanjutnya, kita akan menyiapkan hub saat aplikasi dimulai. Di Penjelajah Solusi, klik kanan proyek, lalu klik Tambahkan | Kelas Aplikasi Global. Terima nama default Global dan klik OK.

    Tambahkan Kelas Aplikasi Global

  4. Tambahkan pernyataan berikut using setelah pernyataan yang disediakan menggunakan di kelas Global.asax.cs.

    using System.Web.Routing;
    
  5. Tambahkan baris kode berikut dalam Application_Start metode kelas Global untuk mendaftarkan rute default untuk SignalR.

    RouteTable.Routes.MapHubs();
    

    File global.asax Anda akan terlihat seperti berikut ini:

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Web;
    using System.Web.Security;
    using System.Web.SessionState;
    
    using System.Web.Routing;
    
    namespace MoveShapeDemo
    {
        public class Global : System.Web.HttpApplication
        {
            protected void Application_Start(object sender, EventArgs e)
            {
                RouteTable.Routes.MapHubs();
            }
        }
    }
    
  6. Selanjutnya, kita akan menambahkan klien. Di Penjelajah Solusi, klik kanan proyek, lalu klik Tambahkan | Item Baru. Dalam dialog Tambahkan Item Baru , pilih Halaman Html. Beri halaman nama yang sesuai (seperti Default.html) dan klik Tambahkan.

  7. Di Penjelajah Solusi, klik kanan halaman yang baru saja Anda buat dan klik Atur sebagai Halaman Mulai.

  8. Ganti kode default di halaman HTML dengan cuplikan kode berikut.

    Catatan

    Verifikasi bahwa referensi skrip di bawah ini cocok dengan paket yang ditambahkan ke proyek Anda di folder Skrip. Di Visual Studio 2010, versi JQuery dan SignalR yang ditambahkan ke proyek mungkin tidak cocok dengan nomor versi di bawah ini.

    <!DOCTYPE html>
    <html>
    <head>
        <title>SignalR MoveShape Demo</title>
        <style>
            #shape {
                width: 100px;
                height: 100px;
                background-color: #FF0000;
            }
        </style>
    </head>
    <body>
    <script src="Scripts/jquery-1.6.4.js"></script>
    <script src="Scripts/jquery-ui-1.10.2.js"></script>
    <script src="Scripts/jquery.signalR-1.0.1.js"></script>
    <script src="/signalr/hubs"></script>
    <script>
     $(function () {
                var moveShapeHub = $.connection.moveShapeHub,
                $shape = $("#shape"),
    
                shapeModel = {
                    left: 0,
                    top: 0
                };
    
                moveShapeHub.client.updateShape = function (model) {
                    shapeModel = model;
                    $shape.css({ left: model.left, top: model.top });
                };
    
                $.connection.hub.start().done(function () {
                    $shape.draggable({
                        drag: function () {
                            shapeModel = $shape.offset();
                            moveShapeHub.server.updateModel(shapeModel);
                        }
                    });
                });
            });
    </script>
    
        <div id="shape" />
    </body>
    </html>
    

    Kode HTML dan JavaScript di atas membuat Div merah yang disebut Bentuk, memungkinkan perilaku penyeretan bentuk menggunakan pustaka jQuery, dan menggunakan peristiwa bentuk drag untuk mengirim posisi bentuk ke server.

  9. Mulai aplikasi dengan menekan F5. Salin URL halaman, dan tempelkan ke jendela browser kedua. Seret bentuk di salah satu jendela browser; bentuk di jendela browser lain harus dipindahkan.

    Cuplikan layar memperlihatkan bagaimana bentuk yang Anda seret dalam satu jendela browser bergerak di jendela lain.

Menambahkan perulangan klien

Karena mengirim lokasi bentuk pada setiap peristiwa pemindahan mouse akan membuat jumlah lalu lintas jaringan yang tidak perlu, pesan dari klien perlu dibatasi. Kita akan menggunakan fungsi javascript setInterval untuk menyiapkan perulangan yang mengirim informasi posisi baru ke server pada tingkat tetap. Perulangan ini adalah representasi yang sangat mendasar dari "perulangan game", fungsi yang berulang kali disebut yang mendorong semua fungsionalitas game atau simulasi lainnya.

  1. Perbarui kode klien di halaman HTML agar sesuai dengan cuplikan kode berikut.

    <!DOCTYPE html>
    <html>
    <head>
        <title>SignalR MoveShape Demo</title>
        <style>
            #shape {
                width: 100px;
                height: 100px;
                background-color: #FF0000;
            }
        </style>
    
    </head>
    <body>
    <script src="Scripts/jquery-1.6.4.js"></script>
    <script src="Scripts/jquery-ui-1.10.2.js"></script>
    <script src="Scripts/jquery.signalR-1.0.1.js"></script>
    <script src="/signalr/hubs"></script>
    <script>
            $(function () {
                var moveShapeHub = $.connection.moveShapeHub,
                    $shape = $("#shape"),
                    // Send a maximum of 10 messages per second 
                    // (mouse movements trigger a lot of messages)
                    messageFrequency = 10, 
                    // Determine how often to send messages in
                    // time to abide by the messageFrequency
                    updateRate = 1000 / messageFrequency, 
                    shapeModel = {
                        left: 0,
                        top: 0
                    },
                    moved = false;
    
                moveShapeHub.client.updateShape = function (model) {
                    shapeModel = model;
                    $shape.css({ left: model.left, top: model.top });
                };
    
                $.connection.hub.start().done(function () {
                    $shape.draggable({
                        drag: function () {
                            shapeModel = $shape.offset();
                            moved = true;
                        }
                    });
    
                    // Start the client side server update interval
                    setInterval(updateServerModel, updateRate);
                });
    
                function updateServerModel() {
                    // Only update server if we have a new movement
                    if (moved) {
                        moveShapeHub.server.updateModel(shapeModel);
                        moved = false;
                    }
                }
            });
    </script>
    
        <div id="shape" />
    </body>
    </html>
    

    Pembaruan di atas menambahkan updateServerModel fungsi , yang dipanggil pada frekuensi tetap. Fungsi ini mengirimkan data posisi ke server setiap kali moved bendera menunjukkan bahwa ada data posisi baru untuk dikirim.

  2. Mulai aplikasi dengan menekan F5. Salin URL halaman, dan tempelkan ke jendela browser kedua. Seret bentuk di salah satu jendela browser; bentuk di jendela browser lain harus dipindahkan. Karena jumlah pesan yang dikirim ke server akan dibatasi, animasi tidak akan tampak semulus di bagian sebelumnya.

    Cuplikan layar memperlihatkan bagaimana bentuk yang Anda seret di satu jendela browser bergerak di jendela lain saat Anda menambahkan perulangan klien.

Menambahkan perulangan server

Dalam aplikasi saat ini, pesan yang dikirim dari server ke klien keluar sesering yang diterima. Ini menyajikan masalah serupa seperti yang terlihat pada klien; pesan dapat dikirim lebih sering daripada yang diperlukan, dan koneksi dapat menjadi banjir sebagai akibatnya. Bagian ini menjelaskan cara memperbarui server untuk mengimplementasikan timer yang membatasi laju pesan keluar.

  1. Ganti konten MoveShapeHub.cs dengan cuplikan kode berikut.

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Web;
    
    using System.Threading;
    using Microsoft.AspNet.SignalR;
    
    using Newtonsoft.Json;
    
    namespace MoveShapeDemo
    {
        public class Broadcaster
        {
            private readonly static Lazy<Broadcaster> _instance = 
                new Lazy<Broadcaster>(() => new Broadcaster());
            // We're going to broadcast to all clients a maximum of 25 times per second
            private readonly TimeSpan BroadcastInterval = 
                TimeSpan.FromMilliseconds(40); 
            private readonly IHubContext _hubContext;
            private Timer _broadcastLoop;
            private ShapeModel _model;
            private bool _modelUpdated;
    
            public Broadcaster()
            {
                // Save our hub context so we can easily use it 
                // to send to its connected clients
                _hubContext = GlobalHost.ConnectionManager.GetHubContext<MoveShapeHub>();
    
                _model = new ShapeModel();
                _modelUpdated = false;
    
                // Start the broadcast loop
                _broadcastLoop = new Timer(
                    BroadcastShape, 
                    null, 
                    BroadcastInterval, 
                    BroadcastInterval);
            }
    
            public void BroadcastShape(object state)
            {
                // No need to send anything if our model hasn't changed
                if (_modelUpdated)
                {
                    // This is how we can access the Clients property 
                    // in a static hub method or outside of the hub entirely
                    _hubContext.Clients.AllExcept(_model.LastUpdatedBy).updateShape(_model);
                    _modelUpdated = false;
                }
            }
    
            public void UpdateShape(ShapeModel clientModel)
            {
                _model = clientModel;
                _modelUpdated = true;
            }
    
            public static Broadcaster Instance
            {
                get
                {
                    return _instance.Value;
                }
            }
        }
        
        public class MoveShapeHub : Hub
        {
            // Is set via the constructor on each creation
            private Broadcaster _broadcaster;
    
            public MoveShapeHub()
                : this(Broadcaster.Instance)
            {
            }
    
            public MoveShapeHub(Broadcaster broadcaster)
            {
                _broadcaster = broadcaster;
            }
    
            public void UpdateModel(ShapeModel clientModel)
            {
                clientModel.LastUpdatedBy = Context.ConnectionId;
                // Update the shape model within our broadcaster
                _broadcaster.UpdateShape(clientModel);
            }
        }
        public class ShapeModel
        {
            // We declare Left and Top as lowercase with 
            // JsonProperty to sync the client and server models
            [JsonProperty("left")]
            public double Left { get; set; }
    
            [JsonProperty("top")]
            public double Top { get; set; }
    
            // We don't want the client to get the "LastUpdatedBy" property
            [JsonIgnore]
            public string LastUpdatedBy { get; set; }
        }
        
    }
    

    Kode di atas memperluas klien untuk menambahkan Broadcaster kelas , yang membatasi pesan keluar menggunakan Timer kelas dari .NET framework.

    Karena hub itu sendiri bersifat transitory (dibuat setiap kali diperlukan), Broadcaster hub akan dibuat sebagai singleton. Inisialisasi malas (diperkenalkan dalam .NET 4) digunakan untuk menunda pembuatannya sampai diperlukan, memastikan bahwa instans hub pertama benar-benar dibuat sebelum timer dimulai.

    Panggilan ke fungsi klien UpdateShape kemudian dipindahkan dari metode hub UpdateModel , sehingga tidak lagi dipanggil segera setiap kali pesan masuk diterima. Sebaliknya, pesan kepada klien akan dikirim dengan tarif 25 panggilan per detik, dikelola oleh timer _broadcastLoop dari dalam Broadcaster kelas.

    Terakhir, alih-alih memanggil metode klien dari hub secara langsung, Broadcaster kelas perlu mendapatkan referensi ke hub operasi saat ini (_hubContext) menggunakan GlobalHost.

  2. Mulai aplikasi dengan menekan F5. Salin URL halaman, dan tempelkan ke jendela browser kedua. Seret bentuk di salah satu jendela browser; bentuk di jendela browser lain harus dipindahkan. Tidak akan ada perbedaan yang terlihat di browser dari bagian sebelumnya, tetapi jumlah pesan yang dikirim ke klien akan dibatasi.

    Cuplikan layar memperlihatkan bagaimana bentuk yang Anda seret dalam satu jendela browser bergerak di jendela lain saat Anda menambahkan perulangan server.

Menambahkan animasi halus pada klien

Aplikasi ini hampir selesai, tetapi kita dapat melakukan satu perbaikan lagi, dalam gerakan bentuk pada klien karena dipindahkan sebagai respons terhadap pesan server. Daripada mengatur posisi bentuk ke lokasi baru yang diberikan oleh server, kita akan menggunakan fungsi pustaka animate UI JQuery untuk memindahkan bentuk dengan lancar antara posisinya saat ini dan baru.

  1. Perbarui metode klien updateShape agar terlihat seperti kode yang disorot di bawah ini:

    <!DOCTYPE html>
    <html>
    <head>
        <title>SignalR MoveShape Demo</title>
        <style>
            #shape {
                width: 100px;
                height: 100px;
                background-color: #FF0000;
            }
        </style>
    
    </head>
    <body>
    <script src="Scripts/jquery-1.6.4.js"></script>
    <script src="Scripts/jquery-ui-1.10.2.js"></script>
    <script src="Scripts/jquery.signalR-1.0.1.js"></script>
    <script src="/signalr/hubs"></script>
    <script>
            $(function () {
                var moveShapeHub = $.connection.moveShapeHub,
                    $shape = $("#shape"),
                    // Send a maximum of 10 messages per second 
                    // (mouse movements trigger a lot of messages)
                    messageFrequency = 10, 
                    // Determine how often to send messages in
                    // time to abide by the messageFrequency
                    updateRate = 1000 / messageFrequency, 
                    shapeModel = {
                        left: 0,
                        top: 0
                    },
                    moved = false;
    
                 moveShapeHub.client.updateShape = function (model) {
                     shapeModel = model;
                     // Gradually move the shape towards the new location (interpolate)
                     // The updateRate is used as the duration because by the time 
                     // we get to the next location we want to be at the "last" location
                     // We also clear the animation queue so that we start a new 
                     // animation and don't lag behind.
                     $shape.animate(shapeModel, { duration: updateRate, queue: false });
                };
    
                $.connection.hub.start().done(function () {
                    $shape.draggable({
                        drag: function () {
                            shapeModel = $shape.offset();
                            moved = true;
                        }
                    });
    
                    // Start the client side server update interval
                    setInterval(updateServerModel, updateRate);
                });
    
                function updateServerModel() {
                    // Only update server if we have a new movement
                    if (moved) {
                        moveShapeHub.server.updateModel(shapeModel);
                        moved = false;
                    }
                }
            });
    </script>
    
        <div id="shape" />
    </body>
    </html>
    

    Kode di atas memindahkan bentuk dari lokasi lama ke yang baru yang diberikan oleh server selama interval animasi (dalam hal ini, 100 milidetik). Animasi sebelumnya yang berjalan pada bentuk dibersihkan sebelum animasi baru dimulai.

  2. Mulai aplikasi dengan menekan F5. Salin URL halaman, dan tempelkan ke jendela browser kedua. Seret bentuk di salah satu jendela browser; bentuk di jendela browser lain harus dipindahkan. Pergerakan bentuk di jendela lain akan tampak kurang dendeng karena gerakannya diinterpolasi dari waktu ke waktu daripada diatur sekali per pesan masuk.

    Cuplikan layar memperlihatkan bagaimana bentuk yang Anda seret dalam satu jendela browser bergerak di jendela lain saat Anda menambahkan animasi yang halus pada klien.

Langkah-langkah Lebih Lanjut

Dalam tutorial ini, Anda telah mempelajari cara memprogram aplikasi SignalR yang mengirim pesan frekuensi tinggi antara klien dan server. Paradigma komunikasi ini berguna untuk mengembangkan game online dan simulasi lainnya, seperti game ShootR yang dibuat dengan SignalR.

Aplikasi lengkap yang dibuat dalam tutorial ini dapat diunduh dari Code Gallery.

Untuk mempelajari selengkapnya tentang konsep pengembangan SignalR, kunjungi situs berikut untuk kode sumber dan sumber daya SignalR: