Öğretici: SignalR 2 ile sunucu yayını

Uyarı

Bu belgeler SignalR'nin en son sürümüne yönelik değildir. SignalR ASP.NET Core göz atın.

Bu öğreticide, sunucu yayını işlevselliği sağlamak için ASP.NET SignalR 2 kullanan bir web uygulamasının nasıl oluşturulacağı gösterilmektedir. Sunucu yayını, sunucunun istemcilere gönderilen iletişimleri başlattığı anlamına gelir.

Bu öğreticide oluşturacağınız uygulama, sunucu yayını işlevselliği için tipik bir senaryo olan hisse senedi değerleyicisinin benzetimini yapar. Sunucu düzenli aralıklarla hisse senedi fiyatlarını rastgele güncelleştirir ve güncelleştirmeleri tüm bağlı istemcilere yayınlar. Tarayıcıda, Değiştir ve sütunlardaki sayılar ve % simgeler sunucudan gelen bildirimlere yanıt olarak dinamik olarak değişir. Aynı URL'ye ek tarayıcılar açarsanız, hepsi aynı verileri ve aynı değişiklikleri aynı anda verilerde gösterir.

Birden çok web tarayıcısının aynı anda aynı güncelleştirilmiş verileri nasıl gösterdiğini gösteren ekran görüntüsü.

Bu öğreticide şunları yaptınız:

  • Proje oluşturma
  • Sunucu kodunu ayarlama
  • Sunucu kodunu inceleme
  • İstemci kodunu ayarlama
  • İstemci kodunu inceleme
  • Uygulamayı test edin
  • Günlü kaydını etkinleştir

Önemli

Uygulamayı oluşturma adımlarında çalışmak istemiyorsanız SignalR.Sample paketini yeni bir Boş ASP.NET Web Uygulaması projesine yükleyebilirsiniz. NuGet paketini bu öğreticideki adımları uygulamadan yüklerseniz readme.txt dosyasındaki yönergeleri izlemeniz gerekir. Paketi çalıştırmak için yüklü pakette yöntemini çağıran ConfigureSignalR bir OWIN başlangıç sınıfı eklemeniz gerekir. OWIN başlangıç sınıfını eklemezseniz bir hata alırsınız. Bu makalenin StockTicker örneğini yükleme bölümüne bakın.

Önkoşullar

Proje oluşturma

Bu bölümde, Boş bir ASP.NET Web Uygulaması oluşturmak için Visual Studio 2017'nin nasıl kullanılacağı gösterilmektedir.

  1. Visual Studio'da bir ASP.NET Web Uygulaması oluşturun.

    ASP.NET Web Uygulaması oluşturmayı gösteren ekran görüntüsü.

  2. Yeni ASP.NET Web Uygulaması - SignalR.StockTicker penceresinde Boş'u seçili bırakın ve Tamam'ı seçin.

Sunucu kodunu ayarlama

Bu bölümde, sunucuda çalışan kodu ayarlarsınız.

Stock sınıfını oluşturma

İlk olarak , bir hisse senediyle ilgili bilgileri depolamak ve iletmek için kullanacağınız Hisse Senedi modeli sınıfını oluşturursunuz.

  1. Çözüm Gezgini'da projeye sağ tıklayın veSınıfEkle'yi> seçin.

  2. Sınıfı Stock olarak adlandırın ve projeye ekleyin.

  3. Stock.cs dosyasındaki kodu şu kodla değiştirin:

    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);
                }
            }
        }
    }
    

    Hisse senetlerini oluştururken ayarlayacağınız iki özellik (örneğin, Microsoft için MSFT) ve Priceşeklindedir Symbol . Diğer özellikler, öğesini nasıl ve ne zaman ayarladığınıza Pricebağlıdır. değerini ilk kez ayarladığınızda Price, değer öğesine DayOpenyayılır. Bundan sonra, ayarladığınızda Priceuygulama ile arasındaki PriceDayOpenfarka göre ve PercentChange özellik değerlerini hesaplarChange.

StockTickerHub ve StockTicker sınıflarını oluşturma

