Bagikan melalui


Tutorial: Siaran server dengan SignalR 2

Peringatan

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

Tutorial ini menunjukkan cara membuat aplikasi web yang menggunakan ASP.NET SignalR 2 untuk menyediakan fungsionalitas siaran server. Siaran server berarti bahwa server memulai komunikasi yang dikirim ke klien.

Aplikasi yang akan Anda buat dalam tutorial ini mensimulasikan ticker stok, skenario umum untuk fungsionalitas siaran server. Secara berkala, server secara acak memperbarui harga stok dan menyiarkan pembaruan ke semua klien yang terhubung. Di browser, angka dan simbol dalam Perubahan dan % kolom berubah secara dinamis sebagai respons terhadap pemberitahuan dari server. Jika Anda membuka browser tambahan ke URL yang sama, semuanya menampilkan data yang sama dan perubahan yang sama pada data secara bersamaan.

Cuplikan layar memperlihatkan bagaimana beberapa browser web menampilkan data yang diperbarui yang sama secara bersamaan.

Di tutorial ini, Anda akan:

  • Membuat proyek
  • Menyiapkan kode server
  • Memeriksa kode server
  • Menyiapkan kode klien
  • Memeriksa kode klien
  • Menguji aplikasi
  • Aktifkan pencatatan log

Penting

Jika Anda tidak ingin bekerja melalui langkah-langkah membangun aplikasi, Anda dapat menginstal paket SignalR.Sample dalam proyek Empty ASP.NET Web Application baru. Jika Anda menginstal paket NuGet tanpa melakukan langkah-langkah dalam tutorial ini, Anda harus mengikuti instruksi dalam file readme.txt . Untuk menjalankan paket, Anda perlu menambahkan kelas startup OWIN yang memanggil ConfigureSignalR metode dalam paket yang diinstal. Anda akan menerima kesalahan jika Anda tidak menambahkan kelas startup OWIN. Lihat bagian Instal sampel StockTicker di artikel ini.

Prasyarat

Membuat proyek

Bagian ini memperlihatkan cara menggunakan Visual Studio 2017 untuk membuat Aplikasi Web ASP.NET kosong.

  1. Di Visual Studio, buat Aplikasi Web ASP.NET.

    Cuplikan layar memperlihatkan cara membuat Aplikasi Web ASP.NET.

  2. Di jendela Aplikasi Web ASP.NET Baru - SignalR.StockTicker , biarkan Kosong dipilih dan pilih OK.

Menyiapkan kode server

Di bagian ini, Anda menyiapkan kode yang berjalan di server.

Membuat kelas Stock

Anda mulai dengan membuat kelas model Stok yang akan Anda gunakan untuk menyimpan dan mengirimkan informasi tentang stok.

  1. Di Penjelajah Solusi, klik kanan proyek dan pilih Tambahkan>Kelas.

  2. Beri nama kelas Stock dan tambahkan ke proyek.

  3. Ganti kode dalam file Stock.cs dengan kode ini:

    using System;
    
    namespace SignalR.StockTicker
    {
        public class Stock
        {
            private decimal _price;
    
            public string Symbol { get; set; }
    
            public decimal Price
            {
                get
                {
                    return _price;
                }
                set
                {
                    if (_price == value)
                    {
                        return;
                    }
    
                    _price = value;
    
                    if (DayOpen == 0)
                    {
                        DayOpen = _price;
                    }
                }
            }
    
            public decimal DayOpen { get; private set; }
    
            public decimal Change
            {
                get
                {
                    return Price - DayOpen;
                }
            }
    
            public double PercentChange
            {
                get
                {
                    return (double)Math.Round(Change / Price, 4);
                }
            }
        }
    }
    

    Dua properti yang akan Anda tetapkan saat membuat saham adalah Symbol (misalnya, MSFT untuk Microsoft) dan Price. Properti lainnya bergantung pada bagaimana dan kapan Anda mengatur Price. Pertama kali Anda mengatur Price, nilai akan disebarluaskan ke DayOpen. Setelah itu, saat Anda mengatur Price, aplikasi menghitung Change nilai properti dan PercentChange berdasarkan perbedaan antara Price dan DayOpen.

Membuat kelas StockTickerHub dan StockTicker

Anda akan menggunakan SignalR Hub API untuk menangani interaksi server-ke-klien. Kelas StockTickerHub yang berasal dari kelas SignalR Hub akan menangani penerimaan koneksi dan panggilan metode dari klien. Anda juga perlu mempertahankan data stok dan menjalankan Timer objek . Objek Timer akan secara berkala memicu pembaruan harga secara independen dari koneksi klien. Anda tidak dapat menempatkan fungsi-fungsi ini di Hub kelas , karena Hub bersifat sementara. Aplikasi ini membuat instans Hub kelas untuk setiap tugas di hub, seperti koneksi dan panggilan dari klien ke server. Jadi mekanisme yang menyimpan data stok, memperbarui harga, dan menyiarkan pembaruan harga harus berjalan di kelas terpisah. Anda akan memberi nama kelas StockTicker.

Penyiaran dari StockTicker

Anda hanya ingin satu instans StockTicker kelas berjalan di server, jadi Anda harus menyiapkan referensi dari setiap StockTickerHub instans ke instans singleton StockTicker . Kelas StockTicker harus disiarkan ke klien karena memiliki data stok dan memicu pembaruan, tetapi StockTicker bukan Hub kelas. Kelas StockTicker harus mendapatkan referensi ke objek konteks koneksi SignalR Hub. Kemudian dapat menggunakan objek konteks koneksi SignalR untuk menyiarkan ke klien.

