SignalR 1.x ile Yüksek Sıklıkta Gerçek Zamanlı

Tarafından Patrick Fletcher

Uyarı

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

Bu öğreticide, yüksek frekanslı mesajlaşma işlevselliği sağlamak için ASP.NET SignalR kullanan bir web uygulamasının nasıl oluşturulacağı gösterilmektedir. Bu durumda yüksek frekanslı mesajlaşma, sabit bir hızda gönderilen güncelleştirmeler anlamına gelir; bu uygulama söz konusu olduğunda, saniyede en fazla 10 ileti.

Bu öğreticide oluşturacağınız uygulama, kullanıcıların sürükleyebileceği bir şekil görüntüler. Şeklin diğer tüm bağlı tarayıcılardaki konumu, zamanlanmış güncelleştirmeler kullanılarak sürüklenen şeklin konumuyla eşleşecek şekilde güncelleştirilir.

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

Öğreticideki yorumlar kabul edilir. Öğreticiyle doğrudan ilgili olmayan sorularınız varsa bunları ASP.NET SignalR forumunu veya StackOverflow.com gönderebilirsiniz.

Genel Bakış

Bu öğreticide, bir nesnenin durumunu diğer tarayıcılarla gerçek zamanlı olarak paylaşan bir uygulamanın nasıl oluşturulacağı gösterilmektedir. Oluşturacağımız uygulamaya MoveShape adı verilir. MoveShape sayfasında kullanıcının sürükleyebileceği bir HTML Div öğesi görüntülenir; Kullanıcı Div'i sürüklediğinde, yeni konumu sunucuya gönderilir ve böylece diğer tüm bağlı istemcilere şeklin konumunu eşleşecek şekilde güncelleştirmelerini söyler.

MoveShape uygulama sayfasını gösteren ekran görüntüsü.

Bu öğreticide oluşturulan uygulama, Damian Edwards'ın bir tanıtımını temel alır. Bu tanıtımı içeren bir video burada görülebilir.

Öğretici, şekil sürüklendikçe tetiklenen her olaydan SignalR iletilerinin nasıl gönderileceğini göstererek başlar. Her bağlı istemci, her ileti alındığında şeklin yerel sürümünün konumunu güncelleştirir.

Uygulama bu yöntemi kullanarak çalışacak olsa da, bu önerilen bir programlama modeli değildir, çünkü gönderilen ileti sayısının üst sınırı yoktur, bu nedenle istemciler ve sunucu iletilere boğulabilir ve performans düşebilir. İstemcide görüntülenen animasyon da kopuk olur çünkü şekil her yeni konuma sorunsuz bir şekilde taşınmak yerine her yöntem tarafından anında taşınır. Öğreticinin sonraki bölümlerinde, iletilerin istemci veya sunucu tarafından gönderilme hızını kısıtlayan bir zamanlayıcı işlevinin nasıl oluşturulacağı ve şeklin konumlar arasında sorunsuz bir şekilde nasıl taşınacağı gösterilmektedir. Bu öğreticide oluşturulan uygulamanın son sürümü Kod Galerisi'nden indirilebilir.

Bu öğretici aşağıdaki bölümleri içerir:

Önkoşullar

Bu öğretici için Visual Studio 2012 veya Visual Studio 2010 gerekir. Visual Studio 2010 kullanılırsa, proje .NET Framework 4.5 yerine .NET Framework 4 kullanır.

Visual Studio 2012 kullanıyorsanız, ASP.NET and Web Tools 2012.2 güncelleştirmesini yüklemeniz önerilir. Bu güncelleştirme yayımlama iyileştirmeleri, yeni işlevler ve yeni şablonlar gibi yeni özellikler içerir.

Visual Studio 2010'larınız varsa NuGet'in yüklü olduğundan emin olun.

Proje oluşturma

Bu bölümde projeyi Visual Studio'da oluşturacağız.

  1. Dosyamenüsünden Yeni Proje'ye tıklayın.

  2. Yeni Proje iletişim kutusunda Şablonlar'ın altında C# öğesini genişletin ve Web'i seçin.

  3. Boş Web Uygulaması şablonunu ASP.NET seçin, projeye MoveShapeDemo adını verin ve Tamam'a tıklayın.

    Yeni proje oluşturma

SignalR ve JQuery.UI NuGet Paketlerini Ekleme