Sunucudan istemciye etkileşimi işlemek için SignalR Hub API'sini kullanacaksınız. StockTickerHub SignalR Hub sınıfından türetilen bir sınıf, istemcilerden gelen alma bağlantılarını ve yöntem çağrılarını işler. Ayrıca hisse senedi verilerini korumanız ve bir Timer nesne çalıştırmanız gerekir. nesnesi, Timer istemci bağlantılarından bağımsız olarak fiyat güncelleştirmelerini düzenli aralıklarla tetikler. Hub'lar geçici olduğundan bu işlevleri bir Hub sınıfa koyamazsınız. Uygulama, merkezdeki her görev için istemciden sunucuya bağlantılar ve çağrılar gibi bir Hub sınıf örneği oluşturur. Bu nedenle hisse senedi verilerini tutan, fiyatları güncelleştiren ve fiyat güncelleştirmelerini yayınlayan mekanizmanın ayrı bir sınıfta çalıştırılması gerekir. Sınıfı StockTickerolarak adlandıracaksınız.

StockTicker'dan yayın

Sınıfının yalnızca bir örneğinin StockTicker sunucuda çalışmasını istiyorsunuz, bu nedenle her StockTickerHub örnekten tekil StockTicker örneğe bir başvuru ayarlamanız gerekir. Sınıfın StockTicker istemcilere yayınlaması gerekir çünkü hisse senedi verilerine sahiptir ve güncelleştirmeleri tetikler, ancak StockTicker bir Hub sınıf değildir. sınıfının StockTicker SignalR Hub bağlantı bağlam nesnesine bir başvuru alması gerekir. Daha sonra istemcilere yayınlamak için SignalR bağlantı bağlamı nesnesini kullanabilir.

StockTickerHub.cs oluşturma

  1. Çözüm Gezgini'da projeye sağ tıklayın veYeni Öğe Ekle'yi> seçin.

  2. Yeni Öğe Ekle - SignalR.StockTicker bölümünde Yüklü>Visual C#>Web>SignalR'yi ve ardından SignalR Hub Sınıfı (v2) öğesini seçin.

  3. Sınıfı StockTickerHub olarak adlandırın ve projeye ekleyin.

    Bu adım StockTickerHub.cs sınıf dosyasını oluşturur. Aynı anda, projeye SignalR'yi destekleyen bir dizi betik dosyası ve derleme başvurusu ekler.

  4. StockTickerHub.cs dosyasındaki kodu şu kodla değiştirin:

    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. Dosyayı kaydedin.

Uygulama, istemcilerin sunucuda çağırabileceği yöntemleri tanımlamak için Hub sınıfını kullanır. Tek bir yöntem tanımlıyorsunuz: GetAllStocks(). bir istemci başlangıçta sunucuya bağlandığında, geçerli fiyatlarıyla tüm hisse senetlerinin listesini almak için bu yöntemi çağırır. yöntemi zaman uyumlu olarak çalışabilir ve bellekten veri döndüreceği için döndürebilir IEnumerable<Stock> .

Yöntemin, veritabanı araması veya web hizmeti çağrısı gibi beklemeyi kapsayan bir işlem yaparak verileri alması gerekiyorsa, zaman uyumsuz işlemeyi etkinleştirmek için dönüş değeri olarak belirtebilirsiniz Task<IEnumerable<Stock>> . Daha fazla bilgi için bkz. ASP.NET SignalR Hubs API Kılavuzu - Sunucu - Zaman uyumsuz olarak yürütülme zamanları.

özniteliği, HubName uygulamanın istemcideki JavaScript kodunda Hub'a nasıl başvuracağını belirtir. Bu özniteliği kullanmazsanız istemcideki varsayılan ad, sınıf adının camelCase sürümüdür ve bu durumda olacaktır stockTickerHub.

Daha sonra sınıfı oluşturduğunuzda StockTicker göreceğiniz gibi uygulama, statik Instance özelliğinde bu sınıfın tekil bir örneğini oluşturur. Bu tekil örneği StockTicker , kaç istemcinin bağlanması veya bağlantısının kesilmesi fark etmez bellektedir. Bu örnek, yöntemin GetAllStocks() geçerli hisse senedi bilgilerini döndürmek için kullandığı örnektir.

StockTicker.cs oluşturma

  1. Çözüm Gezgini'da projeye sağ tıklayın veSınıfEkle'yi> seçin.

  2. Sınıfı StockTicker olarak adlandırın ve projeye ekleyin.

  3. StockTicker.cs dosyasındaki kodu şu kodla değiştirin:

    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);
            }
    
        }
    }
    