Membuat StockTickerHub.cs

  1. Di Penjelajah Solusi, klik kanan proyek dan pilih Tambahkan>Item Baru.

  2. Di Tambahkan Item Baru - SignalR.StockTicker, pilihVisual C#>Web>SignalRterinstal> lalu pilih SignalR Hub Class (v2).

  3. Beri nama kelas StockTickerHub dan tambahkan ke proyek.

    Langkah ini membuat file kelas StockTickerHub.cs . Secara bersamaan, ia menambahkan sekumpulan file skrip dan referensi rakitan yang mendukung SignalR ke proyek.

  4. Ganti kode dalam file StockTickerHub.cs dengan kode ini:

    using System.Collections.Generic;
    using Microsoft.AspNet.SignalR;
    using Microsoft.AspNet.SignalR.Hubs;
    
    namespace SignalR.StockTicker
    {
        [HubName("stockTickerMini")]
        public class StockTickerHub : Hub
        {
            private readonly StockTicker _stockTicker;
    
            public StockTickerHub() : this(StockTicker.Instance) { }
    
            public StockTickerHub(StockTicker stockTicker)
            {
                _stockTicker = stockTicker;
            }
    
            public IEnumerable<Stock> GetAllStocks()
            {
                return _stockTicker.GetAllStocks();
            }
        }
    }
    
  5. Simpan file.

Aplikasi ini menggunakan kelas Hub untuk menentukan metode yang dapat dipanggil klien di server. Anda mendefinisikan satu metode: GetAllStocks(). Ketika klien awalnya terhubung ke server, klien akan memanggil metode ini untuk mendapatkan daftar semua saham dengan harga mereka saat ini. Metode ini dapat berjalan secara sinkron dan mengembalikan IEnumerable<Stock> karena mengembalikan data dari memori.

Jika metode harus mendapatkan data dengan melakukan sesuatu yang akan melibatkan menunggu, seperti pencarian database atau panggilan layanan web, Anda akan menentukan Task<IEnumerable<Stock>> sebagai nilai pengembalian untuk mengaktifkan pemrosesan asinkron. Untuk informasi selengkapnya, lihat ASP.NET Panduan API SignalR Hubs - Server - Kapan harus dijalankan secara asinkron.

Atribut HubName menentukan bagaimana aplikasi akan mereferensikan Hub dalam kode JavaScript pada klien. Nama default pada klien jika Anda tidak menggunakan atribut ini, adalah versi camelCase dari nama kelas, yang dalam hal ini adalah stockTickerHub.

Seperti yang akan Anda lihat nanti saat membuat StockTicker kelas, aplikasi membuat instans database tunggal dari kelas tersebut di properti statisnya Instance . Instans StockTicker singleton itu berada dalam memori tidak peduli berapa banyak klien yang terhubung atau terputus. Instans tersebut GetAllStocks() adalah apa yang digunakan metode untuk mengembalikan informasi stok saat ini.

Membuat StockTicker.cs

  1. Di Penjelajah Solusi, klik kanan proyek dan pilih Tambahkan>Kelas.

  2. Beri nama kelas StockTicker dan tambahkan ke proyek.

  3. Ganti kode dalam file StockTicker.cs dengan kode ini:

    using System;
    using System.Collections.Concurrent;
    using System.Collections.Generic;
    using System.Threading;
    using Microsoft.AspNet.SignalR;
    using Microsoft.AspNet.SignalR.Hubs;
    
    namespace SignalR.StockTicker
    {
        public class StockTicker
        {
            // Singleton instance
            private readonly static Lazy<StockTicker> _instance = new Lazy<StockTicker>(() => new StockTicker(GlobalHost.ConnectionManager.GetHubContext<StockTickerHub>().Clients));
    
            private readonly ConcurrentDictionary<string, Stock> _stocks = new ConcurrentDictionary<string, Stock>();
    
            private readonly object _updateStockPricesLock = new object();
    
            //stock can go up or down by a percentage of this factor on each change
            private readonly double _rangePercent = .002;
    
            private readonly TimeSpan _updateInterval = TimeSpan.FromMilliseconds(250);
            private readonly Random _updateOrNotRandom = new Random();
    
            private readonly Timer _timer;
            private volatile bool _updatingStockPrices = false;
    
            private StockTicker(IHubConnectionContext<dynamic> clients)
            {
                Clients = clients;
    
                _stocks.Clear();
                var stocks = new List<Stock>
                {
                    new Stock { Symbol = "MSFT", Price = 30.31m },
                    new Stock { Symbol = "APPL", Price = 578.18m },
                    new Stock { Symbol = "GOOG", Price = 570.30m }
                };
                stocks.ForEach(stock => _stocks.TryAdd(stock.Symbol, stock));
    
                _timer = new Timer(UpdateStockPrices, null, _updateInterval, _updateInterval);
    
            }
    
            public static StockTicker Instance
            {
                get
                {
                    return _instance.Value;
                }
            }
    
            private IHubConnectionContext<dynamic> Clients
            {
                get;
                set;
            }
    
            public IEnumerable<Stock> GetAllStocks()
            {
                return _stocks.Values;
            }
    
            private void UpdateStockPrices(object state)
            {
                lock (_updateStockPricesLock)
                {
                    if (!_updatingStockPrices)
                    {
                        _updatingStockPrices = true;
    
                        foreach (var stock in _stocks.Values)
                        {
                            if (TryUpdateStockPrice(stock))
                            {
                                BroadcastStockPrice(stock);
                            }
                        }
    
                        _updatingStockPrices = false;
                    }
                }
            }
    
            private bool TryUpdateStockPrice(Stock stock)
            {
                // Randomly choose whether to update this stock or not
                var r = _updateOrNotRandom.NextDouble();
                if (r > .1)
                {
                    return false;
                }
    
                // Update the stock price by a random factor of the range percent
                var random = new Random((int)Math.Floor(stock.Price));
                var percentChange = random.NextDouble() * _rangePercent;
                var pos = random.NextDouble() > .51;
                var change = Math.Round(stock.Price * (decimal)percentChange, 2);
                change = pos ? change : -change;
    
                stock.Price += change;
                return true;
            }
    
            private void BroadcastStockPrice(Stock stock)
            {
                Clients.All.updateStockPrice(stock);
            }
    
        }
    }
    

