Поделиться через


Руководство. Создание высокочастотного приложения в режиме реального времени с помощью SignalR 2

В этом руководстве показано, как создать веб-приложение, использующее ASP.NET SignalR 2 для обеспечения функций обмена сообщениями с высокой частотой. В этом случае "высокочастотное обмен сообщениями" означает, что сервер отправляет обновления с фиксированной скоростью. Вы отправляете до 10 сообщений в секунду.

Создаваемое приложение отображает фигуру, которую пользователи могут перетаскивать. Сервер обновляет положение фигуры во всех подключенных браузерах, чтобы она соответствовала позиции перетаскиваемой фигуры с помощью времени обновления.

Основные понятия, представленные в этом руководстве, содержат приложения в играх в режиме реального времени и других приложений моделирования.

Изучив это руководство, вы:

  • Настройка проекта
  • Создание базового приложения
  • Сопоставление с центром при запуске приложения
  • Добавление клиента
  • Выполнить приложение
  • Добавление цикла клиента
  • Добавление цикла сервера
  • Добавление плавной анимации

Предупреждение

Эта документация не подходит для последней версии SignalR. Взгляните на ASP.NET Core SignalR.

Необходимые компоненты

  • Visual Studio 2017 с рабочей нагрузкой ASP.NET и веб-разработка.

Настройка проекта

В этом разделе описано, как создать проект в Visual Studio 2017.

В этом разделе показано, как использовать Visual Studio 2017 для создания пустого веб-приложения ASP.NET и добавления библиотек SignalR и jQuery.UI.

  1. В Visual Studio создайте веб-приложение ASP.NET.

    Создание веб-сайта

  2. В окне "Новое веб-приложение ASP.NET — MoveShapeDemo" оставьте пустым и нажмите кнопку "ОК".

  3. В Обозреватель решений щелкните проект правой кнопкой мыши и выберите "Добавить>новый элемент".

  4. В разделе "Добавление нового элемента — MoveShapeDemo" выберите "Установленный>visual C#>Web>SignalR", а затем выберите класс Концентратора SignalR (версия 2).

  5. Назовите класс MoveShapeHub и добавьте его в проект.

    На этом шаге создается файл класса MoveShapeHub.cs . Одновременно он добавляет набор файлов скриптов и ссылок на сборки, которые поддерживают SignalR в проект.

  6. Выберите Инструменты>Диспетчер пакетов NuGet>Консоль диспетчера пакетов.

  7. В консоли диспетчер пакетов выполните следующую команду:

    Install-Package jQuery.UI.Combined
    

    Команда устанавливает библиотеку пользовательского интерфейса jQuery. Вы используете его для анимации фигуры.

  8. В Обозреватель решений разверните узел "Скрипты".

    Ссылки на библиотеку скриптов

    Библиотеки скриптов для jQuery, jQueryUI и SignalR отображаются в проекте.

Создание базового приложения

В этом разделе описано, как создать приложение браузера. Приложение отправляет расположение фигуры на сервер во время каждого события перемещения мыши. Сервер передает эти сведения всем другим подключенным клиентам в режиме реального времени. Дополнительные сведения об этом приложении см. в последующих разделах.

  1. Откройте файл MoveShapeHub.cs.

  2. Замените код в файле MoveShapeHub.cs следующим кодом:

    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. Сохраните файл.

Класс MoveShapeHub представляет собой реализацию концентратора SignalR. Как и в руководстве по началу работы с SignalR , концентратор имеет метод, который клиенты вызывают напрямую. В этом случае клиент отправляет объект с новыми координатами X и Y фигуры на сервер. Эти координаты передаются всем другим подключенным клиентам. SignalR автоматически сериализует этот объект с помощью JSON.

Приложение отправляет ShapeModel объект клиенту. Он содержит элементы для хранения позиции фигуры. Версия объекта на сервере также имеет член для отслеживания хранения данных клиента. Этот объект запрещает серверу отправлять данные клиента обратно. Этот член использует JsonIgnore атрибут для сохранения сериализации данных приложения и отправки его обратно клиенту.