Tüm iş parçacıkları aynı StockTicker kodu örneğini çalıştıracağı için StockTicker sınıfının iş parçacığı güvenli olması gerekir.

Sunucu kodunu inceleme

Sunucu kodunu incelerseniz, uygulamanın nasıl çalıştığını anlamanıza yardımcı olur.

Tekil örneği statik alanda depolama

Kod, özelliğini sınıfının bir örneğiyle destekleyen Instance statik _instance alanı başlatır. Oluşturucu özel olduğundan, uygulamanın oluşturabileceği tek sınıf örneğidir. Uygulama, alan için Gecikmeli başlatma kullanır _instance . Performans nedenleriyle değil. Örnek oluşturma işleminin iş parçacığı açısından güvenli olduğundan emin olmaktır.

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

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

İstemci sunucuya her bağlandığında, ayrı bir iş parçacığında çalıştırılan stockTickerHub sınıfının yeni bir örneği, daha önce StockTickerHub sınıfında gördüğünüz gibi statik özelliğinden StockTicker.Instance StockTicker tekil örneğini alır.

Hisse senedi verilerini ConcurrentDictionary'de depolama

Oluşturucu, koleksiyonu bazı örnek hisse senedi verileriyle başlatır _stocks ve GetAllStocks hisse senetlerini döndürür. Daha önce gördüğünüz gibi, bu hisse senetleri koleksiyonu tarafından döndürülür StockTickerHub.GetAllStocks. Bu, istemcilerinin çağırabileceği sınıftaki Hub bir sunucu yöntemidir.

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;
}

Hisse senetleri koleksiyonu, iş parçacığı güvenliği için ConcurrentDictionary türü olarak tanımlanır. Alternatif olarak, bir Sözlük nesnesi kullanabilir ve sözlüğe değişiklik yaptığınızda sözlüğü açıkça kilitleyebilirsiniz.

Bu örnek uygulama için, uygulama verilerini bellekte depolamak ve uygulama örneği attığında StockTicker verileri kaybetmek uygun olur. Gerçek bir uygulamada veritabanı gibi bir arka uç veri deposuyla çalışırsınız.

Hisse senedi fiyatlarını düzenli aralıklarla güncelleştirme

Oluşturucu, hisse senedi fiyatlarını rastgele olarak güncelleştiren yöntemleri düzenli aralıklarla çağıran bir nesne başlatır Timer .

_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;
}

TimerUpdateStockPricesçağrıları, durum parametresinde null değerini geçirir. Fiyatları güncelleştirmeden önce uygulama nesneye kilitlenir _updateStockPricesLock . Kod, başka bir iş parçacığının zaten fiyatları güncelleştirip güncelleştirmediğini denetler ve listedeki her hisse senedini çağırır TryUpdateStockPrice . TryUpdateStockPrice yöntemi hisse senedi fiyatının değiştirilip değiştirilmeyeceğini ve ne kadar değiştireceğini karar verir. Hisse senedi fiyatı değişirse uygulama, hisse senedi fiyat değişikliğini tüm bağlı istemcilere yayınlamayı çağırır BroadcastStockPrice .

bayrağı, _updatingStockPrices iş parçacığı güvenli olduğundan emin olmak için geçici olarak belirlenmiştir.

private volatile bool _updatingStockPrices = false;

Gerçek bir uygulamada yöntemi, TryUpdateStockPrice fiyatı aramak için bir web hizmetini çağırır. Bu kodda uygulama rastgele değişiklik yapmak için rastgele bir sayı oluşturucu kullanır.

StockTicker sınıfının istemcilere yayın edebilmesi için SignalR bağlamını alma

Fiyat değişiklikleri burada nesnesinden StockTicker kaynaklandığı için, tüm bağlı istemcilerde bir updateStockPrice yöntemi çağırması gereken nesnedir. Bir Hub sınıfta, istemci yöntemlerini çağırmak için bir API'niz vardır, ancak StockTicker sınıfından Hub türetilmez ve herhangi Hub bir nesneye başvurusu yoktur. Bağlı istemcilere yayınlamak için sınıfın StockTicker sınıfın SignalR bağlam örneğini alması ve istemcilerdeki yöntemleri çağırmak için StockTickerHub bunu kullanması gerekir.

