From a53c707f0a2a7bec35db636f42b1a4f25e114a5e Mon Sep 17 00:00:00 2001 From: dicky Date: Fri, 29 Nov 2019 14:05:16 -0800 Subject: [PATCH] Run master vm through vm filters (#226). --- .../VMController/VMController.cs | 39 +++++++---- UnitTests/MasterDetailsVMTest.cs | 69 +++++++++++++++++++ UnitTests/VMSerializerTest.cs | 12 ++-- 3 files changed, 101 insertions(+), 19 deletions(-) diff --git a/DotNetifyLib.Core/VMController/VMController.cs b/DotNetifyLib.Core/VMController/VMController.cs index d91ad49f..d1b73409 100644 --- a/DotNetifyLib.Core/VMController/VMController.cs +++ b/DotNetifyLib.Core/VMController/VMController.cs @@ -220,7 +220,7 @@ public virtual string OnRequestVM(string connectionId, string vmId, object vmArg var vmData = vmInstance.Serialize(); // Send the view model data back to the browser client. - ResponseVMFilter.Invoke(vmId, vmInstance, vmData, filteredData => _vmResponse(connectionId, vmId, (string)filteredData)); + ResponseVMFilter.Invoke(vmId, vmInstance, vmData, filteredData => _vmResponse(connectionId, vmId, (string) filteredData)); // Reset the changed property states. vmInstance.AcceptChangedProperties(); @@ -356,11 +356,12 @@ protected virtual BaseVM CreateVM(string vmId, object vmArg = null, string vmNam // If the view model Id is in the form of a delimited path, it has a master view model. BaseVM masterVM = null; + string masterVMId = null; var path = vmId.Split('.'); if (path.Length > 1) { // Get the master view model; create the instance if it doesn't exist. - var masterVMId = vmId.Remove(vmId.LastIndexOf('.')); + masterVMId = vmId.Remove(vmId.LastIndexOf('.')); lock (_activeVMs) { if (!_activeVMs.ContainsKey(masterVMId)) @@ -384,19 +385,31 @@ protected virtual BaseVM CreateVM(string vmId, object vmArg = null, string vmNam vmInstanceId = path[1]; } - // Get the view model instance from the master view model, and if not, create it ourselves here. - var vmInstance = masterVM?.GetSubVM(vmTypeName, vmInstanceId) - ?? _vmFactory.GetInstance(vmTypeName, vmInstanceId, vmNamespace) - ?? throw new Exception($"[dotNetify] ERROR: '{vmId}' is not a known view model! Its assembly must be registered through VMController.RegisterAssembly."); + BaseVM vmInstance = null; + void createVMAction(object data) + { + // Get the view model instance from the master view model, and if not, create it ourselves here. + vmInstance = masterVM?.GetSubVM(vmTypeName, vmInstanceId) ?? _vmFactory.GetInstance(vmTypeName, vmInstanceId, vmNamespace); + if (vmInstance != null) + { + // If there are view model arguments, set them into the instance. + if (data is JObject) + foreach (var prop in (data as JObject).Properties()) + UpdateVM(vmInstance, prop.Name, prop.Value.ToString()); - // If there are view model arguments, set them into the instance. - if (vmArg is JObject) - foreach (var prop in (vmArg as JObject).Properties()) - UpdateVM(vmInstance, prop.Name, prop.Value.ToString()); + // Pass the view model instance to the master view model. + masterVM?.OnSubVMCreated(vmInstance); + } + } - // Pass the view model instance to the master view model. - masterVM?.OnSubVMCreated(vmInstance); + // If there's a master view model, run it through the view model filter. + if (masterVM != null) + RequestVMFilter(masterVMId, masterVM, vmArg, createVMAction); + else + createVMAction(vmArg); + if (vmInstance == null) + throw new Exception($"[dotNetify] ERROR: '{vmId}' is not a known view model! Its assembly must be registered through VMController.RegisterAssembly."); return vmInstance; } @@ -482,7 +495,7 @@ protected virtual void PushUpdates(VMInfo vmInfo, string vmData) ResponseVMFilter.Invoke(vmInfo.Id, vmInfo.Instance, vmData, filteredData => { - _vmResponse(vmInfo.ConnectionId, vmInfo.Id, (string)filteredData); + _vmResponse(vmInfo.ConnectionId, vmInfo.Id, (string) filteredData); }); } diff --git a/UnitTests/MasterDetailsVMTest.cs b/UnitTests/MasterDetailsVMTest.cs index 8bfa23f4..06e9a00d 100644 --- a/UnitTests/MasterDetailsVMTest.cs +++ b/UnitTests/MasterDetailsVMTest.cs @@ -1,4 +1,6 @@ +using System; using System.Collections.Generic; +using System.Threading.Tasks; using DotNetify; using DotNetify.Testing; using Microsoft.VisualStudio.TestTools.UnitTesting; @@ -11,6 +13,7 @@ public class MasterDetailsVMTest private MasterVM _masterVM = new MasterVM(); private string _detailsVMId = $"{nameof(MasterVM)}.{nameof(DetailsVM)}"; + [CustomFilter] private class MasterVM : BaseVM { private DetailsVM _detailsVM = new DetailsVM() { Value = int.MaxValue }; @@ -25,11 +28,39 @@ private class MasterVM : BaseVM public override void OnSubVMDisposing(BaseVM subVM) => DisposedSubVM = subVM; } + [CustomFilter] private class DetailsVM : BaseVM { public int Value { get; set; } } + [CustomFilter] + private class RootVM : BaseVM + { + } + + private class CustomFilterAttribute : Attribute + { + } + + private class CustomFilter : IVMFilter + { + public static event EventHandler> Invoked; + + public static void Cleanup() + { + if (Invoked != null) + foreach (Delegate d in Invoked.GetInvocationList()) + Invoked -= (EventHandler>) d; + } + + public Task Invoke(CustomFilterAttribute attribute, VMContext context, NextFilterDelegate next) + { + Invoked?.Invoke(this, Tuple.Create(attribute, context)); + return next.Invoke(context); + } + } + private HubEmulator _hubEmulator; [TestInitialize] @@ -41,6 +72,12 @@ public void Initialize() .Build(); } + [TestCleanup] + public void Cleanup() + { + CustomFilter.Cleanup(); + } + [TestMethod] public void MasterDetailsVM_Request() { @@ -50,6 +87,38 @@ public void MasterDetailsVM_Request() Assert.AreEqual(int.MaxValue, (int) response.Value); } + [TestMethod] + public void MasterDetailsVM_RequestWithCustomFilter_FiltersInvoked() + { + var contexts = new List(); + CustomFilter.Invoked += customFilter_Invoked; + void customFilter_Invoked(object sender, Tuple e) => contexts?.Add(e.Item2); + + var hubEmulator = new HubEmulatorBuilder() + .Register() + .Register() + .Register() + .UseFilter() + .Build(); + + var client = hubEmulator.CreateClient(); + client.Connect(_detailsVMId).As(); + client.Destroy(); + + Assert.IsTrue(contexts.Count >= 2); + Assert.IsTrue(contexts[0].Instance is MasterVM); + Assert.IsTrue(contexts[1].Instance is DetailsVM); + + contexts.Clear(); + + client.Connect("RootVM.MasterVM.DetailsVM").As(); + + Assert.IsTrue(contexts.Count >= 3); + Assert.IsTrue(contexts[0].Instance is RootVM); + Assert.IsTrue(contexts[1].Instance is MasterVM); + Assert.IsTrue(contexts[2].Instance is DetailsVM); + } + [TestMethod] public void MasterDetailsVM_Update() { diff --git a/UnitTests/VMSerializerTest.cs b/UnitTests/VMSerializerTest.cs index 54e53da7..2d8c9fa7 100644 --- a/UnitTests/VMSerializerTest.cs +++ b/UnitTests/VMSerializerTest.cs @@ -1,5 +1,5 @@ -using System; -using System.Collections.Generic; +using System.Collections.Generic; +using System.Linq; using DotNetify; using Microsoft.VisualStudio.TestTools.UnitTesting; @@ -21,10 +21,10 @@ public void Serialize_SetsIgnoredPropertyNames() Assert.IsNotNull(resolver); var serializer = new VMSerializer(); - var ignoredPropertyNames = new List {"World"}; - serializer.Serialize(new {Hello = "Hello", World = "World"}, ignoredPropertyNames); + var ignoredPropertyNames = new List { "World" }; + serializer.Serialize(new { Hello = "Hello", World = "World" }, ignoredPropertyNames); - Assert.AreSame(ignoredPropertyNames, resolver.IgnoredPropertyNames); + Assert.IsTrue(ignoredPropertyNames.All(name => resolver.IgnoredPropertyNames.Contains(name))); } } -} +} \ No newline at end of file