2016-09-15 12 views
7

私のWebアプリケーションでは、起動時にサーバからすべてのデータをクライアント側にロードします。 その後、私はすべてのコミュニケーションをSignalrを通して管理したいと思っています。つまり、各アップデートはサーバがすべてのクライアントに通知を送信し、アップデートされたデータを要求します。クライアントとサーバを同期させるための通知を管理する(C#)

しかし、SingalR接続が壊れてから元に戻ったときにどうすればいいのか分かりません。私はすべてのデータをもう一度ロードしたくありません。私がしたいのは、切断されたクライアントごとに、また、SignalR接続が再度行われるときに、サーバ側で何らかの通知管理を実装することです。彼が見逃したすべての通知を特定のクライアントにプッシュします。

クライアント側のsignalRリスナーは、短いリビングコントローラーではなくシングルトンリスナーで作成されているため、各ビューの変更に対するGET要求を防ぎ、アプリケーションをより迅速かつ使いやすくすることができます。そのアプローチの、バックグラウンドで新しい通知も取り扱い、それが現在のビューに関連していないときでも処理されますので、エンドユーザーはそのようなことがある:例えば、何が起こるか現時点では

// This service is initialized once only 
public class Service1 { 
     static inject = ['$rootScope'] 
    array : Item[]; 

    // This is a singleton! 
    public constructor ($rootScope){ 

     // Get all items from the server 
     GetAllItemsFromServer(); 

     // Listener for signalR updates 
     var listener = $rootScope.$on("ItemsNotificationFromServer", UpdateItems); 

     $rootScope.$on('destroy', { 
      // Stop the listener 
      listener(); 
     }) 
    } 

    // Getting all the items from the server on each controller creation 
    GetAllItemsFromServer(){ 
     // Getting the items 
    } 

    // Handle the notification from the server 
    public UpdateItems(event, result) : void 
     //.. 
    } 
} 

ですエンドユーザーがブラウザ(F5)をリフレッシュすると、このクライアントが接続の問題で逃したSignalRの通知を知ることができず、サーバーからすべてのデータをもう一度読み込みます。

私はこのような何かの実装を考え、それを防止するために - 私はまだそれをテストするために持っていないが、私は私のチームにこのアイデアを提示する前に、このアプローチは人気がある

namespace MapUsersSample 
{ 
    public class UserContext : DbContext 
    { 
     // All those are cleaned when server is powered up 
     public DbSet<Connection> Connections { get; set; } 
     public DbSet<Notification> Notifications {get; set;} 
    } 

    public class Connection 
    { 
     [Key] 
     [DatabaseGenerationOptions.None] 
     public string ConnectionID { get; set; } 
     public bool Connected { get; set; } 

     // I fill this when disconnected 
     public List<Notification> MissedNotifications {get; set;} 

     public Connection(string id) 
     { 
      this.ConnectionID = id; 
      this.Connected = true; 
      this.MissedNotifications = new List<Notification>(); 
     } 
    } 

    public abstract class Notification() 
    { 
     public int Id {get; set;} 
     public DateTime CreationTime {get; set;} 
    } 

    .. // Many notifications implement this 
} 

public class MyHub : Hub 
{ 
    private readonly DbContext _db; 
    public class MyHub(DbContext db) 
    { 
     this._db = db; 
    } 

    // Adding a new connection or updating status to true 
    public override Task OnConnected() 
    { 
     var connection = GetConnection(Context.ConnectionId); 

     if (connection == null) 
      _db.Connections.Add(new Connection(Context.ConnectionId)); 
     else 
      connection.Connected = true; 

     return base.OnConnected() 
    } 

    // Changing connection status to false 
    public override Task OnDisconnected() 
    { 
     var connection = GetConnection(Context.ConnectionId); 

     if (connection == null) 
     { 
      Log("Disconnect error: failed to find a connection with id : " + Context.ConnectionId); 
      return; 
     } 
     else { 
      connection.Connected = false; 
     } 
     return base.OnDisconnected(); 
    } 