Kod, tekli sınıf örneğini oluşturduğunda SignalR bağlamı için bir başvuru alır, bu başvuruyu oluşturucuya geçirir ve oluşturucu bunu özelliğine Clients yerleştirir.

Bağlamı yalnızca bir kez almak istemenin iki nedeni vardır: bağlamı almak pahalı bir görevdir ve bir kez almak, uygulamanın istemcilere gönderilen iletilerin hedeflenen sırasını koruduğundan emin olmanızı sağlar.

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);
}

Bağlamın Clients özelliğini alma ve özelliğine StockTickerClient yerleştirme, bir sınıfta olduğu gibi Hub görünen istemci yöntemlerini çağırmak için kod yazmanızı sağlar. Örneğin, tüm istemcilere yayınlamak için yazabilirsiniz Clients.All.updateStockPrice(stock).

updateStockPrice Çağırdığınız BroadcastStockPrice yöntem henüz mevcut değil. Daha sonra istemcide çalışan bir kod yazdığınızda ekleyeceksiniz. Dinamik olduğundan buraya Clients.All başvurabilirsinizupdateStockPrice; bu da uygulamanın ifadeyi çalışma zamanında değerlendireceği anlamına gelir. Bu yöntem çağrısı yürütürken SignalR yöntem adını ve parametre değerini istemciye gönderir ve istemcinin adlı updateStockPricebir yöntemi varsa, uygulama bu yöntemi çağırır ve parametre değerini ona geçirir.

Clients.All tüm istemcilere gönderme anlamına gelir. SignalR, hangi istemcilere veya istemci gruplarına gönderileceğini belirtmek için size başka seçenekler sunar. Daha fazla bilgi için bkz . HubConnectionContext.

SignalR yolunu kaydetme

Sunucunun hangi URL'nin kesilip SignalR'ye yönlendirilmesi gerektiğini bilmesi gerekir. Bunu yapmak için bir OWIN başlangıç sınıfı ekleyin:

  1. Çözüm Gezgini'da projeye sağ tıklayın veYeni Öğe Ekle'yi> seçin.

  2. Yeni Öğe Ekle - SignalR.StockTicker'daYüklü>Visual C#>Web'i ve ardından OWIN Başlangıç Sınıfı'ni seçin.

  3. Sınıfı Başlangıç olarak adlandırın ve Tamam'ı seçin.

  4. Startup.cs dosyasındaki varsayılan kodu şu kodla değiştirin:

    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();
            }
    
        }
    }
    

Sunucu kodunu ayarlamayı tamamladınız. Sonraki bölümde istemciyi ayarlayacaksınız.

İstemci kodunu ayarlama

Bu bölümde, istemcide çalışan kodu ayarlarsınız.

HTML sayfasını ve JavaScript dosyasını oluşturma

HTML sayfasında veriler görüntülenir ve JavaScript dosyası verileri düzenler.

StockTicker.html oluşturma

İlk olarak HTML istemcisini ekleyeceksiniz.

  1. Çözüm Gezgini'da projeye sağ tıklayın veHTML SayfasıEkle'yi> seçin.

  2. Dosyayı StockTicker olarak adlandırın ve Tamam'ı seçin.

  3. StockTicker.html dosyasındaki varsayılan kodu şu kodla değiştirin:

    <!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 beş sütunlu bir tablo, üst bilgi satırı ve beş sütunun tümüne yayılan tek bir hücre içeren bir veri satırı oluşturur. Veri satırı "yükleniyor..." bir an için uygulama başlatıldığında. JavaScript kodu bu satırı kaldırır ve sunucudan alınan hisse senedi verileriyle yerine satır ekler.

    Betik etiketleri şunları belirtir:

    • jQuery betik dosyası.

    • SignalR çekirdek betik dosyası.

    • SignalR proxy'leri betik dosyası.

    • Daha sonra oluşturacağınız bir StockTicker betik dosyası.

    Uygulama SignalR proxy'leri betik dosyasını dinamik olarak oluşturur. "/signalr/hubs" URL'sini belirtir ve Hub sınıfındaki yöntemler için ara sunucu yöntemlerini tanımlar. Bu örnekte için StockTickerHub.GetAllStocks. İsterseniz SignalR Yardımcı Programlarını kullanarak bu JavaScript dosyasını el ile oluşturabilirsiniz. Yöntem çağrısında MapHubs dinamik dosya oluşturmayı devre dışı bırakmayı unutmayın.

  4. Çözüm Gezgini'daBetikler'i genişletin.

    jQuery ve SignalR için betik kitaplıkları projede görünür.

    Önemli

    Paket yöneticisi SignalR betiklerinin sonraki bir sürümünü yükler.

  5. Kod bloğundaki betik başvurularını projedeki betik dosyalarının sürümlerine karşılık gelen şekilde güncelleştirin.

  6. Çözüm Gezgini'daStockTicker.htmlöğesine sağ tıklayın ve Ardından Başlangıç Sayfası Olarak Ayarla'yı seçin.

