Bir SignalR bağlantısını nasıl öldürebilirim?


10

Bir web sitesinde veri aktarmak için SignalR kullanıyorum. Ancak SignalR sadece belirli bir süre veri gönderebilmeli ve süre geçtiyse bağlantı kesilmelidir.

$.connection.hub.stop()Bir istek hala beklemede ve tamamlanmamışsa Durdurma İşlevi iptal edilir. Ancak ne kadar veri gönderilirse gönderilsin, bu istek iptal edilmeye zorlanmalıdır.

SignalR-Connection'ı nasıl öldürebilirim ?

Yanıtlar:


6

Zaman Aşımı ve saklama ayarları hakkındaki bu Microsoft Belgelerinde görebileceğiniz gibi DisconnectTimeout'u seçeneklerde tanımlayabilirsiniz.

Misal:

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

Düzenleme : Ne olursa olsun istemciden bağlantıyı öldürmek istediğiniz için, bir CancellationTokendavranış hakkında konuşuyorsunuz, ancak ne yazık ki bu hala burada ve burada görebileceğiniz gibi SignalR'de desteklenmiyor , takım bunu yapmak istiyor SignalRama hala var bu konuda haber yok.


Belirttiğim gibi, Ön Uç Sitesinden gelen talep tamamlanmadığından, Ön Uçtan SignalR-Arka Uç / Hub'a gönderilecek bazı veriler bulunmaktadır. Bu yüzden bir ön uç çözümü arıyorum, çünkü iyi miktarda veri gönderilir ve bir süre geçerse, veri iletilsin ya da iletilmesin, bağlantı ön uç tarafından öldürülmelidir. Ne aradığımı anlıyor musun?
Snickbrack

@Snickbrack şu anda veri gönderiyor olsanız bile, istemci tarafı üzerinden bağlantıyı öldürmek istiyorsunuz, doğru mu?
Kiril1512

1
Evet. Haklısın.
Snickbrack

@Snickbrack cevabımı güncelledi.
Kiril1512

@Snickbrack, sorunuza, bu veya diğer cevaplara doğru cevabı seçmeyi unutmayın ...
Kiril1512

1

Hub kullanım ömrü olayıyla ilgili bu microsoft belgesini okuyun . Sen, bu ayarlar için varsayılan değerleri değiştirmek bunları ayarlayabilirsiniz Application_Startsizin de Global.asaxdosyaya. Ancak bu şekilde istemci tarafını tam olarak kontrol edemezsiniz. Böylece javascript setTimeoutişlevini kullanın ve yeni bir kullanıcı bağlandığında zaman formu sunucusunun sonunu geçirin. Bu olabilir GlobalHost.Configuration.DisconnectTimeoutveya istediğiniz zaman. Demo projesi ile tam bir örnek veriyorum. Aslında bu mantığı gerçek zamanlı tutma bileti için çok büyük bir biletleme sisteminde kullanıyorum. (lütfen tüm satır içi yorumları okuyun)

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

Hub:

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

(Test edilmiştir)



0

Güncellenmiş Düzenleme, lütfen aşağıdaki Seçenek 3'e bakın. Tüm diğerleri zaman aşımına güveniyor, zorla bağlantıyı kesdim.

Bir Bağlantıyı Kesmeye çalışıyorsanız - Bağlı Kullanıcıların listesini alabilir ForceLogOutve Sunucu tarafında İşlevi çağırabilirsiniz , bunu kod projesinde bir yerde gördüm, umarım yardımcı olur. Yalnızca bazı kullanıcıları oturumdan çıkarmaya / öldürmeye zorlamak istiyorsanız, yalnızca bu bağlantıyı geçin ve yalnızca bu bağlantıyı öldürün.

Sunucu Tarafı


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

Müşteri Tarafı

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

Seçenek 3 ile güncellendi : isteğe bağlı olarak ... diğer çözümler zaman aşımına dayanır, ancak bağlantıyı kendiniz atarak doğrudan da zorlayabilirsiniz

SignalR kodunu açtım ve içinde DisposeAndRemoveAsyncbir istemci bağlantısının sonlandırıldığını görebilirsiniz .

1- DisposeAndRemoveAsyncBağlantınızı değiştirebilir veya bağlantı kurabilirsiniz.

2- Sonra ara 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);
            }
        }

Dikkat, bu yapıldığında kendiniz temizleyin.


Dediğim gibi $.connection.hub.stop()-Function bir hata atar çünkü istek tamamen Arka Uç'a gönderilmemiştir. Bu yüzden, çalışan bir istek mevcut olsa bile, şu anda aktif bağlantıyı öldüren bir çözüm arıyorum.
Snickbrack
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.