Karena semua utas akan menjalankan instans kode StockTicker yang sama, kelas StockTicker harus aman untuk utas.

Memeriksa kode server

Jika Anda memeriksa kode server, ini akan membantu Anda memahami cara kerja aplikasi.

Menyimpan instans singleton di bidang statis

Kode menginisialisasi bidang statis _instance yang mendukung properti dengan instans Instance kelas . Karena konstruktor bersifat privat, ini adalah satu-satunya instans kelas yang dapat dibuat aplikasi. Aplikasi ini menggunakan inisialisasi Malas untuk _instance bidang . Ini bukan karena alasan performa. Ini untuk memastikan pembuatan instans aman untuk utas.

private readonly static Lazy<StockTicker> _instance = new Lazy<StockTicker>(() => new StockTicker(GlobalHost.ConnectionManager.GetHubContext<StockTickerHub>().Clients));

public static StockTicker Instance
{
    get
    {
        return _instance.Value;
    }
}

Setiap kali klien terhubung ke server, instans baru kelas StockTickerHub yang berjalan di utas terpisah mendapatkan instans singleton StockTicker dari StockTicker.Instance properti statis, seperti yang Anda lihat sebelumnya di StockTickerHub kelas .

Menyimpan data stok dalam ConcurrentDictionary

Konstruktor menginisialisasi _stocks koleksi dengan beberapa data stok sampel, dan GetAllStocks mengembalikan saham. Seperti yang Anda lihat sebelumnya, koleksi saham ini dikembalikan oleh StockTickerHub.GetAllStocks, yang merupakan metode server di Hub kelas yang dapat dipanggil klien.

private readonly ConcurrentDictionary<string, Stock> _stocks = new ConcurrentDictionary<string, Stock>();
private StockTicker(IHubConnectionContext<dynamic> clients)
{
    Clients = clients;

    _stocks.Clear();
    var stocks = new List<Stock>
    {
        new Stock { Symbol = "MSFT", Price = 30.31m },
        new Stock { Symbol = "APPL", Price = 578.18m },
        new Stock { Symbol = "GOOG", Price = 570.30m }
    };
    stocks.ForEach(stock => _stocks.TryAdd(stock.Symbol, stock));

    _timer = new Timer(UpdateStockPrices, null, _updateInterval, _updateInterval);
}

public IEnumerable<Stock> GetAllStocks()
{
    return _stocks.Values;
}

Koleksi saham didefinisikan sebagai jenis ConcurrentDictionary untuk keamanan utas. Sebagai alternatif, Anda dapat menggunakan objek Kamus dan secara eksplisit mengunci kamus saat Anda membuat perubahan padanya.

Untuk aplikasi sampel ini, tidak apa-apa untuk menyimpan data aplikasi dalam memori dan kehilangan data saat aplikasi membuang StockTicker instans. Dalam aplikasi nyata, Anda akan bekerja dengan penyimpanan data back-end seperti database.

Memperbarui harga saham secara berkala

Konstruktor memulai Timer objek yang secara berkala memanggil metode yang memperbarui harga saham secara acak.

_timer = new Timer(UpdateStockPrices, null, _updateInterval, _updateInterval);

private void UpdateStockPrices(object state)
{
    lock (_updateStockPricesLock)
    {
        if (!_updatingStockPrices)
        {
            _updatingStockPrices = true;

            foreach (var stock in _stocks.Values)
            {
                if (TryUpdateStockPrice(stock))
                {
                    BroadcastStockPrice(stock);
                }
            }

            _updatingStockPrices = false;
        }
    }
}

private bool TryUpdateStockPrice(Stock stock)
{
    // Randomly choose whether to update this stock or not
    var r = _updateOrNotRandom.NextDouble();
    if (r > .1)
    {
        return false;
    }

    // Update the stock price by a random factor of the range percent
    var random = new Random((int)Math.Floor(stock.Price));
    var percentChange = random.NextDouble() * _rangePercent;
    var pos = random.NextDouble() > .51;
    var change = Math.Round(stock.Price * (decimal)percentChange, 2);
    change = pos ? change : -change;

    stock.Price += change;
    return true;
}

TimerUpdateStockPricesmemanggil , yang melewati null dalam parameter status. Sebelum memperbarui harga, aplikasi mengunci _updateStockPricesLock objek. Kode memeriksa apakah utas lain sudah memperbarui harga, dan kemudian memanggil TryUpdateStockPrice setiap saham dalam daftar. Metode memutuskan TryUpdateStockPrice apakah akan mengubah harga saham, dan berapa banyak untuk mengubahnya. Jika harga saham berubah, aplikasi akan memanggil BroadcastStockPrice untuk menyiarkan perubahan harga saham ke semua klien yang terhubung.

Bendera yang _updatingStockPrices ditunjuk volatil untuk memastikannya aman untuk utas.

private volatile bool _updatingStockPrices = false;

Dalam aplikasi nyata, metode ini TryUpdateStockPrice akan memanggil layanan web untuk mencari harganya. Dalam kode ini, aplikasi menggunakan generator angka acak untuk membuat perubahan secara acak.

Mendapatkan konteks SignalR sehingga kelas StockTicker dapat disiarkan ke klien