StockTicker.js oluşturma

Şimdi JavaScript dosyasını oluşturun.

  1. Çözüm Gezgini'da projeye sağ tıklayın veJavaScript DosyasıEkle'yi> seçin.

  2. Dosyayı StockTicker olarak adlandırın ve Tamam'ı seçin.

  3. Bu kodu StockTicker.js dosyasına ekleyin:

    // 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);
    
    });
    

İstemci kodunu inceleme

İstemci kodunu incelerseniz, uygulamanın çalışması için istemci kodunun sunucu koduyla nasıl etkileşim kuracağını öğrenmenize yardımcı olur.

Bağlantıyı başlatma

$.connection SignalR proxy'lerini ifade eder. Kod, sınıfın StockTickerHub ara sunucusuna bir başvuru alır ve değişkenine ticker yerleştirir. Proxy adı, özniteliği tarafından HubName ayarlanan addır:

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

Tüm değişkenleri ve işlevleri tanımladıktan sonra, dosyadaki son kod satırı SignalR işlevini çağırarak SignalR start bağlantısını başlatır. start İşlev zaman uyumsuz olarak yürütülür ve jQuery Ertelenmiş nesnesi döndürür. Uygulama zaman uyumsuz eylemi tamamladığında çağrılacak işlevi belirtmek için done işlevini çağırabilirsiniz.

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

Tüm hisse senetlerini alma

İşlev, init sunucudaki işlevi çağırır getAllStocks ve sunucunun hisse senedi tablosunu güncelleştirmek için döndürdüğü bilgileri kullanır. Varsayılan olarak, yöntem adı sunucuda pascal-cased olsa bile istemcide camelCasing kullanmanız gerekir. camelCasing kuralı nesnelere değil yalnızca yöntemlere uygulanır. Örneğin, veya stock.priceyerine stock.symbol ve stock.Priceöğesine başvurursunuzstock.Symbol.

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();
}

yönteminde init uygulama, nesnenin özelliklerini stock biçimlendirmek için çağrısı formatStock yaparak sunucudan alınan her hisse senedi nesnesi için bir tablo satırı için HTML oluşturur ve ardından değişkendeki rowTemplate yer tutucuları nesne özelliği değerleriyle stock değiştirmek için çağrısı supplant yapar. Elde edilen HTML daha sonra hisse senedi tablosuna eklenir.

Not

Zaman uyumsuz start işlev tamamlandıktan sonra yürütülen bir callback işlev olarak geçirerek çağırıninit. çağrısından startsonra ayrı bir JavaScript deyimi olarak çağırdıysanızinit, start işlevinin bağlantıyı kurmayı bitirmesini beklemeden hemen çalıştırıldığından işlev başarısız olur. Bu durumda işlev, init uygulama bir sunucu bağlantısı kurmadan önce işlevini çağırmayı getAllStocks dener.

Güncelleştirilmiş hisse senedi fiyatlarını alma

Sunucu hisse senedinin fiyatını değiştirdiğinde bağlı istemcileri çağırır updateStockPrice . Uygulama, işlevi sunucudan gelen çağrılar için kullanılabilir hale getirmek için proxy'nin stockTicker istemci özelliğine ekler.

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

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

İşlev, updateStockPrice sunucudan alınan hisse senedi nesnesini işlevdeki gibi bir tablo satırına biçimlendirir init . Satırı tabloya eklemek yerine, tablonun hisse senedinin geçerli satırını bulur ve bu satırı yenisiyle değiştirir.

Uygulamayı test edin