    public override Task OnReconnected() 
    { 
     var connection = GetConnection(Context.ConnectionId); 

     if (connection == null) 
     { 
      Log("Reconnect error - failed to find a connection with id : " + Context.ConnectionId); 
      return; 
     } 
     else { 
      connection.Connected = true; 
     } 

     // On reconnect, trying to send to the client all the notifications that he has missed 
     foreach (var notification in connection.MissedNotifications){ 
      Clients.Client(connection.ConnectionID).handleNotification(notification); 
     } 

     return base.OnReconnected(); 
    } 

    // This method is called from clients that receive a notification 
    public clientNotified(int connectionId, int notificationId) 
    { 
     // Getting the connection 
     var connection = GetConnection(connectionId); 

     if (connection == null){ 
      Log("clientNotified error - failed to find a connection with id : " + Context.ConnectionId); 
      return; 
     } 

     // Getting the notification that the client was notified about 
     var notificationToRemove = _dbConnection.Notifications.FirstOrDefault(n => n.Id == notificationId); 

     if (notificationToRemove == null) 
     { 
      Log("clientNotified error - failed to find notification with id : " + notificationId); 
      return; 
     } 

     // Removing from the missed notifications 
     connection.MissedNotifications.Remove(notificationToRemove); 
    } 

    private Connection GetConnection(int connectionId) 
    { 
     return _db.Connections.find(connectionId); 
    } 


} 

// Notifications outside of the hub 
public class Broadcaster 
{ 
    DbContext _db; 
    public Broadcaster(DbContext db) 
    { 
     _hubContext = GlobalHost.ConnectionManager.GetHubContext<MoveShapeHub>(); 
     _dbConnection = db; 
    } 

    public void NotifyClients(Notification notification) 
    { 
     var openConnections = _db.Connections.Where(x => x.Connected); 
     var closedConnections = _db.Connections.Where(x => !x.Connected); 

     // Adding all notifications to be sent when those connections are back 
     foreach (var connection in closedConnections){ 
      connection.MissedNotifications.add(notification); 
     } 

     // Notifying all open connections 
     foreach (var connection in openConnections){ 
      _hubContext.Clients.Client(connection.ConnectionID).handleNotification(notification); 
     } 
    } 
} 


client side java script: 

handleNotification(notification){ 
    hubProxy.Server.clientNotified(hub.connection.id, notification.Id) 

    // Keep handling the notification here.. 
} 

を?人々はこのアプローチを取っているのを見たことがないと私はなぜ思った?ここにリスクはありますか?

+0

私の意見では、エンド・ユーザーがページをリフレッシュすると、コール・クライアント側のコレクションを含むJSによって構築された城全体が失われます。その場合、必要に応じてすべてのデータを取得する必要があります。そうでない場合は、増分データだけが必要になります。 –

+0

あなたはRabbitMQのようなキューを考えましたか? –

+0

ソケット接続が失われてしまった場合、状態を維持しない限り、同じクライアントが再接続されるかどうかを知る方法がないため、正しいデータを慎重に押して正しいユーザーにプッシュする必要があります。私は新しいリクエストを新しいリクエストとして扱うことをお勧めします。 –

答えて

2

たとえば、エンドユーザがブラウザ(F5)をリフレッシュすると、このクライアントが接続の問題で紛失したSignalRの通知を知ることができないため、サーバからすべてのデータをロードします何度も何度も(それは吸う)。

F5キーを押してブラウザをリフレッシュするとハードリセットされ、既存のSignalR接続はすべて失われます。データを取得するために新しい接続が作成されます。接続問題は、SignalRが、例えば、http接続での問題に気づいた場合に発生する。一時的なネットワークの問題が原因です。ブラウザの更新は接続の問題ではなく、ユーザーが意図的に新しい接続を再作成する行為です。

通知が届かない通知を管理するコードは、signalR接続の問題でのみ機能します。私はそれがブラウザのリフレッシュのために働くだろうとは思わないが、それはあなたが何かを見逃していないので、新しい接続です。

2

データが実際のものかどうかを確認する必要があります。 ハッシュまたは最終変更の日時にすることができます。

クライアントが再接続すると、実際のデータハッシュまたは最後の変更の日時をクライアントに送信する必要があります。

{ 
clients: '2016-05-05T09:05:05', 
orders: '2016-09-20T10:11:11' 
} 

とクライアント・アプリケーション例えば

はそれを更新する必要がどのようなデータを決定します。

クライアントでは、データをLocalStorageまたはSessionStorageに保存できます。

関連する問題