Samouczek: tworzenie aplikacji w czasie rzeczywistym o wysokiej częstotliwości za pomocą usługi SignalR 2
W tym samouczku pokazano, jak utworzyć aplikację internetową korzystającą z usługi ASP.NET SignalR 2 w celu zapewnienia funkcji obsługi komunikatów o wysokiej częstotliwości. W takim przypadku "obsługa komunikatów o wysokiej częstotliwości" oznacza, że serwer wysyła aktualizacje z stałą szybkością. Wysyłasz maksymalnie 10 komunikatów na sekundę.
Utworzona aplikacja wyświetla kształt, który użytkownicy mogą przeciągać. Serwer aktualizuje położenie kształtu we wszystkich połączonych przeglądarkach, aby dopasować położenie przeciąganego kształtu przy użyciu aktualizacji czasowych.
Pojęcia wprowadzone w tym samouczku zawierają aplikacje w grach w czasie rzeczywistym i innych aplikacjach symulacji.
W tym samouczku zostały wykonane następujące czynności:
- Konfigurowanie projektu
- Tworzenie aplikacji podstawowej
- Mapuj na centrum po uruchomieniu aplikacji
- Dodawanie klienta
- Uruchom aplikację
- Dodawanie pętli klienta
- Dodawanie pętli serwera
- Dodawanie płynnej animacji
Ostrzeżenie
Ta dokumentacja nie dotyczy najnowszej wersji usługi SignalR. Przyjrzyj się ASP.NET Core SignalR.
Wymagania wstępne
- Program Visual Studio 2017 z pakietem roboczym Tworzenie aplikacji na platformie ASP.NET i aplikacji internetowych.
Konfigurowanie projektu
W tej sekcji utworzysz projekt w programie Visual Studio 2017.
W tej sekcji pokazano, jak za pomocą programu Visual Studio 2017 utworzyć pustą aplikację internetową ASP.NET i dodać biblioteki SignalR i jQuery.UI.
W programie Visual Studio utwórz aplikację internetową ASP.NET.
W oknie Nowa aplikacja internetowa ASP.NET — MoveShapeDemo pozostaw pole Puste i wybierz przycisk OK.
W Eksplorator rozwiązań kliknij prawym przyciskiem myszy projekt i wybierz polecenie Dodaj>nowy element.
W obszarze Dodawanie nowego elementu — MoveShapeDemo wybierz pozycję Zainstalowano visual>C#>Web>SignalR, a następnie wybierz pozycję SignalR Hub Class (v2).
Nadaj klasie nazwę MoveShapeHub i dodaj ją do projektu.
Ten krok tworzy plik klasy MoveShapeHub.cs . Jednocześnie dodaje zestaw plików skryptów i odwołań do zestawów, które obsługują usługę SignalR do projektu.
Wybierz pozycję Narzędzia NuGet>Menedżer pakietów> Menedżer pakietów Konsola.
W konsoli Menedżer pakietów uruchom następujące polecenie:
Install-Package jQuery.UI.Combined
Polecenie instaluje bibliotekę interfejsu użytkownika jQuery. Służy do animowania kształtu.
W Eksplorator rozwiązań rozwiń węzeł Skrypty.
Biblioteki skryptów dla bibliotek jQuery, jQueryUI i SignalR są widoczne w projekcie.
Tworzenie aplikacji podstawowej
W tej sekcji utworzysz aplikację przeglądarki. Aplikacja wysyła lokalizację kształtu na serwer podczas każdego zdarzenia przenoszenia myszy. Serwer rozgłasza te informacje wszystkim innym połączonym klientom w czasie rzeczywistym. Więcej informacji o tej aplikacji można dowiedzieć się w kolejnych sekcjach.
Otwórz plik MoveShapeHub.cs.
Zastąp kod w pliku MoveShapeHub.cs następującym kodem:
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; } } }
Zapisz plik.
Klasa MoveShapeHub
jest implementacją koncentratora SignalR. Podobnie jak w samouczku Wprowadzenie do usługi SignalR , centrum ma metodę wywoływaną bezpośrednio przez klientów. W takim przypadku klient wysyła obiekt z nowymi współrzędnymi X i Y kształtu do serwera. Te współrzędne są emitowane do wszystkich innych połączonych klientów. Usługa SignalR automatycznie serializuje ten obiekt przy użyciu formatu JSON.
Aplikacja wysyła ShapeModel
obiekt do klienta. Zawiera elementy członkowskie do przechowywania położenia kształtu. Wersja obiektu na serwerze ma również element członkowski do śledzenia, które dane klienta są przechowywane. Ten obiekt uniemożliwia serwerowi wysyłanie danych klienta z powrotem do samego siebie. Ten element członkowski używa atrybutu JsonIgnore
, aby aplikacja nie serializować danych i wysyłać je z powrotem do klienta.
Mapuj na centrum po uruchomieniu aplikacji
Następnie skonfigurujesz mapowanie na centrum po uruchomieniu aplikacji. W usłudze SignalR 2 dodanie klasy uruchamiania OWIN tworzy mapowanie.
W Eksplorator rozwiązań kliknij prawym przyciskiem myszy projekt i wybierz polecenie Dodaj>nowy element.
W obszarze Dodaj nowy element — MoveShapeDemo wybierz pozycję Zainstalowano program>Visual C#>Web, a następnie wybierz pozycję Klasa uruchamiania OWIN.
Nadaj klasie nazwę Startup i wybierz przycisk OK.
Zastąp domyślny kod w pliku Startup.cs następującym kodem:
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(); } } }
Klasa uruchamiania OWIN wywołuje metodę MapSignalR
, gdy aplikacja wykonuje metodę Configuration
. Aplikacja dodaje klasę do procesu uruchamiania OWIN przy użyciu atrybutu OwinStartup
zestawu.
Dodawanie klienta
Dodaj stronę HTML dla klienta.
W Eksplorator rozwiązań kliknij prawym przyciskiem myszy projekt i wybierz pozycję Dodaj>stronę HTML.
Nadaj stronie nazwę Domyślna i wybierz przycisk OK.
W Eksplorator rozwiązań kliknij prawym przyciskiem myszy Default.html i wybierz pozycję Ustaw jako stronę początkową.
Zastąp kod domyślny w pliku Default.html następującym kodem:
<!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>
W Eksplorator rozwiązań rozwiń węzeł Skrypty.
Biblioteki skryptów dla bibliotek jQuery i SignalR są widoczne w projekcie.
Ważne
Menedżer pakietów instaluje nowszą wersję skryptów usługi SignalR.
Zaktualizuj odwołania do skryptu w bloku kodu, aby odpowiadały wersjom plików skryptów w projekcie.
Ten kod HTML i JavaScript tworzy czerwony div
o nazwie shape
. Umożliwia ona przeciąganie kształtu przy użyciu biblioteki jQuery i używa drag
zdarzenia do wysłania położenia kształtu na serwer.
Uruchom aplikację
Możesz uruchomić aplikację, aby ją wykonać. Przeciągając kształt wokół okna przeglądarki, kształt jest również przesuwany w innych przeglądarkach.
Na pasku narzędzi włącz pozycję Debugowanie skryptu, a następnie wybierz przycisk odtwarzania, aby uruchomić aplikację w trybie debugowania.
Zostanie otwarte okno przeglądarki z czerwonym kształtem w prawym górnym rogu.
Skopiuj adres URL strony.
Otwórz inną przeglądarkę i wklej adres URL na pasku adresu.
Przeciągnij kształt w jednym z okien przeglądarki. Kształt w innym oknie przeglądarki jest następujący.
Chociaż funkcje aplikacji korzystające z tej metody nie są zalecanym modelem programowania. Nie ma górnego limitu liczby wysyłanych komunikatów. W związku z tym klienci i serwer są przeciążeni komunikatami i wydajnością. Ponadto aplikacja wyświetla rozłączną animację na kliencie. Ta szarpnięta animacja ma miejsce, ponieważ kształt jest przesuwany natychmiast przez każdą metodę. Lepiej jest, jeśli kształt przesuwa się płynnie do każdej nowej lokalizacji. Następnie dowiesz się, jak rozwiązać te problemy.
Dodawanie pętli klienta
Wysłanie lokalizacji kształtu na każdym zdarzeniu przenoszenia myszy powoduje niepotrzebny ruch sieciowy. Aplikacja musi ograniczać komunikaty z klienta.
Użyj funkcji javascript setInterval
, aby skonfigurować pętlę, która wysyła nowe informacje o pozycji do serwera z stałą szybkością. Ta pętla jest podstawową reprezentacją "pętli gry". Jest to wielokrotnie nazywana funkcja, która napędza wszystkie funkcje gry.
Zastąp kod klienta w pliku Default.html następującym kodem:
<!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>
Ważne
Należy ponownie zastąpić odwołania do skryptu. Muszą one być zgodne z wersjami skryptów w projekcie.
Ten nowy kod dodaje
updateServerModel
funkcję. Jest wywoływany z częstotliwością stałą. Funkcja wysyła dane pozycji do serwera za każdym razem, gdymoved
flaga wskazuje, że istnieją nowe dane położenia do wysłania.Wybierz przycisk odtwarzania, aby uruchomić aplikację
Skopiuj adres URL strony.
Otwórz inną przeglądarkę i wklej adres URL na pasku adresu.
Przeciągnij kształt w jednym z okien przeglądarki. Kształt w innym oknie przeglądarki jest następujący.
Ponieważ aplikacja ogranicza liczbę komunikatów wysyłanych do serwera, animacja nie będzie wyświetlana tak płynnie, jak wcześniej.
Dodawanie pętli serwera
W bieżącej aplikacji komunikaty wysyłane z serwera do klienta wyjdą tak często, jak są odbierane. Ten ruch sieciowy stanowi podobny problem, jak widać na kliencie.
Aplikacja może wysyłać komunikaty częściej niż są potrzebne. W rezultacie połączenie może zostać zalane. W tej sekcji opisano sposób aktualizowania serwera w celu dodania czasomierza, który ogranicza szybkość komunikatów wychodzących.
Zastąp zawartość
MoveShapeHub.cs
tego kodu następującym kodem: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; } } }
Wybierz przycisk odtwarzania, aby uruchomić aplikację.
Skopiuj adres URL strony.
Otwórz inną przeglądarkę i wklej adres URL na pasku adresu.
Przeciągnij kształt w jednym z okien przeglądarki.
Ten kod rozszerza klienta, aby dodać klasę Broadcaster
. Nowa klasa ogranicza komunikaty wychodzące przy użyciu Timer
klasy z platformy .NET Framework.
Dobrze jest dowiedzieć się, że sam koncentrator jest przejściowy. Jest tworzony za każdym razem, gdy jest potrzebny. W związku z tym aplikacja tworzy Broadcaster
element jako pojedynczy obiekt. Używa leniwej inicjalizacji, aby odroczyć Broadcaster
tworzenie, dopóki nie będzie potrzebny. Gwarantuje to całkowite utworzenie przez aplikację pierwszego wystąpienia centrum przed uruchomieniem czasomierza.
Wywołanie funkcji klienta UpdateShape
jest następnie przenoszone z metody centrum UpdateModel
. Nie jest już wywoływana natychmiast, gdy aplikacja odbiera komunikaty przychodzące. Zamiast tego aplikacja wysyła komunikaty do klientów w tempie 25 wywołań na sekundę. Proces jest zarządzany przez _broadcastLoop
czasomierz z poziomu Broadcaster
klasy .
Na koniec zamiast wywoływać metodę klienta bezpośrednio z centrum, Broadcaster
klasa musi uzyskać odwołanie do aktualnie działającego _hubContext
centrum. Pobiera odwołanie za pomocą polecenia GlobalHost
.
Dodawanie płynnej animacji
Aplikacja jest prawie zakończona, ale możemy wprowadzić jeszcze jedną poprawę. Aplikacja przenosi kształt na klienta w odpowiedzi na komunikaty serwera. Zamiast ustawiać położenie kształtu na nową lokalizację nadaną przez serwer, użyj funkcji biblioteki animate
interfejsu użytkownika JQuery. Może płynnie przenosić kształt między jego bieżącą i nową pozycją.
Zaktualizuj metodę klienta
updateShape
w pliku Default.html , aby wyglądała jak wyróżniony kod:<!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>
Wybierz przycisk odtwarzania, aby uruchomić aplikację.
Skopiuj adres URL strony.
Otwórz inną przeglądarkę i wklej adres URL na pasku adresu.
Przeciągnij kształt w jednym z okien przeglądarki.
Ruch kształtu w innym oknie wydaje się mniej szarpnięta. Aplikacja interpoluje jego ruch w czasie, a nie jest ustawiany raz na przychodzący komunikat.
Ten kod przenosi kształt ze starej lokalizacji do nowej. Serwer nadaje położenie kształtu w trakcie interwału animacji. W tym przypadku jest to 100 milisekund. Aplikacja czyści wszystkie poprzednie animacje uruchomione na kształcie przed rozpoczęciem nowej animacji.
Uzyskiwanie kodu
Pobieranie ukończonego projektu
Dodatkowe zasoby
Aby uzyskać więcej informacji na temat usługi SignalR, zobacz następujące zasoby:
Następne kroki
W tym samouczku zostały wykonane następujące czynności:
- Konfigurowanie projektu
- Utworzono aplikację podstawową
- Zamapowane na centrum po uruchomieniu aplikacji
- Dodano klienta
- Uruchom aplikację
- Dodano pętlę klienta
- Dodano pętlę serwera
- Dodano płynną animację
Przejdź do następnego artykułu, aby dowiedzieć się, jak utworzyć aplikację internetową, która używa ASP.NET SignalR 2 w celu zapewnienia funkcji emisji serwera.