Bagaimana saya bisa membunuh koneksi SignalR?

10

Saya menggunakan SignalR untuk mentransfer data di situs web. Tetapi SignalR seharusnya hanya dapat mengirim data untuk periode waktu tertentu dan jika periode waktu telah berlalu koneksi harus dimatikan.

Stop-Function $.connection.hub.stop()dibatalkan jika permintaan masih menunggu dan belum selesai. Tetapi permintaan ini harus dipaksa untuk membatalkan tidak peduli berapa banyak data yang telah dikirim.

Bagaimana saya bisa membunuh SignalR-Connection?

Snickbrack
sumber

Jawaban:

6

Seperti yang dapat Anda lihat di Dokumentasi Microsoft ini tentang Timeout dan pengaturan keepalive Anda dapat menentukan DisconnectTimeout dalam opsi.

Contoh:

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();
}

Sunting : Karena Anda ingin mematikan koneksi dari klien, apa pun yang Anda lakukan, Anda berbicara tentang CancellationTokenperilaku tetapi sayangnya ini masih tidak didukung di SignalR seperti yang Anda lihat di sini dan di sini , tim ingin melakukan itu SignalRtetapi masih ada tidak ada berita tentang itu.

Kiril1512
sumber
Seperti yang saya nyatakan, permintaan dari Frontend-Site tidak selesai sehingga masih ada beberapa data dari frontend untuk dikirim ke SignalR-Backend / Hub. Jadi saya mencari solusi frontend karena jumlah data yang layak dikirim dan jika periode waktu berlalu maka koneksi harus dimatikan oleh frontend tidak peduli apakah data telah dikirim atau tidak. Apakah Anda mengerti apa yang saya cari?
Snickbrack
@Snickbrack Anda ingin mematikan koneksi melalui sisi klien, bahkan jika Anda mengirim data sekarang, saya benar?
Kiril1512
1
Iya. Anda benar.
Snickbrack
@Snickbrack memperbarui jawaban saya.
Kiril1512
@Snickbrack jangan lupa untuk memilih jawaban yang benar untuk pertanyaan Anda, ini atau jawaban lain di sini ...
Kiril1512
1

Silakan baca dokumen microsoft ini tentang acara Hub seumur hidup. Anda dapat mengubah nilai default untuk pengaturan ini, mengaturnya Application_Startdi Global.asaxfile Anda . Tetapi dengan cara ini Anda tidak dapat sepenuhnya mengontrol sisi klien. Jadi, Anda menggunakan setTimeoutfungsi javascript dan melewatkan waktu bentuk server ketika pengguna baru connect.it mungkin GlobalHost.Configuration.DisconnectTimeoutatau kapan saja Anda inginkan. Saya memberikan contoh lengkap dengan proyek demo. Sebenarnya saya menggunakan logika ini dalam sistem tiket yang sangat besar untuk memegang tiket secara real-time. (harap baca semua komentar sebaris)

Model:

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";
    }
}

Pusat:

[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);
}

(Diuji)

Ashiquzzaman
sumber
0

Anda perlu menentukan batas waktu. Di server Anda dapat mengatur DisconnectTimeout, seperti ini:

GlobalHost.Configuration.DisconnectTimeout = TimeSpan.FromMinutes(30);

https://zzz.buzz/2016/05/11/setting-timeout-for-signalr-for-easier-debugging/

Lajos Arpad
sumber
Seperti yang saya nyatakan, permintaan dari Frontend-Site tidak selesai sehingga masih ada beberapa data dari frontend untuk dikirim ke SignalR-Backend / Hub. Jadi saya mencari solusi frontend.
Snickbrack
0

Edit yang Diperbarui, silakan lihat Opsi 3 di bawah ini. Semua yang lain mengandalkan batas waktu, saya diposting putuskan paksa.

Jika Anda mencoba Memutus Kekuatan - Anda bisa mendapatkan daftar Pengguna yang Terhubung dan memanggil ForceLogOut Fungsi di sisi server, saya melihat ini di suatu tempat di proyek kode, saya harap ini membantu. Jika Anda hanya ingin memaksaLogout / membunuh beberapa pengguna, cukup lewati saja dan matikan koneksi itu saja.

Sisi server


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();
            }
        }
    }
}

Sisi klien

 // 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();                
        });

Diperbarui dengan Opsi 3 : berdasarkan permintaan ... solusi lain bergantung pada waktu habis, tetapi Anda juga dapat memaksanya secara langsung dengan membuang koneksi sendiri

Saya membuka kode SignalR, dan di dalam Anda dapat melihat DisposeAndRemoveAsync penghentian koneksi klien yang sebenarnya.

1- Anda dapat memodifikasi atau menelepon DisposeAndRemoveAsync dengan koneksi Anda.

2- Lalu panggil 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);
            }
        }

Perhatian, lakukan pembersihan sendiri saat ini dilakukan.

transformator
sumber
Seperti yang saya nyatakan $.connection.hub.stop()-Fungsi melempar kesalahan karena permintaan belum sepenuhnya dikirim ke Backend. Jadi saya mencari solusi yang membunuh koneksi aktif saat ini bahkan jika ada permintaan yang sedang berjalan.
Snickbrack