回答:
このMicrosoftドキュメントでタイムアウトとキープアライブの設定について確認できるように、オプションでDisconnectTimeoutを定義できます。
例:
protected void Application_Start(object sender, EventArgs e)
{
// Make long-polling connections wait a maximum of 110 seconds for a
// response. When that time expires, trigger a timeout command and
// make the client reconnect.
GlobalHost.Configuration.ConnectionTimeout = TimeSpan.FromSeconds(110);
// Wait a maximum of 30 seconds after a transport connection is lost
// before raising the Disconnected event to terminate the SignalR connection.
GlobalHost.Configuration.DisconnectTimeout = TimeSpan.FromSeconds(30);
// For transports other than long polling, send a keepalive packet every
// 10 seconds.
// This value must be no more than 1/3 of the DisconnectTimeout value.
GlobalHost.Configuration.KeepAlive = TimeSpan.FromSeconds(10);
RouteTable.Routes.MapHubs();
}
編集:あなたは、あなたが話しているかに関係なく、クライアントからの接続殺したいのでCancellationToken
行動が、残念ながら、これはまだあなたが見ることができるようSignalRではサポートされていませんこことここを、チームはにことをやりたいSignalR
けど、まだそこにありますそれについてのニュースはありません。
ハブのライフタイムイベントに関するこの Microsoftドキュメントをお読みください。これらの設定のデフォルト値を変更Application_Start
し、Global.asax
ファイルに設定できます。しかし、この方法ではクライアント側を完全に制御することはできません。そのため、JavaScript setTimeout
関数を使用して、新しいユーザーが接続したときにサーバーの終了時間を渡しGlobalHost.Configuration.DisconnectTimeout
ます。デモプロジェクトの完全な例を示します。実際、私はこのロジックを非常に大規模な発券システムでリアルタイムのチケット保持に使用しています。(すべてのインラインコメントをお読みください)
モデル:
public class MyModel
{
public int Id { get; set; }
public string Name { get; set; }
public static string Send(MyModel my)
{
//Do Somthing
return $"Data Sending to {my.Name}...";
}
public static string Stop(string name)
{
//Do Somthing
return $"ForceStop {name}.";
}
public static string Delete()
{
//Do Somthing
return "Deleted";
}
}
ハブ:
[HubName("myHub")]
public class MyHub : Hub
{
int connectionTimeOut = 10;//sec
[HubMethodName("connect")]
public void Connect()
{
//apply logic if any when user connected or reload page
//set connection Time Out as you need
connectionTimeOut= 10;// GlobalHost.Configuration.DisconnectTimeout
Clients.Client(Context.ConnectionId).onNewUserConnected(connectionTimeOut);
}
[HubMethodName("startSendingServer")]
public void StartSending(int id, string name)//pass anything you need
{
//apply logic if any when start sending data
var my = new MyModel
{
Id = id,
Name = name
};
var status = MyModel.Send(my);//example
var result = new
{
status,
name
};
Clients.Client(Context.ConnectionId).startSendingClient(result);
}
[HubMethodName("forceStopServer")]
public void ForceStop(string name)//pass anything you need
{
//apply logic if any when force stop sending data
var status = MyModel.Stop(name);
Clients.Client(Context.ConnectionId).forceStopClint(status);
}
public override Task OnDisconnected(bool stopCalled)
{
//apply logic if any when connection Disconnected
var status = MyModel.Delete();//example
if (stopCalled)
{
// status=String.Format("Client {0} explicitly closed the connection.", Context.ConnectionId)
//your code here
}
else
{
// status=String.Format("Client {0} timed out .", Context.ConnectionId);
//your code here
//Clients.Client(Context.ConnectionId).onUserDisconnected(status);
}
return base.OnDisconnected(stopCalled);
}
}
TestView:
<div class="row">
<div class="col-md-12">
<h1> Status: <span id="hubStatus"></span></h1>
<br />
<h4> Countdown : <span id="counter"></span></h4>
<br />
<button id="btnHub" class="btn btn-primary btn-lg">Start Sending Data</button>
</div>
</div>
@section scripts{
<script src="~/Scripts/app/hub.js"></script>
}
hub.js:
var proxyTimer = null;
var sendTimeLimit = 1;//sec
var sessionTime = sendTimeLimit * 1000;
$(function () {
var myProxy = $.connection.myHub;
$.connection.hub.start().done(function () {
registerServerEvents(myProxy);
});
clientMethods(myProxy);
});
function registerServerEvents(proxyHub) {
proxyHub.server.connect();
$(document).on("click", "#btnHub", function (e) {
$("#hubStatus").html("Sending..");
$("#btnHub").text("Count Down Start...");
//Logic Before start sending data.
var id = 1;
var name = "AzR";
proxyHub.server.startSendingServer(id,name);
// $.connection.hub.disconnected(function () {
// setTimeout(function () { $.connection.hub.start(); }, 5000); // Restart connection after 5 seconds.
//});
$.connection.hub.disconnected(function () {
$("#hubStatus").html("Disconnected");// you can restart on here.
$("#btnHub").text("Stat Again after reload window");
});
});
}
function clientMethods(proxyHub) {
//proxyHub.on('onConnected', function (sendTimeLimit) {
// sendTimeLimit = sendTimeLimit;
//});
proxyHub.on('onNewUserConnected', function (serverItem) {
sendTimeLimit = serverItem;
sessionTime = sendTimeLimit * 1000;
});
proxyHub.on('startSendingClient', function (serverItem) {
//Logic after start sending data.
var name = serverItem.name;
var status = serverItem.status;
$("#hubStatus").html(status);
$("#counter").html(sendTimeLimit);
timeCounter();
startTimer(proxyHub, name );
});
proxyHub.on('forceStopClint', function (serverItem) {
clearClintPendingTask(serverItem);//Logic before proxy stop.
$("#btnHub").text("Force Stop...");
$.connection.hub.stop();
});
proxyHub.on('onUserDisconnected', function (serverItem) {
//Logic after proxy Disconnected (time out).
$("#hubStatus").html(serverItem);
$("#btnHub").text("Stat Again after reload window");
});
}
//Logic before proxy stop.
function clearClintPendingTask(status) {
//do all you need
$("#hubStatus").html(status);
stopTimer();
}
function startTimer(proxyHub,data) {
stopTimer();
proxyTimer = setTimeout(function () {
proxyHub.server.forceStopServer(data);
}, sessionTime);
}
function stopTimer() {
if (proxyTimer) {
clearTimeout(proxyTimer);
proxyTimer = null;
}
}
function timeCounter() {
var counter = sendTimeLimit;
var interval = setInterval(function () {
counter--;
$("#counter").html(counter);
if (counter == 0) {
//Do something
$("#counter").html("Countdown ended!");
// Stop the counter
clearInterval(interval);
}
}, 1000);
}
(テスト済み)
タイムアウトを定義する必要があります。サーバーでは、次のようにDisconnectTimeoutを設定できます。
GlobalHost.Configuration.DisconnectTimeout = TimeSpan.FromMinutes(30);
https://zzz.buzz/2016/05/11/setting-timeout-for-signalr-for-easier-debugging/
編集を更新しました。以下のオプション3を参照してください。他のすべてはタイムアウトに依存している、私は強制切断を投稿しました。
強制切断を試行している場合、接続ユーザーのリストを取得ForceLogOut
してサーバー側で関数を呼び出すことができます。これはコードプロジェクトのどこかにありました。一部のユーザーのみをforceLogout / killする場合は、ループしてその接続のみを強制終了します。
サーバ側
public class User
{
public string Name { get; set; }
public HashSet<string> ConnectionIds { get; set; }
}
public class ExtendedHub : Hub
{
private static readonly ConcurrentDictionary<string, User> ActiveUsers =
new ConcurrentDictionary<string, User>(StringComparer.InvariantCultureIgnoreCase);
public IEnumerable<string> GetConnectedUsers()
{
return ActiveUsers.Where(x => {
lock (x.Value.ConnectionIds)
{
return !x.Value.ConnectionIds.Contains
(Context.ConnectionId, StringComparer.InvariantCultureIgnoreCase);
}
}).Select(x => x.Key);
}
public void forceLogOut(string to)
{
User receiver;
if (ActiveUsers.TryGetValue(to, out receiver))
{
IEnumerable<string> allReceivers;
lock (receiver.ConnectionIds)
{
allReceivers = receiver.ConnectionIds.Concat(receiver.ConnectionIds);
}
foreach (var cid in allReceivers)
{
// ***************** log out/KILL connection for whom ever your want here
Clients.Client(cid).Signout();
}
}
}
}
クライアント側
// 1- Save your connection variable when you start it, and later on you can use it to stop.
var myHubProxy = $.connection.myHub
// 2- Use it when you need to stop it, IF NOT YOU WILL GET AN ERROR
myHubProxy.client.stopClient = function() {
$.connection.hub.stop();
};
// With a button for testing
$('#SomeButtonKillSignalr').click(function () {
$.connection.hub.stop();
});
オプション3で更新:リクエストに基づいて...他のソリューションはタイムアウトに依存しますが、接続を自分で破棄することで直接強制することもできます
SignalRコードを開いたところDisposeAndRemoveAsync
、クライアント接続の実際の終了を確認できます。
1-変更または呼び出しが可能 DisposeAndRemoveAsync
接続をます。
2-次に電話する RemoveConnection(connection.ConnectionId);
public async Task DisposeAndRemoveAsync(HttpConnectionContext connection)
{
try
{
// this will force it
await connection.DisposeAsync();
}
catch (IOException ex)
{
_logger.ConnectionReset(connection.ConnectionId, ex);
}
catch (WebSocketException ex) when (ex.InnerException is IOException)
{
_logger.ConnectionReset(connection.ConnectionId, ex);
}
catch (Exception ex)
{
_logger.FailedDispose(connection.ConnectionId, ex);
}
finally
{
// Remove it from the list after disposal so that's it's easy to see
// connections that might be in a hung state via the connections list
RemoveConnection(connection.ConnectionId);
}
}
これが完了したら、注意してください。
$.connection.hub.stop()
、リクエストがバックエンドに完全に送信されていないため、-Functionはエラーをスローします。したがって、実行中のリクエストが存在する場合でも、現在アクティブな接続を強制終了するソリューションを探しています。