Çalıştığından emin olmak için uygulamayı test edebilirsiniz. Tüm tarayıcı pencerelerinin hisse senedi fiyatlarının dalgalı olduğu canlı hisse senedi tablosunu görüntülediğini göreceksiniz.

  1. Araç çubuğunda Betik Hata Ayıklama'yı açın ve uygulamayı Hata Ayıklama modunda çalıştırmak için yürüt düğmesini seçin.

    Kullanıcının hata ayıklama modunu açmasının ve yürüt'ün seçilmesinin ekran görüntüsü.

    Live Stock Table'ın görüntülendiği bir tarayıcı penceresi açılır. Hisse senedi tablosunda başlangıçta "yükleniyor..." satırına gidin ve kısa bir süre sonra uygulama ilk hisse senedi verilerini gösterir ve ardından hisse senedi fiyatları değişmeye başlar.

  2. Tarayıcıdan URL'yi kopyalayın, iki tarayıcı daha açın ve URL'leri adres çubuklarına yapıştırın.

    İlk stok ekranı ilk tarayıcıyla aynıdır ve değişiklikler aynı anda gerçekleşir.

  3. Tüm tarayıcıları kapatın, yeni bir tarayıcı açın ve aynı URL'ye gidin.

    StockTicker singleton nesnesi sunucuda çalışmaya devam etti. Live Stock Table hisse senetlerinin değişmeye devam ettiğini gösterir. Sıfır değişiklik rakamı içeren ilk tabloyu görmezsiniz.

  4. Tarayıcıyı kapatın.

Günlü kaydını etkinleştir

SignalR, sorun gidermeye yardımcı olması için istemcide etkinleştirebileceğiniz yerleşik bir günlüğe kaydetme işlevine sahiptir. Bu bölümde, günlüğe kaydetmeyi etkinleştirip günlüklerin SignalR'nin aşağıdaki aktarım yöntemlerinden hangisini kullandığını nasıl gösterdiğini gösteren örnekleri görürsünüz:

Belirli bir bağlantı için SignalR, hem sunucunun hem de istemcinin desteklediği en iyi aktarım yöntemini seçer.

  1. StockTicker.jsaçın.

  2. Dosyanın sonunda bağlantıyı başlatan koddan hemen önce günlüğe kaydetmeyi etkinleştirmek için bu vurgulanmış kod satırını ekleyin:

    // Start the connection
    $.connection.hub.logging = true;
    $.connection.hub.start().done(init);
    
  3. Projeyi çalıştırmak için F5 tuşuna basın.

  4. Tarayıcınızın geliştirici araçları penceresini açın ve günlükleri görmek için Konsol'a tıklayın. SignalR günlüklerinin yeni bir bağlantı için aktarım yönteminde anlaşmaya varan günlüklerini görmek için sayfayı yenilemeniz gerekebilir.

    • Internet Explorer 10'u Windows 8 (IIS 8) üzerinde çalıştırıyorsanız aktarım yöntemi WebSockets'tir.

    • Windows 7'de (IIS 7.5) Internet Explorer 10 çalıştırıyorsanız, aktarım yöntemi iframe'dir.

    • firefox 19'u Windows 8 (IIS 8) üzerinde çalıştırıyorsanız aktarım yöntemi WebSockets'tir.

      İpucu

      Firefox'ta Bir Konsol penceresi almak için Firebug eklentisini yükleyin.

    • Windows 7'de (IIS 7.5) Firefox 19 çalıştırıyorsanız, aktarım yöntemi sunucu tarafından gönderilen olaylardır.

StockTicker örneğini yükleme

Microsoft.AspNet.SignalR.Sample, StockTicker uygulamasını yükler. NuGet paketi sıfırdan oluşturduğunuz basitleştirilmiş sürümden daha fazla özellik içerir. Öğreticinin bu bölümünde NuGet paketini yükler ve yeni özellikleri ve bunları uygulayan kodu gözden geçirirsiniz.

Önemli

Bu öğreticinin önceki adımlarını gerçekleştirmeden paketi yüklerseniz, projenize bir OWIN başlangıç sınıfı eklemeniz gerekir. NuGet paketi için bu readme.txt dosyası bu adımı açıklar.

