WebSocket & ASP.NET
In this topic, I want to tell how to organize a WebSocket connection between a browser that supports WebSocket and an ASP.NET application.
The article describes how to organize a connection and send a message to a connected client. Also, at the end of the article, there is a link to the source code of the working application.
The article and the application are just an example of how this all works, and how ASP.NET and WebSockets can be connected, and it hardly claims to be an implementation guide in its current form, but it demonstrates the basics well and can be improved.
Why WebSockets are needed and what their advantages are, I think it’s not necessary to tell. Personally, I think that there are really not enough of them, so that you can make full-fledged client applications in JavaScript without tricks like Comet (great article here) or periodic requests.
But specifically, this technology seriously interested me in finding a solution to a small “problem” of working with Comet in the Chrome browser.
When organizing using Comet technology, some browsers, such as Chrome, behave in such a way that it seems as if the page is constantly loading, the same Chrome writes “waiting for a request” and the cursor always remains in a waiting state.
This is of course unpleasant.
Yes, and just why use a workaround when there is a more suitable technology for this and it seems possible to study it.
So the connection itself. On the client side (JavaScript), the browser provides a special WebSocket class.
Here is his description from here
Using it, we open a connection to the server and subscribe to the necessary events, as well as send messages to the server after the connection.
As you can see from the code above, our server will wait for connections at localhost: 8181.
In this example, all subscriber functions simply display information in a text field, and we send nothing to the server. After connecting, this is quite simple, but in this example it will only complicate things a bit.
So the server. Since the ASP.NET application / website works only when processing requests, and we need to constantly wait for connections, we must start a separate thread. Let's do it at Global.asax. The stream and server will be handled by our special classic.
In the Start function, we simply start Thread, which will wait for the connection, and in End we clean it up. All this can be seen in more detail in the source code, which I will give at the end of the article.
So, hereinafter the code of the most important function, but first I will briefly tell you what will happen to make it easier to navigate.
And here are the promised sources.
dl.dropbox.com/u/3945288/WebSocketsArticle.zip
This is the simplest example, it has drawbacks, for example, the lack of multithreading when processing clients. And also, there is still room for improvement, for example, to provide access to the user session.
I will be glad if the article is liked and helps someone, I will try to develop the topic and write more.
UPD: In the comments, they noticed that the implementation for the previous revision 75, the current 76, in which added security. I will try to make a version that will work with both editions, but apparently not today.
For those who asked me to share my best practices, I uploaded everything here . In theory, everything should work but does not work :), somewhere a jamb but the brain does not notice it anymore.
UPD2: As promised, here is a version that supports both versions 75 and 76.
The article describes how to organize a connection and send a message to a connected client. Also, at the end of the article, there is a link to the source code of the working application.
The article and the application are just an example of how this all works, and how ASP.NET and WebSockets can be connected, and it hardly claims to be an implementation guide in its current form, but it demonstrates the basics well and can be improved.
Why WebSockets are needed and what their advantages are, I think it’s not necessary to tell. Personally, I think that there are really not enough of them, so that you can make full-fledged client applications in JavaScript without tricks like Comet (great article here) or periodic requests.
But specifically, this technology seriously interested me in finding a solution to a small “problem” of working with Comet in the Chrome browser.
When organizing using Comet technology, some browsers, such as Chrome, behave in such a way that it seems as if the page is constantly loading, the same Chrome writes “waiting for a request” and the cursor always remains in a waiting state.
This is of course unpleasant.
Yes, and just why use a workaround when there is a more suitable technology for this and it seems possible to study it.
So the connection itself. On the client side (JavaScript), the browser provides a special WebSocket class.
Here is his description from here
Using it, we open a connection to the server and subscribe to the necessary events, as well as send messages to the server after the connection.
var sock;
function connectToServer() {
try {
sock = new WebSocket("ws://localhost:8181/websock");
sock.onopen = sockOpen;
sock.onerror = sockError;
sock.onclose = sockClosed;
sock.onmessage = sockMessage;
} catch (e) {
log("error:" + e);
}
}
* This source code was highlighted with Source Code Highlighter.
As you can see from the code above, our server will wait for connections at localhost: 8181.
In this example, all subscriber functions simply display information in a text field, and we send nothing to the server. After connecting, this is quite simple, but in this example it will only complicate things a bit.
So the server. Since the ASP.NET application / website works only when processing requests, and we need to constantly wait for connections, we must start a separate thread. Let's do it at Global.asax. The stream and server will be handled by our special classic.
void Application_Start(object sender, EventArgs e)
{
WebSocks.WebSockServer.Start();
}
void Application_End(object sender, EventArgs e)
{
WebSocks.WebSockServer.End();
}
* This source code was highlighted with Source Code Highlighter.
In the Start function, we simply start Thread, which will wait for the connection, and in End we clean it up. All this can be seen in more detail in the source code, which I will give at the end of the article.
So, hereinafter the code of the most important function, but first I will briefly tell you what will happen to make it easier to navigate.
- A new client will join (for now, we will serve one at a time)
- We accept customer handshake
- Sending our Handshake. After that, the connection can be considered established.
- We send the line Hello World !, where without it :)
public static void Listen()
{
//Начинаем слушать
Listener = new TcpListener(IPAddress.Loopback, PortNumber);
Listener.Start();
while (true)
{
//Присоеденился клиент
using (Socket client = Listener.AcceptSocket())
using (NetworkStream stream = new NetworkStream(client))
using (StreamReader reader = new StreamReader(stream))
using (StreamWriter writer = new StreamWriter(stream))
{
string clientHandshake = String.Empty;
string currentRead = null;
string clientOrigin = "";
while (currentRead != "")
{
//Построчно читаем handshake от клиента
currentRead = reader.ReadLine();
clientHandshake += currentRead + Environment.NewLine;
//Проверяем дошли ли мы до строчки с источником
if (currentRead.StartsWith("Origin"))
{
//Считываем источник соеденения
int valueStartIndex = currentRead.IndexOf(':') + 1;
clientOrigin = currentRead.Substring(valueStartIndex, currentRead.Length - valueStartIndex);
}
}
//Отвечаем клиенту в рамках процедуры установления соединения (Handshake)
writer.WriteLine("HTTP/1.1 101 Web Socket Protocol Handshake");
writer.WriteLine("Upgrade: WebSocket");
writer.WriteLine("Connection: Upgrade");
//Вот тут нам и нужен Origin который мы взяли ранее.
//Мы не "хардкодим значение", потому что, если запускать
//из под студии, то порт может быть разным.
writer.WriteLine(String.Format("WebSocket-Origin: {0}", clientOrigin));
writer.WriteLine("WebSocket-Location: ws://localhost:8181/websock");
writer.WriteLine("");
writer.Flush();
//Даем клиенту/браузеру время сообразить.
Thread.Sleep(100);
//Специальные байты которые начинают и заканчивают сообщения
byte[] first = new byte[] { 0x00 };
byte[] last = new byte[] { 0xFF };
//Отсылаем первый байт (начинаем сообщение)
client.Send(first);
//Ну и куда же без Hello World
client.Send(Encoding.UTF8.GetBytes("Hello world!"));
//Отсылаем последний байт (заканчиваем сообщение)
client.Send(last);
}
}
}
* This source code was highlighted with Source Code Highlighter.
And here are the promised sources.
dl.dropbox.com/u/3945288/WebSocketsArticle.zip
This is the simplest example, it has drawbacks, for example, the lack of multithreading when processing clients. And also, there is still room for improvement, for example, to provide access to the user session.
I will be glad if the article is liked and helps someone, I will try to develop the topic and write more.
UPD: In the comments, they noticed that the implementation for the previous revision 75, the current 76, in which added security. I will try to make a version that will work with both editions, but apparently not today.
For those who asked me to share my best practices, I uploaded everything here . In theory, everything should work but does not work :), somewhere a jamb but the brain does not notice it anymore.
UPD2: As promised, here is a version that supports both versions 75 and 76.