1. 程式人生 > >在ASP.NET CORE 2.0使用SignalR技術

在ASP.NET CORE 2.0使用SignalR技術

cli put ast log body post disco nbsp dot

閱讀目錄

  • 一、前言
  • 二、環境搭建
  • 三、最後
回到目錄

一、前言

上次講SignalR還是在《在ASP.NET Core下使用SignalR技術》文章中提到,ASP.NET Core 1.x.x 版本發布中並沒有包含SignalR技術和開發計劃中。時間過得很快,MS已經發布了.NET Core 2.0 Preview 2 預覽版,距離正式版已經不遠了,上文中也提到過在ASP.NET Core 2.0中的SignalR將做為重要的組件與MVC等框架一起發布。它的開發團隊也兌現了承諾,使用TypeScript對它的javascript客戶端進行重寫,服務端方面也會貼近ASP.NET Core的開發方式,比如會集成到ASP.NET Core依賴註入框架中。

回到目錄

二、環境搭建

要在ASP.NET Core 2.0中使用SignalR,要先引用Microsoft.AspNetCore.SignalR 、 Microsoft.AspNetCore.SignalR.Http 兩個Package包。

目前ASP.NET Core 2.0與SignalR還都是Preview版本,所以NUGET上也找不到SignalR的程序包,想添加引用我們就得去MyGet上去找找。既然要用MyGet的話,就要為項目添加NuGet源了。

1.添加NuGet源

在程序根目錄新建一個命為NuGet.Config的文件內容如下:

<?xml version="1.0" encoding="
utf-8"?> <configuration> <packageSources> <clear/> <add key="aspnetcidev" value="https://dotnet.myget.org/F/aspnetcore-ci-dev/api/v3/index.json"/> <add key="api.nuget.org" value="https://api.nuget.org/v3/index.json"/> </packageSources> </configuration>

2.編輯項目文件csproj

添加上面提到的兩個包的引用:

    <PackageReference Include="Microsoft.AspNetCore.All" Version="2.0.0-preview3-26040" />
    <PackageReference Include="Microsoft.AspNetCore.SignalR" Version="1.0.0-preview3-26037" />
    <PackageReference Include="Microsoft.AspNetCore.SignalR.Http" Version="1.0.0-preview3-26037" />

我在這個示例裏使用的是目前的最高,當然版本號每天都有可能發生變化,最新版本的SignalR,是不兼容.NET Core SDK 2.0 Preview 1中默認創建項目時Microsoft.AspNetCore.All這個包的版本的,這裏也修改修改一下版本號為:Microsoft.AspNetCore.All 2.0.0-preview3-26040。

當然也可以用dotnet cli 來添加包引用:

dotnet add package Microsoft.AspNetCore.SignalR --version 1.0.0-preview3-26037 --source https://dotnet.myget.org/F/aspnetcore-dev/api/v3/index.json

dotnet add package Microsoft.AspNetCore.SignalR.Http --version 1.0.0-preview3-26037 --source https://dotnet.myget.org/F/aspnetcore-dev/api/v3/index.json

3.添加配置代碼

我們需要在Startup類中的 ConfigureServices方法中添加如下代碼:

public void ConfigureServices(IServiceCollection services)
{
    services.AddSignalR();
}

在Startup類中的Configure方法中添加如下代碼:

public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
    app.UseStaticFiles();
    app.UseSignalR(routes =>
    {
        routes.MapHub<Chat>("hubs");
    });
}

4.添加一個HUB類

public class Chat : Hub
{
    public override async Task OnConnectedAsync()
    {
        await Clients.All.InvokeAsync("Send", $"{Context.ConnectionId} joined");
    }

    public override async Task OnDisconnectedAsync(Exception ex)
    {
        await Clients.All.InvokeAsync("Send", $"{Context.ConnectionId} left");
    }

    public Task Send(string message)
    {
        return Clients.All.InvokeAsync("Send", $"{Context.ConnectionId}: {message}");
    }

    public Task SendToGroup(string groupName, string message)
    {
        return Clients.Group(groupName).InvokeAsync("Send", $"{Context.ConnectionId}@{groupName}: {message}");
    }

    public async Task JoinGroup(string groupName)
    {
        await Groups.AddAsync(Context.ConnectionId, groupName);

        await Clients.Group(groupName).InvokeAsync("Send", $"{Context.ConnectionId} joined {groupName}");
    }

    public async Task LeaveGroup(string groupName)
    {
        await Groups.RemoveAsync(Context.ConnectionId, groupName);

        await Clients.Group(groupName).InvokeAsync("Send", $"{Context.ConnectionId} left {groupName}");
    }

    public Task Echo(string message)
    {
        return Clients.Client(Context.ConnectionId).InvokeAsync("Send", $"{Context.ConnectionId}: {message}");
    }
}

