/// <summary> /// Sends a view model data to one or more clients. /// </summary> /// <param name="vmInfo">View model info.</param> /// <param name="args">Arguments containing information on clients to send to.</param> private void Send(VMInfo vmInfo, GroupSend args) { ResponseVMFilter.Invoke(vmInfo, args, filteredData => { VMResponse(MULTICAST + nameof(GroupSend), vmInfo.Id, JsonSerializer.Serialize(args)); return(Task.CompletedTask); }); }
/// <summary> /// Push property changed updates on a view model back to the client. /// </summary> /// <param name="vmInfo">View model.</param> /// <param name="vmData">Serialized data to be pushed. If null, it's coming from the view model.</param> protected virtual void PushUpdates(VMInfo vmInfo, string vmData) { if (string.IsNullOrEmpty(vmData)) { return; } ResponseVMFilter.Invoke(vmInfo, vmData, filteredData => { var vmDataToSend = filteredData is GroupSend ? (filteredData as GroupSend).Data : (string)filteredData; VMResponse(vmInfo.ConnectionId, vmInfo.Id, vmDataToSend); return(Task.CompletedTask); }); }
/// <summary> /// Push property changed updates on all view models back to the client. /// </summary> protected virtual void PushUpdates() { foreach (var kvp in _activeVMs) { var vmInstance = kvp.Value.Instance; lock (vmInstance) { var changedProperties = new Dictionary <string, object>(vmInstance.ChangedProperties); if (changedProperties.Count > 0) { var vmData = Serialize(changedProperties); ResponseVMFilter.Invoke(kvp.Key, vmInstance, vmData, filteredData => { _vmResponse(kvp.Value.ConnectionId, kvp.Key, (string)filteredData); // After the changes are forwarded, accept the changes so they won't be marked as changed anymore. vmInstance.AcceptChangedProperties(); }); } } } }
/// <summary> /// Handles a request for a view model from a browser client. /// </summary> /// <param name="connectionId">Identifies the client connection.</param> /// <param name="vmId">Identifies the view model.</param> /// <param name="vmArg">Optional view model's initialization argument.</param> /// <returns>Group name, if the request is for a multicast view model associated with one.</returns> public async virtual Task <string> OnRequestVMAsync(string connectionId, string vmId, object vmArg = null) { BaseVM vmInstance = null; if (_activeVMs.ContainsKey(vmId)) { vmInstance = _activeVMs[vmId].Instance; } else { // Create a new view model instance whose class name is matching the given VMId. vmInstance = CreateVM(vmId, vmArg); // Let the instance complete its initialization. If multicast, make sure it's only called once. if ((vmInstance as MulticastVM)?.RaiseCreatedEvent != false) { await vmInstance.OnCreatedAsync(); } } await RequestVMFilter.Invoke(vmId, vmInstance, vmArg, async data => { string vmData = vmInstance.Serialize(); string groupName = vmInstance is MulticastVM ? (vmInstance as MulticastVM).GroupName : null; // Send the view model data back to the browser client. await ResponseVMFilter.Invoke(new VMInfo(vmId, vmInstance, connectionId, groupName), vmData, filteredData => VMResponse(connectionId, vmId, (string)filteredData)); // Reset the changed property states unless it's a multicast. if (vmInstance is MulticastVM == false) { vmInstance.AcceptChangedProperties(); } // Add the view model instance to the controller. if (!_activeVMs.ContainsKey(vmId)) { var vmInfo = new VMInfo(id: vmId, instance: vmInstance, connectionId: connectionId, groupName: groupName); vmInstance.RequestPushUpdates += VmInstance_RequestPushUpdates; if (vmInstance is MulticastVM) { var multicastVM = vmInstance as MulticastVM; multicastVM.RequestMulticastPushUpdates += VMInstance_RequestMulticastPushUpdates; multicastVM.RequestSend += VMInstance_RequestSend; } _activeVMs.TryAdd(vmId, vmInfo); } else { _activeVMs[vmId].ConnectionId = connectionId; } // If this request causes other view models to change, push those new values back to the client. foreach (var vmInfo in _activeVMs.Values) { PushUpdates(vmInfo); } }); return(_activeVMs[vmId].GroupName); }