Делаем чат на ASP.NET с помощью Web Socket

в 13:41, , рубрики: .net, ASP, asp.net mvc 4, метки: ,

Вступление

Я думаю, что многие веб-разработчики задают себе вопрос о том, как передать пользователю какое-либо сообщение, напоминание. Раньше для этого было необходимо постоянно отправлять запросы к веб-серверу, но теперь появилась такая удобная технология, как Web Socket.

В этой статье я хочу показать, как можно написать простой чат на ASP.NET MVC 4 с помощью Web Socket.

Приступаем

Для начала нам необходимо создать пустой проект ASP.NET MVC 4

Делаем чат на ASP.NET с помощью Web Socket

И добавить в него универсальный обработчик ChatHandler

Делаем чат на ASP.NET с помощью Web Socket

Теперь изменим код метода ProcessRequest нашего обработчика на

        public void ProcessRequest(HttpContext context)
        {
            //Если запрос является запросом веб сокета
            if (context.IsWebSocketRequest)
                context.AcceptWebSocketRequest(WebSocketRequest);
        }

Добавим 2 переменные

        // Список всех клиентов
        private static readonly List<WebSocket> Clients = new List<WebSocket>();

        // Блокировка для обеспечения потокабезопасности
        private static readonly ReaderWriterLockSlim Locker = new ReaderWriterLockSlim();

И напишем основной метод нашего чата

 private async Task WebSocketRequest(AspNetWebSocketContext context)
        {
            // Получаем сокет клиента из контекста запроса
            var socket = context.WebSocket;

            // Добавляем его в список клиентов
            Locker.EnterWriteLock();
            try
            {
                Clients.Add(socket);
            }
            finally
            {
                Locker.ExitWriteLock();
            }

            // Слушаем его
            while (true)
            {
                var buffer = new ArraySegment<byte>(new byte[1024]);

                // Ожидаем данные от него
                var result = await socket.ReceiveAsync(buffer, CancellationToken.None);


                //Передаём сообщение всем клиентам
                for (int i = 0; i < Clients.Count; i++)
                {

                    WebSocket client = Clients[i];

                    try
                    {
                        if (client.State == WebSocketState.Open)
                        {
                            await client.SendAsync(buffer, WebSocketMessageType.Text, true, CancellationToken.None);
                        }
                    }

                    catch (ObjectDisposedException)
                    {
                        Locker.EnterWriteLock();
                        try
                        {
                            Clients.Remove(client);
                            i--;
                        }
                        finally
                        {
                            Locker.ExitWriteLock();
                        }
                    }
                }

            }
        }

Теперь наш обработчик должен выглядеть так:

Скрытый текст

public class ChatHandler : IHttpHandler
    {

        // Список всех клиентов
        private static readonly List<WebSocket> Clients = new List<WebSocket>();

        // Блокировка для обеспечения потокабезопасности
        private static readonly ReaderWriterLockSlim Locker = new ReaderWriterLockSlim();

        public void ProcessRequest(HttpContext context)
        {
            //Если запрос является запросом веб сокета
            if (context.IsWebSocketRequest)
                context.AcceptWebSocketRequest(WebSocketRequest);
        }

        private async Task WebSocketRequest(AspNetWebSocketContext context)
        {
            // Получаем сокет клиента из контекста запроса
            var socket = context.WebSocket;

            // Добавляем его в список клиентов
            Locker.EnterWriteLock();
            try
            {
                Clients.Add(socket);
            }
            finally
            {
                Locker.ExitWriteLock();
            }

            // Слушаем его
            while (true)
            {
                var buffer = new ArraySegment<byte>(new byte[1024]);

                // Ожидаем данные от него
                var result = await socket.ReceiveAsync(buffer, CancellationToken.None);


                //Передаём сообщение всем клиентам
                for (int i = 0; i < Clients.Count; i++)
                {

                    WebSocket client = Clients[i];

                    try
                    {
                        if (client.State == WebSocketState.Open)
                        {
                            await client.SendAsync(buffer, WebSocketMessageType.Text, true, CancellationToken.None);
                        }
                    }

                    catch (ObjectDisposedException)
                    {
                        Locker.EnterWriteLock();
                        try
                        {
                            Clients.Remove(client);
                            i--;
                        }
                        finally
                        {
                            Locker.ExitWriteLock();
                        }
                    }
                }

            }
        }
        public bool IsReusable
        {
            get
            {
                return false;
            }
        }
    }

Теперь мы можем написать простенькую html страничку, которая будет содержать Web Socket, подключающийся к нашему обработчику

<!DOCTYPE html>

<html>
<head>
    <title>Простой чат</title>
</head>
<body>
    <input type="text" id="user" />
    <input type="text" id="message" />
    <input type="button" value="send" id="send" />
    <div id='messages'></div>

    <script type="text/javascript">
        var socket,
            $txt = document.getElementById('message'),
            $user = document.getElementById('user'),
            $messages = document.getElementById('messages');

        if (typeof (WebSocket) !== 'undefined') {
            socket = new WebSocket("ws://localhost/SimpleChatApplication/ChatHandler.ashx");
        } else {
            socket = new MozWebSocket("ws://localhost/SimpleChatApplication/ChatHandler.ashx");
        }

        socket.onmessage = function (msg) {
            var $el = document.createElement('p');
            $el.innerHTML = msg.data;
            $messages.appendChild($el);
        };

        socket.onclose = function (event) {
            alert('Мы потеряли её. Пожалуйста, обновите страницу');
        };

        document.getElementById('send').onclick = function () {
            socket.send($user.value + ' : ' + $txt.value);
            $txt.value = '';
        };
    </script>
</body>
</html>

Теперь мы можем запустить наш чат, но вот только свойство context.IsWebSocketRequest будет всегда false.
Это происходит из-за того, что Visual Studio по умолчанию для отладки использует IIS Express, который не поддерживает Web Socket. Для того, чтобы наконец поиграться с сокетами нам необходимо установить IIS и настроить Visual Studio для работы с ним по умолчанию.

Для этого выполним несколько шагов:

Шаг 1. Устанавливаем IIS.
Для этого перейдём в Панель управления -> Программы -> Включение и отключение компонентов Windows
Там найдём службы IIS и поставим на них галку

Делаем чат на ASP.NET с помощью Web Socket

Шаг 2. Настраиваем IIS.
По умолчанию компонент Web Socket в IIS отключён. Чтобы его включить в компонентах Windows пройдём по пути Службы IIS -> Службы Интернета -> Компоненты разработки приложений. Там найдём Протокол WebSocket и поставим на нём галку

Делаем чат на ASP.NET с помощью Web Socket

Шаг 3. Настраиваем Visual Studio.
Чтобы заставить VS использовать IIS для отладки, нам необходимо зайти в свойства проекта -> Веб и там отжать галку Использовать IIS Express. (Если галка у вас не активна, перезапустите студию)

Делаем чат на ASP.NET с помощью Web Socket

Завершение

Теперь мы можем смело запустить наш проект и поприветствовать самого себя!

Делаем чат на ASP.NET с помощью Web Socket

Скачать файл проекта можно здесь.

Автор: RoboNET

  1. altair:

    А ссылка не рабочая.

* - обязательные к заполнению поля


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js