5.客戶端支持

  在wwwroot目錄下創建一個名為chat.html的Html靜態文件,內容如下:

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8" />
    <title></title>
</head>
<body>
    <h1 id="head1"></h1>
    <div>
        <select id="formatType">
            <option value="json">json</option>
            <option value="line">line</option>
        </select>

        <input type="button" id="connect" value="Connect" />
        <input type="button" id="disconnect" value="Disconnect" />
    </div>


    <h4>To Everybody</h4>
    <form class="form-inline">
        <div class="input-append">
            <input type="text" id="message-text" placeholder="Type a message, name or group" />
            <input type="button" id="broadcast" class="btn" value="Broadcast" />
            <input type="button" id="broadcast-exceptme" class="btn" value="Broadcast (All Except Me)" />
            <input type="button" id="join" class="btn" value="Enter Name" />
            <input type="button" id="join-group" class="btn" value="Join Group" />
            <input type="button" id="leave-group" class="btn" value="Leave Group" />
        </div>
    </form>

    <h4>To Me</h4>
    <form class="form-inline">
        <div class="input-append">
            <input type="text" id="me-message-text" placeholder="Type a message" />
            <input type="button" id="send" class="btn" value="Send to me" />
        </div>
    </form>

    <h4>Private Message</h4>
    <form class="form-inline">
        <div class="input-prepend input-append">
            <input type="text" name="private-message" id="private-message-text" placeholder="Type a message" />
            <input type="text" name="user" id="target" placeholder="Type a user or group name" />

            <input type="button" id="privatemsg" class="btn" value="Send to user" />
            <input type="button" id="groupmsg" class="btn" value="Send to group" />
        </div>
    </form>

    <ul id="message-list"></ul>
</body>
</html>
<script src="signalr-client.js"></script>
<script src="utils.js"></script>
<script>
var isConnected = false;
function invoke(connection, method, ...args) {
    if (!isConnected) {
        return;
    }
    var argsArray = Array.prototype.slice.call(arguments);
    connection.invoke.apply(connection, argsArray.slice(1))
            .then(result => {
                console.log("invocation completed successfully: " + (result === null ? (null) : result));

                if (result) {
                    addLine(message-list, result);
                }
            })
            .catch(err => {
                addLine(message-list, err, red);
            });
}

function getText(id) {
    return document.getElementById(id).value;
}

let transportType = signalR.TransportType[getParameterByName(transport)] || signalR.TransportType.WebSockets;

document.getElementById(head1).innerHTML = signalR.TransportType[transportType];

let connectButton = document.getElementById(connect);
let disconnectButton = document.getElementById(disconnect);
disconnectButton.disabled = true;
var connection;

click(connect, event => {
    connectButton.disabled = true;
    disconnectButton.disabled = false;
    let http = new signalR.HttpConnection(`http://${document.location.host}/hubs`, { transport: transportType });
    connection = new signalR.HubConnection(http);
    connection.on(Send, msg => {
        addLine(message-list, msg);
    });

    connection.onClosed = e => {
        if (e) {
            addLine(message-list, Connection closed with error:  + e, red);
        }
        else {
            addLine(message-list, Disconnected, green);
        }
    }

    connection.start()
        .then(() => {
            isConnected = true;
            addLine(message-list, Connected successfully, green);
        })
        .catch(err => {
            addLine(message-list, err, red);
        });
});

click(disconnect, event => {
    connectButton.disabled = false;
    disconnectButton.disabled = true;
    connection.stop()
        .then(() => {
            isConnected = false;
        });
});

click(broadcast, event => {
    let data = getText(message-text);
    invoke(connection, Send, data);
});

click(join-group, event => {
    let groupName = getText(message-text);
    invoke(connection, JoinGroup, groupName);
});

click(leave-group, event => {
    let groupName = getText(message-text);
    invoke(connection, LeaveGroup, groupName);
});

click(groupmsg, event => {
    let groupName = getText(target);
    let message = getText(private-message-text);
    invoke(connection, SendToGroup, groupName, message);
});

click(send, event => {
    let data = getText(me-message-text);
    invoke(connection, Echo, data);
});

</script>

值得註意的是,你可能會發現,目前找不到signalr-client.js這個文件,它是怎麽來的呢,有兩種方式:
第1種是通過下載SignalR的源代碼,找到Client-TS項目,對TypeScript進行編譯可以得到。

第2種比較簡單通過Npm可以在線獲取:

npm install signalr-client --registry https://dotnet.myget.org/f/aspnetcore-ci-dev/npm/

三、最後

  附上一個可用的Demo:https://github.com/maxzhang1985/AspNetCore.SignalRDemo

  GitHub:https://github.com/maxzhang1985/YOYOFx 如果覺還可以請Star下, 歡迎一起交流。

在ASP.NET CORE 2.0使用SignalR技術