SignalR.Sample NuGet paketini yükleme

  1. Çözüm Gezgini'da projeye sağ tıklayın ve NuGet Paketlerini Yönet'i seçin.

  2. NuGet Paket yöneticisi: SignalR.StockTicker'daGözat'ı seçin.

  3. Paket kaynağı'ndannuget.org'yi seçin.

  4. Arama kutusuna SignalR.Sample yazın ve Microsoft.AspNet.SignalR.Sample>Yükleme'yi seçin.

  5. Çözüm Gezgini'daSignalR.Sample klasörünü genişletin.

    SignalR.Sample paketinin yüklenmesi klasörü ve içeriğini oluşturdu.

  6. SignalR.Sample klasöründe StockTicker.htmlöğesine sağ tıklayın ve Ardından Başlangıç Sayfası Olarak Ayarla'yı seçin.

    Not

    SignalR.Sample NuGet paketinin yüklenmesi Betikler klasörünüzde bulunan jQuery sürümünü değiştirebilir. Paketin SignalR.Sample klasörüne yüklemiş olduğu yeni StockTicker.html dosyası paketin yüklemiş olduğu jQuery sürümüyle eşitlenir, ancak özgün StockTicker.html dosyanızı yeniden çalıştırmak isterseniz, önce betik etiketindeki jQuery başvurusunu güncelleştirmeniz gerekebilir.

Uygulamayı çalıştırma

İlk uygulamada gördüğünüz tabloda yararlı özellikler vardı. Tam hisse senedi değerleyici uygulaması yeni özellikleri gösterir: hisse senedi verilerini ve hisse senetleri yükseldikçe ve düştükçe renk değiştiren hisse senetlerini gösteren yatay olarak kayan bir pencere.

  1. Uygulamayı çalıştırmak için F5 tuşuna basın.

    Uygulamayı ilk kez çalıştırdığınızda "market" "kapalıdır" ve statik bir tablo ve kaydırma olmayan bir değer çizgisi penceresi görürsünüz.

  2. Açık Pazar'ı seçin.

    Canlı değer çizgisinin ekran görüntüsü.

    • Canlı Hisse Senedi DeğerLeyicisi kutusu yatay olarak kaydırmaya başlar ve sunucu hisse senedi fiyat değişikliklerini rastgele olarak düzenli aralıklarla yayınlamaya başlar.

    • Bir hisse senedi fiyatı her değiştiğinde, uygulama hem Live Stock Table'ı hem de Live Stock Ticker'ı güncelleştirir.

    • Bir hisse senedinin fiyat değişikliği pozitif olduğunda, uygulama hisse senedini yeşil bir arka planla gösterir.

    • Değişiklik negatif olduğunda, uygulama hisse senedini kırmızı arka plan ile gösterir.

  3. Pazarı Kapat'ı seçin.

    • Tablo güncelleştirmeleri durduruluyor.

    • Değer çizgisi kaydırmayı durdurur.

  4. Sıfırla’yı seçin.

    • Tüm hisse senedi verileri sıfırlanır.

    • Uygulama, fiyat değişiklikleri başlamadan önce ilk durumu geri yükler.

  5. Tarayıcıdan URL'yi kopyalayın, iki tarayıcı daha açın ve URL'leri adres çubuklarına yapıştırın.

  6. Her tarayıcıda aynı verilerin aynı anda dinamik olarak güncelleştirildiğini görürsünüz.

  7. Denetimlerden herhangi birini seçtiğinizde, tüm tarayıcılar aynı anda aynı şekilde yanıt verir.

Canlı Hisse Senedi Değerleyici ekranı

Canlı Hisse Senedi Değerleyicisi ekranı, CSS stillerine göre tek bir <div> satıra biçimlendirilmiş bir öğede sıralanmamış bir listedir. Uygulama, bir şablon dizesindeki <li> yer tutucuları değiştirerek ve öğeleri öğeye dinamik olarak ekleyerek <li> değerleyiciyi <ul> tabloyla aynı şekilde başlatır ve güncelleştirir. Uygulama, içindeki sıralanmamış listenin sol kenar boşluğunu değiştirmek için jQuery animate işlevini kullanarak kaydırmayı <div>içerir.

SignalR.Sample StockTicker.html

Hisse senedi değerleyici HTML kodu:

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

SignalR.Sample StockTicker.css

Hisse senedi değerleyici CSS kodu:

#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.Sample SignalR.StockTicker.js

Bunu kaydıran jQuery kodu:

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