Bir NuGet paketi yükleyerek bir projeye SignalR işlevselliği ekleyebilirsiniz. Bu öğreticide, şeklin sürüklenip animasyonlu olmasını sağlamak için JQuery.UI paketi de kullanılır.

  1. Araçlar |'a tıklayın NuGet Paket Yöneticisi | Paket Yöneticisi Konsolu.

  2. Paket yöneticisine aşağıdaki komutu girin.

    Install-Package Microsoft.AspNet.SignalR -Version 1.1.3
    

    SignalR paketi, bağımlılık olarak bir dizi diğer NuGet paketini yükler. Yükleme tamamlandığında, ASP.NET bir uygulamada SignalR kullanmak için gereken tüm sunucu ve istemci bileşenlerine sahip olursunuz.

  3. JQuery ve JQuery.UI paketlerini yüklemek için paket yöneticisi konsoluna aşağıdaki komutu girin.

    Install-Package jQuery.ui.combined
    

Temel uygulamayı oluşturma

Bu bölümde, her fare taşıma olayı sırasında şeklin konumunu sunucuya gönderen bir tarayıcı uygulaması oluşturacağız. Sunucu daha sonra bu bilgileri alınan diğer tüm bağlı istemcilere yayınlar. Bu uygulamayı sonraki bölümlerde genişleteceğiz.

  1. Çözüm Gezgini'da projeye sağ tıklayın ve Ekle, Sınıf... öğesini seçin. Sınıfı MoveShapeHub olarak adlandırın ve Ekle'ye tıklayın.

  2. Yeni MoveShapeHub sınıfındaki kodu aşağıdaki kodla değiştirin.

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

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

    İstemciye (ShapeModel) gönderilecek nesne, şeklin konumunu depolamak için üyeler içerir. Sunucudaki nesnenin sürümü, belirli bir istemcinin kendi verilerini göndermemesi için hangi istemcinin verilerinin depolandığını izlemek için bir üye de içerir. Bu üye, seri hale getirilip istemciye gönderilmesini korumak için özniteliğini kullanır JsonIgnore .

  3. Ardından, uygulama başlatıldığında hub'ı ayarlayacağız. Çözüm Gezgini'da projeye sağ tıklayın ve ardından Ekle | öğesine tıklayın. Genel Uygulama Sınıfı. Varsayılan Genel adını kabul edin ve Tamam'a tıklayın.

    Genel Uygulama Sınıfı Ekle

  4. Global.asax.cs sınıfında sağlanan using deyimlerinden sonra aşağıdaki using deyimi ekleyin.

    using System.Web.Routing;
    
  5. SignalR için varsayılan yolu kaydetmek için Global sınıfının yöntemine aşağıdaki kod Application_Start satırını ekleyin.

    RouteTable.Routes.MapHubs();
    

    global.asax dosyanız aşağıdaki gibi görünmelidir:

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Web;
    using System.Web.Security;
    using System.Web.SessionState;
    
    using System.Web.Routing;
    
    namespace MoveShapeDemo
    {
        public class Global : System.Web.HttpApplication
        {
            protected void Application_Start(object sender, EventArgs e)
            {
                RouteTable.Routes.MapHubs();
            }
        }
    }
    
  6. Ardından istemciyi ekleyeceğiz. Çözüm Gezgini'da projeye sağ tıklayın ve ardından Ekle | öğesine tıklayın. Yeni Öğe. Yeni Öğe Ekle iletişim kutusunda Html Sayfası'nı seçin. Sayfaya uygun bir ad verin ( Default.htmlgibi) ve Ekle'ye tıklayın.

  7. Çözüm Gezgini'da, yeni oluşturduğunuz sayfaya sağ tıklayın ve Başlangıç Sayfası Olarak Ayarla'ya tıklayın.

  8. HTML sayfasındaki varsayılan kodu aşağıdaki kod parçacığıyla değiştirin.

    Not

    Aşağıdaki betik başvurularının Betikler klasöründe projenize eklenen paketlerle eşleştiğini doğrulayın. Visual Studio 2010'da projeye eklenen JQuery ve SignalR sürümü aşağıdaki sürüm numaralarıyla eşleşmeyebilir.

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

    Yukarıdaki HTML ve JavaScript kodu Shape adlı kırmızı bir Div oluşturur, jQuery kitaplığını kullanarak şeklin sürükleme davranışını etkinleştirir ve şeklin olayını kullanarak şeklin drag konumunu sunucuya gönderir.

  9. F5 tuşuna basarak uygulamayı başlatın. Sayfanın URL'sini kopyalayın ve ikinci bir tarayıcı penceresine yapıştırın. Şekli tarayıcı pencerelerinden birinde sürükleyin; diğer tarayıcı penceresindeki şeklin hareket etmesi gerekir.

    Bir tarayıcı penceresinde sürüklediğiniz şeklin başka bir pencerede nasıl hareket ettiğinizi gösteren ekran görüntüsü.

İstemci döngüsünü ekleme

