Öğ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
- ASP.NET ve web geliştirme iş yüküyle Visual Studio 2017.
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.
Visual Studio'da bir ASP.NET Web Uygulaması oluşturun.
Yeni ASP.NET Web Uygulaması - MoveShapeDemo penceresinde Boş'u seçili bırakın ve Tamam'ı seçin.
Çözüm Gezgini'da projeye sağ tıklayın veYeni Öğe Ekle'yi> seçin.
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.
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.
Araçlar>NuGet Paket Yöneticisi>Paket Yöneticisi Konsolu'nu seçin.
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.
Çözüm Gezgini'da Betikler düğümünü genişletin.
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.
MoveShapeHub.cs dosyasını açın.
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; } } }
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.
Çözüm Gezgini'da projeye sağ tıklayın veYeni Öğe Ekle'yi> seçin.
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.
Sınıfı Başlangıç olarak adlandırın ve Tamam'ı seçin.
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.
Çözüm Gezgini'da projeye sağ tıklayın veHTML SayfasıEkle'yi> seçin.
Sayfayı Varsayılan olarak adlandırın ve Tamam'ı seçin.
Çözüm Gezgini'daDefault.html sağ tıklayın ve Başlangıç Sayfası Olarak Ayarla'yı seçin.
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>
Çö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.
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ı shape
bir 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.
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.
Sağ üst köşede kırmızı şekilli bir tarayıcı penceresi açılır.
Sayfanın URL'sini kopyalayın.
Başka bir tarayıcı açın ve URL'yi adres çubuğuna yapıştırın.
Ş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.
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ğindemoved
işlev konum verilerini sunucuya gönderir.Uygulamayı başlatmak için oynat düğmesini seçin
Sayfanın URL'sini kopyalayın.
Başka bir tarayıcı açın ve URL'yi adres çubuğuna yapıştırın.
Ş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.
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; } } }
Uygulamayı başlatmak için oynat düğmesini seçin.
Sayfanın URL'sini kopyalayın.
Başka bir tarayıcı açın ve URL'yi adres çubuğuna yapıştırın.
Ş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ı Broadcaster
gerekene 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 GlobalHost
alı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.
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>
Uygulamayı başlatmak için oynat düğmesini seçin.
Sayfanın URL'sini kopyalayın.
Başka bir tarayıcı açın ve URL'yi adres çubuğuna yapıştırın.
Ş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
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.