Karena perubahan harga berasal dari sini dalam StockTicker objek , itu adalah objek yang perlu memanggil metode pada semua klien yang updateStockPrice terhubung. Hub Di kelas , Anda memiliki API untuk memanggil metode klien, tetapi StockTicker tidak berasal dari Hub kelas dan tidak memiliki referensi ke objek apa punHub. Untuk menyiarkan ke klien yang terhubung, StockTicker kelas harus mendapatkan instans konteks SignalR untuk StockTickerHub kelas dan menggunakannya untuk memanggil metode pada klien.

Kode mendapatkan referensi ke konteks SignalR saat membuat instans kelas singleton, meneruskan referensi tersebut ke konstruktor, dan konstruktor meletakkannya di Clients properti .

Ada dua alasan mengapa Anda ingin mendapatkan konteks hanya sekali: mendapatkan konteks adalah tugas yang mahal, dan mendapatkannya sekali memastikan aplikasi mempertahankan urutan pesan yang dimaksudkan yang dikirim ke klien.

private readonly static Lazy<StockTicker> _instance =
    new Lazy<StockTicker>(() => new StockTicker(GlobalHost.ConnectionManager.GetHubContext<StockTickerHub>().Clients));

private StockTicker(IHubConnectionContext<dynamic> clients)
{
    Clients = clients;

    // Remainder of constructor ...
}

private IHubConnectionContext<dynamic> Clients
{
    get;
    set;
}

private void BroadcastStockPrice(Stock stock)
{
    Clients.All.updateStockPrice(stock);
}

Clients Mendapatkan properti konteks dan meletakkannya di StockTickerClient properti memungkinkan Anda menulis kode untuk memanggil metode klien yang terlihat sama seperti di Hub kelas. Misalnya, untuk menyiarkan ke semua klien, Anda dapat menulis Clients.All.updateStockPrice(stock).

Metode updateStockPrice yang Anda panggil BroadcastStockPrice belum ada. Anda akan menambahkannya nanti saat menulis kode yang berjalan pada klien. Anda dapat merujuk ke updateStockPrice sini karena Clients.All bersifat dinamis, yang berarti aplikasi akan mengevaluasi ekspresi saat runtime. Ketika panggilan metode ini dijalankan, SignalR akan mengirim nama metode dan nilai parameter ke klien, dan jika klien memiliki metode bernama updateStockPrice, aplikasi akan memanggil metode tersebut dan meneruskan nilai parameter ke dalamnya.

Clients.All berarti mengirim ke semua klien. SignalR memberi Anda opsi lain untuk menentukan klien atau grup klien mana yang akan dikirim. Untuk informasi selengkapnya, lihat HubConnectionContext.

Mendaftarkan rute SignalR

Server perlu mengetahui URL mana yang akan dicegat dan diarahkan ke SignalR. Untuk melakukannya, tambahkan kelas startup OWIN:

  1. Di Penjelajah Solusi, klik kanan proyek dan pilih Tambahkan>Item Baru.

  2. Di Tambahkan Item Baru - SignalR.StockTicker pilihVisual C#>Webterinstal> lalu pilih Kelas Startup OWIN.

  3. Beri nama kelas Startup dan pilih OK.

  4. Ganti kode default dalam file Startup.cs dengan kode ini:

    using System;
    using System.Threading.Tasks;
    using Microsoft.Owin;
    using Owin;
    
    [assembly: OwinStartup(typeof(SignalR.StockTicker.Startup))]
    
    namespace SignalR.StockTicker
    {
        public class Startup
        {
            public void Configuration(IAppBuilder app)
            {
                // Any connection or hub wire up and configuration should go here
                app.MapSignalR();
            }
    
        }
    }
    

Anda sekarang telah selesai menyiapkan kode server. Di bagian berikutnya, Anda akan menyiapkan klien.

Menyiapkan kode klien

Di bagian ini, Anda menyiapkan kode yang berjalan pada klien.

Membuat halaman HTML dan file JavaScript

Halaman HTML akan menampilkan data dan file JavaScript akan mengatur data.

Membuat StockTicker.html