Her fare taşıma olayında şeklin konumunun gönderilmesi gereksiz miktarda ağ trafiği oluşturacağı için istemciden gelen iletilerin kısıtlanması gerekir. Sabit bir hızda sunucuya yeni konum bilgileri gönderen bir döngü ayarlamak için javascript setInterval işlevini kullanacağız. Bu döngü, bir oyunun veya başka bir simülasyonun tüm işlevlerini yönlendiren ve sürekli olarak adlandırılan bir işlev olan "oyun döngüsünün" çok temel bir gösterimidir.

  1. HTML sayfasındaki istemci kodunu aşağıdaki kod parçacığıyla eşleşecek ş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.6.4.js"></script>
    <script src="Scripts/jquery-ui-1.10.2.js"></script>
    <script src="Scripts/jquery.signalR-1.0.1.js"></script>
    <script src="/signalr/hubs"></script>
    <script>
            $(function () {
                var moveShapeHub = $.connection.moveShapeHub,
                    $shape = $("#shape"),
                    // Send a maximum of 10 messages per second 
                    // (mouse movements trigger a lot of messages)
                    messageFrequency = 10, 
                    // Determine how often to send messages in
                    // time to abide by the messageFrequency
                    updateRate = 1000 / messageFrequency, 
                    shapeModel = {
                        left: 0,
                        top: 0
                    },
                    moved = false;
    
                moveShapeHub.client.updateShape = function (model) {
                    shapeModel = model;
                    $shape.css({ left: model.left, top: model.top });
                };
    
                $.connection.hub.start().done(function () {
                    $shape.draggable({
                        drag: function () {
                            shapeModel = $shape.offset();
                            moved = true;
                        }
                    });
    
                    // Start the client side server update interval
                    setInterval(updateServerModel, updateRate);
                });
    
                function updateServerModel() {
                    // Only update server if we have a new movement
                    if (moved) {
                        moveShapeHub.server.updateModel(shapeModel);
                        moved = false;
                    }
                }
            });
    </script>
    
        <div id="shape" />
    </body>
    </html>
    

    Yukarıdaki güncelleştirme, sabit bir frekansta çağrılan işlevi ekler updateServerModel . Bayrak gönderilecek yeni konum verileri olduğunu gösterdiğinde moved bu işlev konum verilerini sunucuya gönderir.

  2. F5 tuşuna basarak uygulamayı başlatın. Sayfanın URL'sini kopyalayın ve ikinci bir tarayıcı penceresine yapıştırın. Şekli tarayıcı pencerelerinden birinde sürükleyin; şeklin diğer tarayıcı penceresinde hareket etmesi gerekir. Sunucuya gönderilen ileti sayısı azaltılacağından, animasyon önceki bölümde olduğu gibi düzgün görünmez.

    Bir tarayıcı penceresinde sürüklediğiniz şeklin, istemci döngüsü eklediğinizde başka bir pencerede nasıl hareket ettiğinizi gösteren ekran görüntüsü.

Sunucu döngüsünü ekleme

Geçerli uygulamada, sunucudan istemciye gönderilen iletiler alındığı sıklıkta dışarı gider. Bu, istemcide görüldüğü gibi benzer bir sorun sunar; iletileri gerektiğinden daha sık gönderilebilir ve bunun sonucunda bağlantı sular altında kalır. Bu bölümde, giden iletilerin hızını kısıtlayan bir zamanlayıcı uygulamak için sunucunun nasıl güncelleştirildiği açıklanır.

  1. öğesinin içeriğini MoveShapeHub.cs aşağıdaki kod parçacığıyla değiştirin.

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

    Yukarıdaki kod, .NET framework'ten sınıfını kullanarak giden iletileri kısıtlayan sınıfını eklemek Broadcaster için istemciyi Timer genişletir.

    Hub'ın kendisi geçici olduğundan (her gerektiğinde oluşturulur), Broadcaster tekil olarak oluşturulur. Gecikmeli başlatma (.NET 4'te kullanıma sunulan), ilk hub örneğinin zamanlayıcı başlatılmadan önce tamamen oluşturulmasını sağlayarak oluşturulmasını gerekene kadar ertelemek için kullanılır.

    İstemcilerin UpdateShape işlevine yapılan çağrı daha sonra hub'ın UpdateModel yönteminden taşınır, böylece gelen iletiler alındığında artık hemen çağrılmaması sağlanır. Bunun yerine, istemcilere iletiler, sınıfın içinden Broadcaster zamanlayıcı tarafından _broadcastLoop yönetilen saniyede 25 çağrı hızında gönderilir.

    Son olarak, istemci yöntemini doğrudan hub'dan çağırmak yerine sınıfının Broadcaster kullanarak şu anda işletim hub'ına (_hubContext) GlobalHostbir başvuru alması gerekir.

  2. F5 tuşuna basarak uygulamayı başlatın. Sayfanın URL'sini kopyalayın ve ikinci bir tarayıcı penceresine yapıştırın. Şekli tarayıcı pencerelerinden birinde sürükleyin; şeklin diğer tarayıcı penceresinde hareket etmesi gerekir. Tarayıcıda önceki bölümden görünür bir fark olmayacaktır, ancak istemciye gönderilen ileti sayısı kısıtlanır.

    Sunucu döngüsü eklediğinizde bir tarayıcı penceresinde sürüklediğiniz şeklin başka bir pencerede nasıl hareket ettiğinizi gösteren ekran görüntüsü.

