---
# System prepended metadata

title: 紀錄 MVC 5 用 WebSocket Server
tags: [.NET MVC]

---

# 紀錄 MVC 5 用 WebSocket Server
###### tags: `.NET MVC`
## 介紹
使用 [WebSocketSharp](https://github.com/sta/websocket-sharp) 套件來進行，其實步驟幾乎同參考資料，但參考資料少一個最重要的步驟 --- 釋放。

導致在重新 Deploy 的時候、本端開發測試的時候，呼叫 WebSocketServer.Start() 時發生 Port 被占用的問題。

## Server
### AppConfig.cs --- 全域變數

```
public class AppConfig
{
    public static WebSocketServer WebSocketServer { get; set; }
}
```

### Global.asax.cs --- 啟用 WebSocket Server 服務
* 檢查 Port 號是否已被使用
* 釋放
* 宣告 WebSocketBehavior --- NotifyBehavior ( 因 Demo Code 就沒放在別處 )
```
    public class MvcApplication : System.Web.HttpApplication, IDisposable
    {
        protected void Application_Start()
        {
            AreaRegistration.RegisterAllAreas();

            WebApiConfig.Register(GlobalConfiguration.Configuration);
            FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
            RouteConfig.RegisterRoutes(RouteTable.Routes);
            BundleConfig.RegisterBundles(BundleTable.Bundles);

            int port = 9380;
            AppConfig.WebSocketServer = new WebSocketServer(port);
            AppConfig.WebSocketServer.AddWebSocketService<NotifyBehavior>("/notify");
            if (PortInUse(port))
                throw new Exception($"WebSocketServer 欲使用的 Port 號已被使用 [Port: {port}]");
            AppConfig.WebSocketServer.Start();
        }

        public static bool PortInUse(int port)
        {
            bool inUse = false;

            IPGlobalProperties ipProperties = IPGlobalProperties.GetIPGlobalProperties();
            IPEndPoint[] ipEndPoints = ipProperties.GetActiveTcpListeners();

            foreach (IPEndPoint endPoint in ipEndPoints)
            {
                if (endPoint.Port == port)
                {
                    inUse = true;
                    break;
                }
            }

            return inUse;
        }

        public override void Dispose()
        {
            if (AppConfig.WebSocketServer != null)
                AppConfig.WebSocketServer.Stop();

            base.Dispose();
        }
    }

    public class NotifyBehavior : WebSocketBehavior
    {
        protected override void OnOpen()
        {
            ////傳送訊息至Client
            //Send(JsonConvert.SerializeObject(new { message = "Open" }));
        }

        protected override void OnMessage(MessageEventArgs e)
        {
            ////接收Client傳入的訊息
            //string msg = e.Data;
        }

        protected override void OnClose(CloseEventArgs e)
        {
            ////傳送訊息至Client
            //Send(JsonConvert.SerializeObject(new { message = "Close" }));
        }

        protected override void OnError(ErrorEventArgs e)
        {

        }
    }
```

### SomeController.cs --- 使用 WebSocket Server 廣播
```
public class SomeController : Controller
{
	public ActionResult DoSomethingForAjax()
	{
		// do... read data something
		for (int i = 0 ; i<100 ; i++) {
			// notify client
			AddConsoleMessage($"when read at data index {i} error.")
		}
		
		// finish
		AddConsoleMessage("i'm done what you want.")
	}
	
	private void AddConsoleMessage(string message)
	{
		if (AppConfig.WebSocketServer != null || AppConfig.WebSocketServer.IsListening)
			AppConfig.WebSocketServer.WebSocketServices["/notify"].Sessions.Broadcast(JsonConvert.SerializeObject(new { message = message }));

		LogUtility.Info(message);
	}
}
```


## Client
### Html

```
<label class="badge rounded-pill bg-secondary mb-1 fs-6">Console：</label>
<br />
<textarea id="consoleArea" readonly style="height: 150px; width:100%"></textarea>
```

### Script
```
var wsc;

$(function () {
    if ("WebSocket" in window) {
            wsc.onopen = function () {
                console.log("connected");
                $("#consoleLabel").removeClass("bg-secondary");
                $("#consoleLabel").addClass("bg-success");
                $("#no-connect-wsc-tip").hide();
                //傳送訊息至Server
                //wsc.send('Client Connected.');
            };
            wsc.onclose = function () {
                console.log("closed");
                $("#consoleLabel").removeClass("bg-success");
                $("#consoleLabel").addClass("bg-secondary");
                $("#no-connect-wsc-tip").show();
            };
            wsc.onmessage = function (e) {
                //接收Server傳入的訊息
                var data = JSON.parse(e.data);
                var $textarea = $('#consoleArea');
                $textarea.html($textarea.html() + "\r\n" + data.message)
                $textarea.scrollTop($textarea[0].scrollHeight);
            };
            wsc.onerror = function (e) {
                $("#no-connect-wsc-tip").show();
                console.log("Error");
            }
    }
}
```
## 參考資料
[C# WebSocket實作雙向通訊](https://ithelp.ithome.com.tw/articles/10256563?sc=rss.qu)

[C#指定指定端口是否已经被占用的代码](https://cloud.tencent.com/developer/article/1896178)