Pertama, Anda akan menambahkan klien HTML.

  1. Di Penjelajah Solusi, klik kanan proyek dan pilih Tambahkan>Halaman HTML.

  2. Beri nama file StockTicker dan pilih OK.

  3. Ganti kode default dalam file StockTicker.html dengan kode ini:

    <!DOCTYPE html>
    <html xmlns="http://www.w3.org/1999/xhtml">
    <head>
        <title>ASP.NET SignalR Stock Ticker</title>
        <style>
            body {
                font-family: 'Segoe UI', Arial, Helvetica, sans-serif;
                font-size: 16px;
            }
            #stockTable table {
                border-collapse: collapse;
            }
                #stockTable table th, #stockTable table td {
                    padding: 2px 6px;
                }
                #stockTable table td {
                    text-align: right;
                }
            #stockTable .loading td {
                text-align: left;
            }
        </style>
    </head>
    <body>
        <h1>ASP.NET SignalR Stock Ticker Sample</h1>
    
        <h2>Live Stock Table</h2>
        <div id="stockTable">
            <table border="1">
                <thead>
                    <tr><th>Symbol</th><th>Price</th><th>Open</th><th>Change</th><th>%</th></tr>
                </thead>
                <tbody>
                    <tr class="loading"><td colspan="5">loading...</td></tr>
                </tbody>
            </table>
        </div>
    
        <!--Script references. -->
        <!--Reference the jQuery library. -->
        <script src="/Scripts/jquery-1.10.2.min.js" ></script>
        <!--Reference the SignalR library. -->
        <script src="/Scripts/jquery.signalR-2.1.0.js"></script>
        <!--Reference the autogenerated SignalR hub script. -->
        <script src="/signalr/hubs"></script>
        <!--Reference the StockTicker script. -->
        <script src="StockTicker.js"></script>
    </body>
    </html>
    

    HTML membuat tabel dengan lima kolom, baris header, dan baris data dengan sel tunggal yang mencakup kelima kolom. Baris data menunjukkan "memuat..." saat aplikasi dimulai. Kode JavaScript akan menghapus baris tersebut dan menambahkan baris tempatnya dengan data stok yang diambil dari server.

    Tag skrip menentukan:

    • File skrip jQuery.

    • File skrip inti SignalR.

    • File skrip proksi SignalR.

    • File skrip StockTicker yang akan Anda buat nanti.

    Aplikasi ini secara dinamis menghasilkan file skrip proksi SignalR. Ini menentukan URL "/signalr/hubs" dan menentukan metode proksi untuk metode pada kelas Hub, dalam hal ini, untuk StockTickerHub.GetAllStocks. Jika mau, Anda dapat membuat file JavaScript ini secara manual dengan menggunakan Utilitas SignalR. Jangan lupa untuk menonaktifkan pembuatan file dinamis dalam MapHubs panggilan metode.

  4. Di Penjelajah Solusi, perluas Skrip.

    Pustaka skrip untuk jQuery dan SignalR terlihat dalam proyek.

    Penting

    Manajer paket akan menginstal versi skrip SignalR yang lebih baru.

  5. Perbarui referensi skrip di blok kode agar sesuai dengan versi file skrip dalam proyek.

  6. Di Penjelajah Solusi, klik kanan StockTicker.html, lalu pilih Atur sebagai Halaman Mulai.

Membuat StockTicker.js

Sekarang buat file JavaScript.

  1. Di Penjelajah Solusi, klik kanan proyek dan pilih Tambahkan>File JavaScript.

  2. Beri nama file StockTicker dan pilih OK.

  3. Tambahkan kode ini ke file StockTicker.js :

    // A simple templating method for replacing placeholders enclosed in curly braces.
    if (!String.prototype.supplant) {
        String.prototype.supplant = function (o) {
            return this.replace(/{([^{}]*)}/g,
                function (a, b) {
                    var r = o[b];
                    return typeof r === 'string' || typeof r === 'number' ? r : a;
                }
            );
        };
    }
    
    $(function () {
    
        var ticker = $.connection.stockTickerMini, // the generated client-side hub proxy
            up = '▲',
            down = '▼',
            $stockTable = $('#stockTable'),
            $stockTableBody = $stockTable.find('tbody'),
            rowTemplate = '<tr data-symbol="{Symbol}"><td>{Symbol}</td><td>{Price}</td><td>{DayOpen}</td><td>{Direction} {Change}</td><td>{PercentChange}</td></tr>';
    
        function formatStock(stock) {
            return $.extend(stock, {
                Price: stock.Price.toFixed(2),
                PercentChange: (stock.PercentChange * 100).toFixed(2) + '%',
                Direction: stock.Change === 0 ? '' : stock.Change >= 0 ? up : down
            });
        }
    
        function init() {
            ticker.server.getAllStocks().done(function (stocks) {
                $stockTableBody.empty();
                $.each(stocks, function () {
                    var stock = formatStock(this);
                    $stockTableBody.append(rowTemplate.supplant(stock));
                });
            });
        }
    
        // Add a client-side hub method that the server will call
        ticker.client.updateStockPrice = function (stock) {
            var displayStock = formatStock(stock),
                $row = $(rowTemplate.supplant(displayStock));
    
            $stockTableBody.find('tr[data-symbol=' + stock.Symbol + ']')
                .replaceWith($row);
            }
    
        // Start the connection
        $.connection.hub.start().done(init);
    
    });
    

Memeriksa kode klien

Jika Anda memeriksa kode klien, ini akan membantu Anda mempelajari bagaimana kode klien berinteraksi dengan kode server untuk membuat aplikasi berfungsi.

Memulai koneksi

$.connection mengacu pada proksi SignalR. Kode mendapatkan referensi ke proksi untuk StockTickerHub kelas dan memasukkannya ke ticker dalam variabel. Nama proksi adalah nama yang ditetapkan oleh HubName atribut :

var ticker = $.connection.stockTickerMini
[HubName("stockTickerMini")]
public class StockTickerHub : Hub

Setelah Anda menentukan semua variabel dan fungsi, baris kode terakhir dalam file menginisialisasi koneksi SignalR dengan memanggil fungsi SignalR start . Fungsi ini start dijalankan secara asinkron dan mengembalikan objek jQuery Deferred. Anda dapat memanggil fungsi selesai untuk menentukan fungsi yang akan dipanggil saat aplikasi menyelesaikan tindakan asinkron.

$.connection.hub.start().done(init);

Mendapatkan semua saham

Fungsi memanggil initgetAllStocks fungsi di server dan menggunakan informasi yang dikembalikan server untuk memperbarui tabel stok. Perhatikan bahwa, secara default, Anda harus menggunakan camelCasing pada klien meskipun nama metodenya pascal-cased di server. Aturan camelCasing hanya berlaku untuk metode, bukan objek. Misalnya, Anda merujuk ke stock.Symbol dan stock.Price, bukan stock.symbol atau stock.price.

function init() {
    ticker.server.getAllStocks().done(function (stocks) {
        $stockTableBody.empty();
        $.each(stocks, function () {
            var stock = formatStock(this);
            $stockTableBody.append(rowTemplate.supplant(stock));
        });
    });
}
public IEnumerable<Stock> GetAllStocks()
{
    return _stockTicker.GetAllStocks();
}

Dalam metode , init aplikasi membuat HTML untuk baris tabel untuk setiap objek stok yang diterima dari server dengan memanggil formatStock untuk memformat properti stock objek, lalu dengan memanggil supplant untuk mengganti tempat penampung dalam rowTemplate variabel dengan stock nilai properti objek. HTML yang dihasilkan kemudian ditambahkan ke tabel stok.

Catatan

Anda memanggil init dengan meneruskannya sebagai callback fungsi yang dijalankan setelah fungsi asinkron start selesai. Jika Anda memanggil init sebagai pernyataan JavaScript terpisah setelah memanggil start, fungsi akan gagal karena akan berjalan segera tanpa menunggu fungsi mulai selesai membuat koneksi. Dalam hal ini, init fungsi akan mencoba memanggil getAllStocks fungsi sebelum aplikasi membuat koneksi server.

Mendapatkan harga saham yang diperbarui

Ketika server mengubah harga saham, server memanggil klien yang updateStockPrice terhubung. Aplikasi menambahkan fungsi ke properti stockTicker klien proksi untuk membuatnya tersedia untuk panggilan dari server.

ticker.client.updateStockPrice = function (stock) {
    var displayStock = formatStock(stock),
        $row = $(rowTemplate.supplant(displayStock));

    $stockTableBody.find('tr[data-symbol=' + stock.Symbol + ']')
        .replaceWith($row);
    }

Fungsi memformat updateStockPrice objek stok yang diterima dari server ke dalam baris tabel dengan cara yang sama seperti dalam init fungsi . Alih-alih menambahkan baris ke tabel, baris stok saat ini ditemukan dalam tabel dan mengganti baris tersebut dengan baris baru.

Menguji aplikasi

Anda dapat menguji aplikasi untuk memastikan aplikasi berfungsi. Anda akan melihat semua jendela browser menampilkan tabel stok langsung dengan harga stok berfluktuasi.

  1. Di toolbar, aktifkan Debugging Skrip lalu pilih tombol putar untuk menjalankan aplikasi dalam mode Debug.

    Cuplikan layar pengguna mengaktifkan mode penelusuran kesalahan dan memilih putar.

    Jendela browser akan terbuka menampilkan Tabel Stok Langsung. Tabel stok awalnya menunjukkan "memuat..." line, kemudian, setelah waktu yang singkat, aplikasi menunjukkan data stok awal, dan kemudian harga saham mulai berubah.

  2. Salin URL dari browser, buka dua browser lain, dan tempelkan URL ke bilah alamat.

    Tampilan stok awal sama dengan browser pertama dan perubahan terjadi secara bersamaan.

  3. Tutup semua browser, buka browser baru, dan buka URL yang sama.

    Objek singleton StockTicker terus berjalan di server. Tabel Saham Langsung menunjukkan bahwa saham terus berubah. Anda tidak melihat tabel awal dengan angka perubahan nol.

  4. Tutup browser.

Aktifkan pencatatan log

SignalR memiliki fungsi pengelogan bawaan yang dapat Anda aktifkan pada klien untuk membantu dalam pemecahan masalah. Di bagian ini, Anda mengaktifkan pengelogan dan melihat contoh yang menunjukkan bagaimana log memberi tahu Anda metode transportasi mana yang digunakan SignalR:

Untuk koneksi tertentu, SignalR memilih metode transportasi terbaik yang didukung server dan klien.

  1. Buka StockTicker.js.

  2. Tambahkan baris kode yang disorot ini untuk mengaktifkan pengelogan segera sebelum kode yang menginisialisasi koneksi di akhir file:

    // Start the connection
    $.connection.hub.logging = true;
    $.connection.hub.start().done(init);
    
  3. Tekan F5 untuk menjalankan proyek.

  4. Buka jendela alat pengembang browser Anda, dan pilih Konsol untuk melihat log. Anda mungkin harus me-refresh halaman untuk melihat log SignalR yang menegosiasikan metode transportasi untuk koneksi baru.

    • Jika Anda menjalankan Internet Explorer 10 di Windows 8 (IIS 8), metode transportasinya adalah WebSockets.

    • Jika Anda menjalankan Internet Explorer 10 di Windows 7 (IIS 7.5), metode transportasinya adalah iframe.

    • Jika Anda menjalankan Firefox 19 di Windows 8 (IIS 8), metode transportasinya adalah WebSockets.

      Tip

      Di Firefox, instal add-in Firebug untuk mendapatkan jendela Konsol.

    • Jika Anda menjalankan Firefox 19 di Windows 7 (IIS 7.5), metode transportasi adalah peristiwa yang dikirim server .

Menginstal sampel StockTicker

Microsoft.AspNet.SignalR.Sample menginstal aplikasi StockTicker. Paket NuGet mencakup lebih banyak fitur daripada versi sederhana yang Anda buat dari awal. Di bagian tutorial ini, Anda menginstal paket NuGet dan meninjau fitur baru dan kode yang mengimplementasikannya.

Penting

Jika Anda menginstal paket tanpa melakukan langkah-langkah sebelumnya dari tutorial ini, Anda harus menambahkan kelas startup OWIN ke proyek Anda. File readme.txt untuk paket NuGet ini menjelaskan langkah ini.