İstemciye düzgün animasyon ekleme

Uygulama neredeyse tamamlandı, ancak sunucu iletilerine yanıt olarak taşınan şeklin istemcideki hareketinde bir geliştirme daha yapabiliriz. Şeklin konumunu sunucu tarafından verilen yeni konuma ayarlamak yerine JQuery UI kitaplığının animate işlevini kullanarak şekli geçerli ve yeni konumu arasında sorunsuz bir şekilde taşıyacağız.

  1. İstemcinin updateShape yöntemini aşağıda 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.6.4.js"></script>
    <script src="Scripts/jquery-ui-1.10.2.js"></script>
    <script src="Scripts/jquery.signalR-1.0.1.js"></script>
    <script src="/signalr/hubs"></script>
    <script>
            $(function () {
                var moveShapeHub = $.connection.moveShapeHub,
                    $shape = $("#shape"),
                    // Send a maximum of 10 messages per second 
                    // (mouse movements trigger a lot of messages)
                    messageFrequency = 10, 
                    // Determine how often to send messages in
                    // time to abide by the messageFrequency
                    updateRate = 1000 / messageFrequency, 
                    shapeModel = {
                        left: 0,
                        top: 0
                    },
                    moved = false;
    
                 moveShapeHub.client.updateShape = function (model) {
                     shapeModel = model;
                     // Gradually move the shape towards the new location (interpolate)
                     // The updateRate is used as the duration because by the time 
                     // we get to the next location we want to be at the "last" location
                     // We also clear the animation queue so that we start a new 
                     // animation and don't lag behind.
                     $shape.animate(shapeModel, { duration: updateRate, queue: false });
                };
    
                $.connection.hub.start().done(function () {
                    $shape.draggable({
                        drag: function () {
                            shapeModel = $shape.offset();
                            moved = true;
                        }
                    });
    
                    // Start the client side server update interval
                    setInterval(updateServerModel, updateRate);
                });
    
                function updateServerModel() {
                    // Only update server if we have a new movement
                    if (moved) {
                        moveShapeHub.server.updateModel(shapeModel);
                        moved = false;
                    }
                }
            });
    </script>
    
        <div id="shape" />
    </body>
    </html>
    

    Yukarıdaki kod, animasyon aralığı boyunca şekli eski konumdan sunucu tarafından verilen yeniye taşır (bu örnekte 100 milisaniye). Şekil üzerinde çalışan önceki animasyonlar, yeni animasyon başlamadan önce temizlenir.

  2. F5 tuşuna basarak uygulamayı başlatın. Sayfanın URL'sini kopyalayın ve ikinci bir tarayıcı penceresine yapıştırın. Şekli tarayıcı pencerelerinden birinde sürükleyin; şeklin diğer tarayıcı penceresinde hareket etmesi gerekir. Şeklin diğer penceredeki hareketi, gelen ileti başına bir kez ayarlamak yerine zaman içinde ilişkilendirilmiş olduğundan daha az hıyarlı görünmelidir.

    bir tarayıcı penceresinde sürüklediğiniz şeklin, istemciye düzgün animasyon eklediğinizde başka bir pencerede nasıl hareket ettiğinizi gösteren ekran görüntüsü.

Diğer Adımlar

Bu öğreticide, istemciler ve sunucular arasında yüksek frekanslı iletiler gönderen bir SignalR uygulamasını programlamayı öğrendiniz. Bu iletişim paradigması, SignalR ile oluşturulan ShootR oyunu gibi çevrimiçi oyunlar ve diğer simülasyonlar geliştirmek için kullanışlıdır.

Bu öğreticide oluşturulan uygulamanın tamamı Kod Galerisi'nden indirilebilir.

SignalR geliştirme kavramları hakkında daha fazla bilgi edinmek için SignalR kaynak kodu ve kaynakları için aşağıdaki siteleri ziyaret edin: