Öğretici: SignalR 2 ile yüksek frekanslı gerçek zamanlı uygulama oluşturma

Bu öğreticide, yüksek frekanslı mesajlaşma işlevselliği sağlamak için ASP.NET SignalR 2 kullanan bir web uygulamasının nasıl oluşturulacağı gösterilmektedir. Bu durumda, "yüksek frekanslı mesajlaşma", sunucunun güncelleştirmeleri sabit bir hızda gönderdiği anlamına gelir. Saniyede en fazla 10 ileti gönderirsiniz.

Oluşturduğunuz uygulama, kullanıcıların sürükleyebileceği bir şekil görüntüler. Sunucu, şeklin tüm bağlı tarayıcılardaki konumunu, zamanlanmış güncelleştirmeleri kullanarak sürüklenen şeklin konumuyla eşleşecek şekilde güncelleştirir.

Bu öğreticide tanıtılan kavramlar, gerçek zamanlı oyun ve diğer simülasyon uygulamalarında uygulamalar içerir.

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

  • Projeyi ayarlama
  • Temel uygulamayı oluşturma
  • Uygulama başlatıldığında hub'a eşleme
  • İstemciyi ekleme
  • Uygulamayı çalıştırma
  • İstemci döngüsünü ekleme
  • Sunucu döngüsünü ekleme
  • Düzgün animasyon ekleme

Uyarı

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

Önkoşullar

Projeyi ayarlama

Bu bölümde, projeyi Visual Studio 2017'de oluşturacaksınız.

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

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

    Web oluşturma

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

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

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

  5. Sınıfı MoveShapeHub olarak adlandırın ve projeye ekleyin.

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

  6. Araçlar>NuGet Paket Yöneticisi>Paket Yöneticisi Konsolu'nu seçin.

  7. Paket Yöneticisi Konsolu'nda şu komutu çalıştırın:

    Install-Package jQuery.UI.Combined
    

    komutu jQuery kullanıcı arabirimi kitaplığını yükler. Şekle animasyon eklemek için bunu kullanırsınız.

  8. Çözüm Gezgini'da Betikler düğümünü genişletin.

    Betik kitaplığı başvuruları

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

Temel uygulamayı oluşturma

Bu bölümde bir tarayıcı uygulaması oluşturacaksınız. Uygulama, her fare taşıma olayı sırasında şeklin konumunu sunucuya gönderir. Sunucu bu bilgileri diğer tüm bağlı istemcilere gerçek zamanlı olarak yayınlar. Bu uygulama hakkında daha fazla bilgiyi sonraki bölümlerde bulabilirsiniz.

  1. MoveShapeHub.cs dosyasını açın.

  2. MoveShapeHub.cs dosyasındaki kodu şu kodla değiştirin:

    using Microsoft.AspNet.SignalR;
    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; }
        }
    }
    
  3. Dosyayı kaydedin.

MoveShapeHub sınıfı bir SignalR hub'ının uygulamasıdır. SignalR ile Çalışmaya Başlama öğreticisinde olduğu gibi hub'da istemcilerin doğrudan çağırdığı bir yöntem vardır. Bu durumda, istemci şeklin yeni X ve Y koordinatlarını içeren bir nesneyi sunucuya gönderir. Bu koordinatlar diğer tüm bağlı istemcilere yayınlanır. SignalR, JSON kullanarak bu nesneyi otomatik olarak seri hale getirmektedir.

Uygulama nesneyi istemciye gönderir ShapeModel . Şeklin konumunu depolamak için üyeleri vardır. Sunucudaki nesnenin sürümü, hangi istemcinin verilerinin depolandığını izlemek için bir üyeye de sahiptir. Bu nesne, sunucunun istemci verilerini kendisine geri göndermesini engeller. Bu üye, uygulamanın verileri seri hale getirmesini ve istemciye geri göndermesini sağlamak için özniteliğini kullanır JsonIgnore .

Uygulama başlatıldığında hub'a eşleme

Ardından, uygulama başlatıldığında hub'a eşlemeyi ayarlarsınız. SignalR 2'de, bir OWIN başlangıç sınıfı eklemek eşlemeyi oluşturur.

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

  2. Yeni Öğe Ekle - MoveShapeDemo bölümünde Yüklü>Visual C#>Web'i ve ardından OWIN Başlangıç Sınıfı'yı 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 Microsoft.Owin;
    using Owin;
    
    [assembly: OwinStartup(typeof(MoveShapeDemo.Startup))]
    namespace MoveShapeDemo
    {
        public class Startup
        {
            public void Configuration(IAppBuilder app)
            {
                // Any connection or hub wire up and configuration should go here
                app.MapSignalR();
            }
        }
    }
    

Uygulama yöntemini yürütürken Configuration OWIN başlangıç sınıfı çağırırMapSignalR. Uygulama, derleme özniteliğini kullanarak sınıfını OWIN'in başlangıç işlemine OwinStartup ekler.

İstemciyi ekleme

İstemcinin HTML sayfasını ekleyin.

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

  2. Sayfayı Varsayılan olarak adlandırın ve Tamam'ı seçin.

  3. Çözüm Gezgini'daDefault.html sağ tıklayın ve Başlangıç Sayfası Olarak Ayarla'yı seçin.

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

    <!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.10.2.min.js"></script>
    <script src="Scripts/jquery-ui-1.10.4.min.js"></script>
    <script src="Scripts/jquery.signalR-2.1.0.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>
    
  5. Çö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.

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

Bu HTML ve JavaScript kodu adlı shapebir kırmızı div oluşturur. jQuery kitaplığını kullanarak şeklin sürükleme davranışını etkinleştirir ve şeklin drag konumunu sunucuya göndermek için olayını kullanır.

Uygulamayı çalıştırma

Uygulamayı çalıştırarak çalışmasını sağlayabilirsiniz. Şekli tarayıcı penceresinin çevresinde sürüklediğinizde, şekil diğer tarayıcılarda da hareket eder.

  1. Araç çubuğunda Betik Hata Ayıklama'yı açın ve ardından 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ü.

    Sağ üst köşede kırmızı şekilli bir tarayıcı penceresi açılır.

  2. Sayfanın URL'sini kopyalayın.

  3. Başka bir tarayıcı açın ve URL'yi adres çubuğuna yapıştırın.

  4. Şekli tarayıcı pencerelerinden birinde sürükleyin. Diğer tarayıcı penceresindeki şekil aşağıdaki gibidir.

Uygulama bu yöntemi kullanarak çalışır ancak önerilen bir programlama modeli değildir. Gönderilen ileti sayısının üst sınırı yoktur. Sonuç olarak, istemciler ve sunucu iletilerle bunalmış olur ve performans düşer. Ayrıca, uygulama istemcide kopuk bir animasyon görüntüler. Bu hıyar animasyon, şeklin her yöntem tarafından anında hareket ettiği için gerçekleşir. Şeklin her yeni konuma sorunsuz bir şekilde taşınması daha iyidir. Ardından bu sorunları nasıl çözeceğinizi öğreneceksiniz.

İstemci döngüsünü ekleme

Şeklin konumunun her fare taşıma olayında gönderilmesi gereksiz miktarda ağ trafiğine neden olur. Uygulamanın istemciden gelen iletileri kısıtlaması gerekir.

Sunucuya sabit bir hızda yeni konum bilgileri gönderen bir döngü ayarlamak için javascript setInterval işlevini kullanın. Bu döngü, bir "oyun döngüsünün" temel bir gösterimidir. Bu, bir oyunun tüm işlevselliğini yönlendiren art arda çağrılan bir işlevdir.

  1. Default.html dosyasındaki istemci kodunu şu kodla değiştirin:

    <!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.10.2.min.js"></script>
    <script src="Scripts/jquery-ui-1.10.4.min.js"></script>
    <script src="Scripts/jquery.signalR-2.1.0.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>
    

    Önemli

    Betik başvurularını yeniden değiştirmeniz gerekir. Bunlar projedeki betiklerin sürümleriyle eşleşmelidir.

    Bu yeni kod işlevi ekler updateServerModel . Sabit bir frekansta çağrılır. bayrağı gönderilecek yeni konum verileri olduğunu gösterdiğinde moved işlev konum verilerini sunucuya gönderir.

  2. Uygulamayı başlatmak için oynat düğmesini seçin

  3. Sayfanın URL'sini kopyalayın.

  4. Başka bir tarayıcı açın ve URL'yi adres çubuğuna yapıştırın.

  5. Şekli tarayıcı pencerelerinden birinde sürükleyin. Diğer tarayıcı penceresindeki şekil aşağıdaki gibidir.

Uygulama sunucuya gönderilen ileti sayısını kısıtladığı için animasyon ilk başta olduğu gibi düzgün görünmez.

Sunucu döngüsünü ekleme

Geçerli uygulamada, sunucudan istemciye gönderilen iletiler alındıkları sıklıkta dışarı çıkar. Bu ağ trafiği, istemcide gördüğümüze benzer bir sorun sunar.