Menginstal paket SignalR.Sample NuGet

  1. Di Penjelajah Solusi, klik kanan proyek, lalu pilih Kelola Paket NuGet.

  2. Di Manajer paket NuGet: SignalR.StockTicker, pilih Telusuri.

  3. Dari Sumber paket, pilih nuget.org.

  4. Masukkan SignalR.Sample di kotak pencarian dan pilih Microsoft.AspNet.SignalR.Sample>Install.

  5. Di Penjelajah Solusi, perluas folder SignalR.Sample.

    Menginstal paket SignalR.Sample membuat folder dan kontennya.

  6. Di folder SignalR.Sample , klik kanan StockTicker.html, lalu pilih Atur Sebagai Halaman Mulai.

    Catatan

    Menginstal paket SignalR.Sample NuGet mungkin mengubah versi jQuery yang Anda miliki di folder Skrip Anda. File StockTicker.html baru yang diinstal paket di folder SignalR.Sample akan sinkron dengan versi jQuery yang diinstal paket, tetapi jika Anda ingin menjalankan file StockTicker.html asli Anda lagi, Anda mungkin harus memperbarui referensi jQuery di tag skrip terlebih dahulu.

Menjalankan aplikasi

Tabel yang Anda lihat di aplikasi pertama memiliki fitur yang berguna. Aplikasi ticker stok penuh menunjukkan fitur baru: jendela pengguliran horizontal yang menunjukkan data stok dan saham yang berubah warna saat naik dan turun.

  1. Tekan F5 untuk menjalankan aplikasi.

    Saat Anda menjalankan aplikasi untuk pertama kalinya, "pasar" "ditutup" dan Anda melihat tabel statis dan jendela ticker yang tidak menggulir.

  2. Pilih Buka Pasar.

    Cuplikan layar ticker langsung.

    • Kotak Ticker Saham Langsung mulai menggulir secara horizontal, dan server mulai secara berkala menyiarkan perubahan harga saham secara acak.

    • Setiap kali harga saham berubah, aplikasi memperbarui Tabel Saham Langsung dan Ticker Saham Langsung.

    • Ketika perubahan harga saham positif, aplikasi menunjukkan saham dengan latar belakang hijau.

    • Ketika perubahan negatif, aplikasi menunjukkan stok dengan latar belakang merah.

  3. Pilih Tutup Pasar.

    • Pembaruan tabel berhenti.

    • Ticker berhenti menggulir.

  4. Pilih Atur ulang.

    • Semua data stok diatur ulang.

    • Aplikasi memulihkan status awal sebelum perubahan harga dimulai.

  5. Salin URL dari browser, buka dua browser lain, dan tempelkan URL ke bilah alamat.

  6. Anda melihat data yang sama diperbarui secara dinamis pada saat yang sama di setiap browser.

  7. Saat Anda memilih salah satu kontrol, semua browser merespons dengan cara yang sama secara bersamaan.

Tampilan Live Stock Ticker

Tampilan Live Stock Ticker adalah daftar yang tidak diurutkan dalam elemen yang <div> diformat menjadi satu baris menurut gaya CSS. Aplikasi ini menginisialisasi dan memperbarui ticker dengan cara yang sama seperti tabel: dengan mengganti tempat penampung dalam <li> string templat dan secara dinamis menambahkan <li> elemen ke <ul> elemen . Aplikasi ini mencakup pengguliran dengan menggunakan fungsi jQuery animate untuk memvariasikan margin-kiri daftar yang tidak diurutkan <div>dalam .

StockTicker.html SignalR.Sample

Kode HTML ticker saham:

<h2>Live Stock Ticker</h2>
<div id="stockTicker">
    <div class="inner">
        <ul>
            <li class="loading">loading...</li>
        </ul>
    </div>
</div>

SignalR.Sample StockTicker.css

Kode CSS ticker saham:

#stockTicker {
    overflow: hidden;
    width: 450px;
    height: 24px;
    border: 1px solid #999;
    }

    #stockTicker .inner {
        width: 9999px;
    }

    #stockTicker ul {
        display: inline-block;
        list-style-type: none;
        margin: 0;
        padding: 0;
    }

    #stockTicker li {
        display: inline-block;
        margin-right: 8px;   
    }

    /*<li data-symbol="{Symbol}"><span class="symbol">{Symbol}</span><span class="price">{Price}</span><span class="change">{PercentChange}</span></li>*/
    #stockTicker .symbol {
        font-weight: bold;
    }

    #stockTicker .change {
        font-style: italic;
    }

SignalR.StockTicker.js SignalR.Sample

Kode jQuery yang membuatnya menggulir:

function scrollTicker() {
    var w = $stockTickerUl.width();
    $stockTickerUl.css({ marginLeft: w });
    $stockTickerUl.animate({ marginLeft: -w }, 15000, 'linear', scrollTicker);
}

Metode tambahan di server yang dapat dipanggil klien

Untuk menambahkan fleksibilitas ke aplikasi, ada metode tambahan yang dapat dipanggil aplikasi.

SignalR.Sample StockTickerHub.cs

Kelas StockTickerHub menentukan empat metode tambahan yang dapat dipanggil klien:

public string GetMarketState()
{
    return _stockTicker.MarketState.ToString();
}

public void OpenMarket()
{
    _stockTicker.OpenMarket();
}

public void CloseMarket()
{
    _stockTicker.CloseMarket();
}

public void Reset()
{
    _stockTicker.Reset();
}

Aplikasi memanggil OpenMarket, CloseMarket, dan Reset sebagai respons terhadap tombol di bagian atas halaman. Mereka menunjukkan pola satu klien yang memicu perubahan status segera disebarluaskan ke semua klien. Masing-masing metode ini memanggil metode di StockTicker kelas yang menyebabkan perubahan status pasar dan kemudian menyiarkan status baru.

SignalR.Sample StockTicker.cs

StockTicker Di kelas , aplikasi mempertahankan status pasar dengan MarketState properti yang mengembalikan MarketState nilai enum:

public MarketState MarketState
{
    get { return _marketState; }
    private set { _marketState = value; }
}

public enum MarketState
{
    Closed,
    Open
}