Сопоставление с центром при запуске приложения

Затем вы настроите сопоставление с концентратором при запуске приложения. В SignalR 2 добавление класса запуска OWIN создает сопоставление.

  1. В Обозреватель решений щелкните проект правой кнопкой мыши и выберите "Добавить>новый элемент".

  2. В разделе "Добавление нового элемента " MoveShapeDemo" выберите "Установлен>Visual C#>Web" и выберите класс запуска OWIN.

  3. Присвойте классу "Запуск " и нажмите кнопку "ОК".

  4. Замените код по умолчанию в файле Startup.cs следующим кодом:

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

Класс запуска OWIN вызывается MapSignalR при выполнении Configuration метода. Приложение добавляет класс в процесс запуска OWIN с помощью атрибута сборки OwinStartup .

Добавление клиента

Добавьте HTML-страницу для клиента.

  1. В Обозреватель решений щелкните проект правой кнопкой мыши и выберите "Добавить>HTML-страницу".

  2. Назовите страницу по умолчанию и нажмите кнопку "ОК".

  3. В Обозреватель решений щелкните правой кнопкой мыши Default.html и выберите "Задать как начальную страницу".

  4. Замените код по умолчанию в файле Default.html следующим кодом:

    <!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. В Обозреватель решений разверните скрипты.

    Библиотеки скриптов для jQuery и SignalR отображаются в проекте.

    Внимание

    Диспетчер пакетов устанавливает более позднюю версию скриптов SignalR.

  6. Обновите ссылки на скрипты в блоке кода, чтобы соответствовать версиям файлов скриптов в проекте.

Этот код HTML и JavaScript создают красный div вызов shape. Он позволяет перетаскиванию фигуры с помощью библиотеки jQuery и использует drag событие для отправки позиции фигуры на сервер.

Выполнить приложение

Вы можете запустить приложение для его работы. При перетаскивании фигуры вокруг окна браузера фигура также перемещается в других браузерах.

  1. На панели инструментов включите отладку скрипта и нажмите кнопку воспроизведения, чтобы запустить приложение в режиме отладки.

    Снимок экрана: включение режима отладки и выбор воспроизведения.

    Откроется окно браузера с красной фигурой в правом верхнем углу.

  2. Скопируйте URL-адрес страницы.

  3. Откройте другой браузер и вставьте URL-адрес в адресную строку.

  4. Перетащите фигуру в одном из окон браузера. Фигура в другом окне браузера следует.

Хотя функции приложения, использующие этот метод, не рекомендуется использовать модель программирования. Максимальное количество отправленных сообщений не ограничено. В результате клиенты и сервер перегружены сообщениями и производительностью. Кроме того, приложение отображает несвязанную анимацию на клиенте. Эта рывчатая анимация происходит, так как фигура перемещается мгновенно по каждому методу. Лучше, если фигура плавно перемещается к каждому новому расположению. Далее вы узнаете, как устранить эти проблемы.

Добавление цикла клиента

Отправка расположения фигуры на каждом событии перемещения мыши создает ненужный объем сетевого трафика. Приложение должно регулировать сообщения от клиента.

Используйте функцию Javascript setInterval , чтобы настроить цикл, который отправляет новые сведения о положении на сервер с фиксированной скоростью. Этот цикл является основным представлением "игрового цикла". Это многократно называемая функция, которая управляет всеми функциями игры.

  1. Замените клиентский код в файле Default.html следующим кодом:

    <!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>
    

    Внимание

    Необходимо снова заменить ссылки на скрипты. Они должны соответствовать версиям скриптов в проекте.

    Этот новый код добавляет функцию updateServerModel . Он вызывается на фиксированной частоте. Функция отправляет данные позиции на сервер всякий раз, когда moved флаг указывает, что для отправки новых данных позиции.

  2. Нажмите кнопку воспроизведения, чтобы запустить приложение

  3. Скопируйте URL-адрес страницы.

  4. Откройте другой браузер и вставьте URL-адрес в адресную строку.

  5. Перетащите фигуру в одном из окон браузера. Фигура в другом окне браузера следует.