Uygulama, gerektiğinden daha sık ileti gönderebilir. Sonuç olarak bağlantı sular altında olabilir. Bu bölümde, giden iletilerin hızını azaltan bir zamanlayıcı eklemek için sunucunun nasıl güncelleştirildiği açıklanır.

  1. içeriğini MoveShapeHub.cs şu kodla değiştirin:

    using System;
    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; }
        }
        
    }
    
  2. Uygulamayı başlatmak için oynat düğmesini seçin.

  3. Sayfanın URL'sini kopyalayın.

  4. Başka bir tarayıcı açın ve URL'yi adres çubuğuna yapıştırın.

  5. Şekli tarayıcı pencerelerinden birinde sürükleyin.

Bu kod, sınıfını eklemek için istemcisini Broadcaster genişletir. Yeni sınıf, .NET framework'ten sınıfını Timer kullanarak giden iletileri kısıtlar.

Hub'ın kendisinin geçici olduğunu öğrenmek iyi bir şey. Her ihtiyaç duyulduğu zaman oluşturulur. Bu nedenle uygulama, öğesini Broadcaster tekil olarak oluşturur. 'nin oluşturulmasını Broadcastergerekene kadar ertelemek için yavaş başlatmayı kullanır. Bu, uygulamanın zamanlayıcıyı başlatmadan önce ilk hub örneğini tamamen oluşturmasını garanti eder.

İstemcilerin UpdateShape işlevine yapılan çağrı daha sonra hub'ın UpdateModel yönteminin dışına taşınır. Uygulama gelen iletileri aldığında artık hemen çağrılmayacak. Bunun yerine uygulama, iletileri istemcilere saniyede 25 çağrı hızında gönderir. İşlem, sınıfın _broadcastLoop içinden Broadcaster zamanlayıcı tarafından yönetilir.

Son olarak, istemci yöntemini doğrudan hub'dan çağırmak yerine sınıfın Broadcaster şu anda işletim _hubContext hub'ına bir başvuru alması gerekir. ile başvuruyu GlobalHostalır.

Düzgün animasyon ekleme

Uygulama neredeyse bitti, ancak bir iyileştirme daha yapabiliriz. Uygulama, sunucu iletilerine yanıt olarak şekli istemcide taşır. Şeklin konumunu sunucu tarafından verilen yeni konuma ayarlamak yerine JQuery UI kitaplığının animate işlevini kullanın. Şekli geçerli ve yeni konumu arasında sorunsuz bir şekilde taşıyabilir.

  1. Default.html dosyasındaki istemcinin updateShape yöntemini, vurgulanan kod gibi görünecek şekilde güncelleştirin:

    <!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.10.2.min.js"></script>
    <script src="Scripts/jquery-ui-1.10.4.min.js"></script>
    <script src="Scripts/jquery.signalR-2.1.0.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>
    
  2. Uygulamayı başlatmak için oynat düğmesini seçin.

  3. Sayfanın URL'sini kopyalayın.

  4. Başka bir tarayıcı açın ve URL'yi adres çubuğuna yapıştırın.

  5. Şekli tarayıcı pencerelerinden birinde sürükleyin.

Şeklin diğer penceredeki hareketi daha az sarsıntılı görünür. Uygulama, gelen ileti başına bir kez ayarlamak yerine zaman içindeki hareketini ara değer olarak belirler.

Bu kod şekli eski konumdan yenisine taşır. Sunucu, animasyon aralığı boyunca şeklin konumunu verir. Bu durumda, bu 100 milisaniyedir. Uygulama, yeni animasyon başlamadan önce şekilde çalışan önceki animasyonları temizler.

Kodu alma

Tamamlanan Projeyi İndir

Ek kaynaklar

Az önce öğrendiğiniz iletişim paradigması, SignalR ile oluşturulan ShootR oyunu gibi çevrimiçi oyunlar ve diğer simülasyonlar geliştirmek için yararlıdır.

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

Sonraki adımlar

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

  • Projeyi ayarlama
  • Temel uygulama oluşturuldu
  • Uygulama başlatıldığında hub'a eşlendi
  • İstemci eklendi
  • Uygulamayı çalıştır
  • İstemci döngüsü eklendi
  • Sunucu döngüsü eklendi
  • Kesintisiz animasyon eklendi

Sunucu yayını işlevselliği sağlamak için ASP.NET SignalR 2 kullanan bir web uygulaması oluşturmayı öğrenmek için sonraki makaleye ilerleyin.