Setiap metode yang mengubah status pasar melakukannya di dalam blok kunci karena StockTicker kelas harus aman untuk utas:

public void OpenMarket()
{
    lock (_marketStateLock)
    {
        if (MarketState != MarketState.Open)
        {
            _timer = new Timer(UpdateStockPrices, null, _updateInterval, _updateInterval);
            MarketState = MarketState.Open;
            BroadcastMarketStateChange(MarketState.Open);
        }
    }
}

public void CloseMarket()
{
    lock (_marketStateLock)
    {
        if (MarketState == MarketState.Open)
        {
            if (_timer != null)
            {
                _timer.Dispose();
            }
            MarketState = MarketState.Closed;
            BroadcastMarketStateChange(MarketState.Closed);
        }
    }
}

public void Reset()
{
    lock (_marketStateLock)
    {
        if (MarketState != MarketState.Closed)
        {
            throw new InvalidOperationException("Market must be closed before it can be reset.");
        }
        LoadDefaultStocks();
        BroadcastMarketReset();
    }
}

Untuk memastikan kode ini aman untuk utas, _marketState bidang yang mendukung properti yang MarketState ditunjuk volatile:

private volatile MarketState _marketState;

Metode BroadcastMarketStateChange dan BroadcastMarketReset mirip dengan metode BroadcastStockPrice yang sudah Anda lihat, kecuali mereka memanggil metode yang berbeda yang ditentukan di klien:

private void BroadcastMarketStateChange(MarketState marketState)
{
    switch (marketState)
    {
        case MarketState.Open:
            Clients.All.marketOpened();
            break;
        case MarketState.Closed:
            Clients.All.marketClosed();
            break;
        default:
            break;
    }
}

private void BroadcastMarketReset()
{
    Clients.All.marketReset();
}

Fungsi tambahan pada klien yang dapat dipanggil server

Fungsi updateStockPrice sekarang menangani tabel dan tampilan ticker, dan digunakan jQuery.Color untuk berkedip warna merah dan hijau.

Fungsi baru di SignalR.StockTicker.js mengaktifkan dan menonaktifkan tombol berdasarkan status pasar. Mereka juga menghentikan atau memulai Pengguliran horizontal Ticker Saham Langsung . Karena banyak fungsi ditambahkan ke ticker.client, aplikasi menggunakan fungsi perluasan jQuery untuk menambahkannya.

$.extend(ticker.client, {
    updateStockPrice: function (stock) {
        var displayStock = formatStock(stock),
            $row = $(rowTemplate.supplant(displayStock)),
            $li = $(liTemplate.supplant(displayStock)),
            bg = stock.LastChange === 0
                ? '255,216,0' // yellow
                : stock.LastChange > 0
                    ? '154,240,117' // green
                    : '255,148,148'; // red

        $stockTableBody.find('tr[data-symbol=' + stock.Symbol + ']')
            .replaceWith($row);
        $stockTickerUl.find('li[data-symbol=' + stock.Symbol + ']')
            .replaceWith($li);

        $row.flash(bg, 1000);
        $li.flash(bg, 1000);
    },

    marketOpened: function () {
        $("#open").prop("disabled", true);
        $("#close").prop("disabled", false);
        $("#reset").prop("disabled", true);
        scrollTicker();
    },

    marketClosed: function () {
        $("#open").prop("disabled", false);
        $("#close").prop("disabled", true);
        $("#reset").prop("disabled", false);
        stopTicker();
    },

    marketReset: function () {
        return init();
    }
});

Penyiapan klien tambahan setelah membuat koneksi

Setelah klien membuat koneksi, klien memiliki beberapa pekerjaan tambahan yang harus dilakukan:

  • Cari tahu apakah pasar terbuka atau ditutup untuk memanggil fungsi atau marketClosed yang sesuaimarketOpened.

  • Lampirkan panggilan metode server ke tombol.

$.connection.hub.start()
    .pipe(init)
    .pipe(function () {
        return ticker.server.getMarketState();
    })
    .done(function (state) {
        if (state === 'Open') {
            ticker.client.marketOpened();
        } else {
            ticker.client.marketClosed();
        }

        // Wire up the buttons
        $("#open").click(function () {
            ticker.server.openMarket();
        });

        $("#close").click(function () {
            ticker.server.closeMarket();
        });

        $("#reset").click(function () {
            ticker.server.reset();
        });
    });

Metode server tidak dikabel ke tombol hingga setelah aplikasi membuat koneksi. Ini sehingga kode tidak dapat memanggil metode server sebelum tersedia.

Sumber Daya Tambahan:

Dalam tutorial ini Anda telah mempelajari cara memprogram aplikasi SignalR yang menyiarkan pesan dari server ke semua klien yang terhubung. Sekarang Anda dapat menyiarkan pesan secara berkala dan menanggapi pemberitahuan dari klien mana pun. Anda dapat menggunakan konsep instans singleton multi-utas untuk mempertahankan status server dalam skenario game online multi-pemain. Misalnya, lihat game ShootR berdasarkan SignalR.

Untuk tutorial yang menunjukkan skenario komunikasi peer-to-peer, lihat Memulai SignalR dan Pembaruan Real-Time dengan SignalR.

Untuk informasi selengkapnya tentang SignalR, lihat sumber daya berikut ini:

Langkah berikutnya

Di tutorial ini, Anda akan:

  • Membuat proyek
  • Menyiapkan kode server
  • Memeriksa kode server
  • Menyiapkan kode klien
  • Memeriksa kode klien
  • Menguji aplikasi
  • Pengelogan yang diaktifkan

Lanjutkan ke artikel berikutnya untuk mempelajari cara membuat aplikasi web real-time yang menggunakan ASP.NET SignalR 2.