Так как приложение регулирует количество сообщений, отправляемых на сервер, анимация не будет отображаться так же гладко, как и вначале.

Добавление цикла сервера

В текущем приложении сообщения, отправляемые с сервера клиенту, выходят так же часто, как они получены. Этот сетевой трафик представляет аналогичную проблему, как мы видим на клиенте.

Приложение может отправлять сообщения чаще, чем они необходимы. Подключение может стать затопленным в результате. В этом разделе описывается, как обновить сервер для добавления таймера, который регулирует частоту исходящих сообщений.

  1. Замените содержимое MoveShapeHub.cs на следующий код:

    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. Нажмите кнопку воспроизведения, чтобы запустить приложение.

  3. Скопируйте URL-адрес страницы.

  4. Откройте другой браузер и вставьте URL-адрес в адресную строку.

  5. Перетащите фигуру в одном из окон браузера.

Этот код расширяет клиент для добавления Broadcaster класса. Новый класс регулирует исходящие сообщения с помощью Timer класса из платформы .NET.

Хорошо узнать, что сам концентратор является транзитивным. Он создается каждый раз, когда он необходим. Таким образом, приложение создает как одноэлементный Broadcaster . Она использует отложенную инициализацию, чтобы отложить Broadcasterсоздание до тех пор, пока оно не потребуется. Это гарантирует, что приложение создает первый экземпляр концентратора полностью перед запуском таймера.

Затем вызов функции клиентов UpdateShape перемещается из метода концентратора UpdateModel . Он больше не вызывается немедленно, когда приложение получает входящие сообщения. Вместо этого приложение отправляет сообщения клиентам с частотой 25 звонков в секунду. Процесс управляется таймером _broadcastLoop из Broadcaster класса.

Наконец, Broadcaster вместо вызова метода клиента из концентратора напрямую класс должен получить ссылку на текущий операционный _hubContext концентратор. Он получает ссылку с помощью GlobalHost.

Добавление плавной анимации

Приложение почти завершено, но мы могли бы сделать еще одно улучшение. Приложение перемещает фигуру на клиенте в ответ на сообщения сервера. Вместо задания позиции фигуры в новом расположении, заданном сервером, используйте функцию библиотеки animate пользовательского интерфейса JQuery. Он может плавно перемещать фигуру между текущей и новой позицией.

  1. Обновите метод клиента updateShape в файле Default.html , чтобы выглядеть как выделенный код:

    <!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. Нажмите кнопку воспроизведения, чтобы запустить приложение.

  3. Скопируйте URL-адрес страницы.

  4. Откройте другой браузер и вставьте URL-адрес в адресную строку.

  5. Перетащите фигуру в одном из окон браузера.

Перемещение фигуры в другом окне появляется менее рывком. Приложение интерполирует его перемещение с течением времени, а не устанавливает один раз на входящее сообщение.

Этот код перемещает фигуру из старого расположения в новое. Сервер предоставляет положение фигуры в течение интервала анимации. В этом случае это 100 миллисекунда. Приложение очищает любую предыдущую анимацию, выполняемую на фигуре до запуска новой анимации.

Получение кода

Скачивание завершенного проекта

Дополнительные ресурсы

Дополнительные сведения о SignalR см. в следующих ресурсах:

Следующие шаги

Изучив это руководство, вы:

  • Настройка проекта
  • Создание базового приложения
  • Сопоставлено с центром при запуске приложения
  • Добавлен клиент
  • Выполнение приложения
  • Добавлен цикл клиента
  • Добавлен цикл сервера
  • Добавлена плавная анимация

Перейдите к следующей статье, чтобы узнать, как создать веб-приложение, использующее ASP.NET SignalR 2 для предоставления функциональность широковещательной трансляции сервера.