sunucuda istemcinin çağırabileceği ek yöntemler

Uygulamaya esneklik eklemek için uygulamanın çağırabileceği ek yöntemler vardır.

SignalR.Sample StockTickerHub.cs

sınıfı, StockTickerHub istemcinin çağırabileceği dört ek yöntem tanımlar:

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

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

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

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

Uygulama, sayfanın üst kısmındaki düğmelere yanıt olarak , CloseMarketve Reset çağrılarını OpenMarketçağırır. Tüm istemcilere hemen yayılan durumda bir değişikliği tetikleyen bir istemcinin desenini gösterir. Bu yöntemlerin her biri, sınıfında pazar durumu değişikliğine StockTicker neden olan ve ardından yeni durumu yayınlayan bir yöntem çağırır.

SignalR.Sample StockTicker.cs

StockTicker sınıfında uygulama, enum değeri döndüren MarketState bir MarketState özellik ile pazarın durumunu korur:

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

public enum MarketState
{
    Closed,
    Open
}

Sınıfın iş parçacığı açısından güvenli olması gerekeceğinden, pazar durumunu değiştiren yöntemlerin her biri bunu bir kilit bloğu içinde StockTicker yapar:

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();
    }
}

Bu kodun iş parçacığı açısından güvenli olduğundan emin olmak için, _marketState belirtilen volatileözelliği destekleyen MarketState alan:

private volatile MarketState _marketState;

BroadcastMarketStateChange ve BroadcastMarketReset yöntemleri, daha önce gördüğünüz BroadcastStockPrice yöntemine benzer, ancak istemcide tanımlanan farklı yöntemleri çağırır:

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();
}

İstemcide sunucunun çağırabileceği ek işlevler

İşlev updateStockPrice artık hem tabloyu hem de değer çizgisi ekranını işler ve kırmızı ve yeşil renkleri yanıp sönmek için kullanır jQuery.Color .

SignalR.StockTicker.js'daki yeni işlevler, pazar durumuna göre düğmeleri etkinleştirir ve devre dışı bırakır. Ayrıca Canlı Hisse Senedi DeğerLeyicisi yatay kaydırmayı durdurur veya başlatır. uygulamasına ticker.clientbirçok işlev eklendiğinden, uygulama bunları eklemek için jQuery genişletme işlevini kullanır.

$.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();
    }
});

Bağlantı kurulduktan sonra ek istemci kurulumu

İstemci bağlantıyı kurduktan sonra yapması gereken bazı ek işler vardır:

  • Uygun marketOpenedmarketClosed veya işlevi çağırmak için pazarın açık mı yoksa kapalı mı olduğunu öğrenin.

  • Düğmelere sunucu yöntemi çağrılarını ekleyin.

$.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();
        });
    });

Uygulama bağlantıyı kurana kadar sunucu yöntemleri düğmelere bağlı değildir. Böylece kod, kullanılabilir olmadan önce sunucu yöntemlerini çağıramaz.

Ek kaynaklar

Bu öğreticide, sunucudan tüm bağlı istemcilere ileti yayınlayan bir SignalR uygulamasının nasıl programlandığını öğrendiniz. Artık iletileri düzenli aralıklarla ve herhangi bir istemciden gelen bildirimlere yanıt olarak yayınlayabilirsiniz. Çok oyunculu çevrimiçi oyun senaryolarında sunucu durumunu korumak için çok iş parçacıklı tekil örnek kavramını kullanabilirsiniz. Bir örnek için SignalR tabanlı ShootR oyununa bakın.

Eşler arası iletişim senaryolarını gösteren öğreticiler için bkz . SignalR ile Çalışmaya Başlama ve SignalR ile Gerçek Zamanlı Güncelleştirme.

SignalR hakkında daha fazla bilgi için aşağıdaki kaynaklara bakın:

Sonraki adımlar

Bu öğreticide şunları yaptınız:

  • Proje oluşturuldu
  • Sunucu kodunu ayarlama
  • Sunucu kodunu inceledim
  • İstemci kodunu ayarlama
  • İstemci kodunu inceledim
  • Uygulamayı test etme
  • Günlüğe kaydetme etkinleştirildi

ASP.NET SignalR 2 kullanan gerçek zamanlı bir web uygulaması oluşturmayı öğrenmek için sonraki makaleye ilerleyin.