public void RecordCalculatedResults(string k1, string k2, decimal pr) { if (calculatedResults.ContainsKey(k1)) { var innerDictionary = calculatedResults[k1]; if (innerDictionary.ContainsKey(k2)) { throw new NotSupportedException("This pattern expects only one entry per k1k2 pair"); } else { //ToDo: Better understanding/handling of exceptions here try { innerDictionary.Add(k2, pr); } catch { new Exception($"adding {pr} to {k1}'s innerDictionary keyed by {k2} failed"); } } } else { var innerDictionary = new ConcurrentObservableDictionary <string, decimal>(); try { innerDictionary.Add(k2, pr); } catch { new Exception($"adding {pr} to the new innerDictionary keyed by {k2} failed"); } try { calculatedResults.Add(k1, innerDictionary); } catch { new Exception($"adding the new innerDictionary to calculatedResults keyed by {k1} failed"); } }; }
public void RecordR(string k1, string k2, decimal pr) { if (ResultsCOD.ContainsKey(k1)) { var innerCOD = ResultsCOD[k1]; if (innerCOD.ContainsKey(k2)) { throw new NotSupportedException("This pattern expects only one entry per k1k2 pair"); } else { //ToDo: Better understanding/handling of exceptions here try { innerCOD.Add(k2, pr); } catch { new Exception($"adding {pr} to {k1}'s innerDictionary keyed by {k2} failed"); } } } else { var innerCOD = new ConcurrentObservableDictionary <string, decimal>(); if (this.onResultsNestedCODCollectionChanged != null) { innerCOD.CollectionChanged += this.onResultsNestedCODCollectionChanged; } if (this.onResultsNestedCODPropertyChanged != null) { innerCOD.PropertyChanged += this.onResultsNestedCODPropertyChanged; } try { innerCOD.Add(k2, pr); } catch { new Exception($"adding {pr} to the new innerDictionary keyed by {k2} failed"); } try { ResultsCOD.Add(k1, innerCOD); } catch { new Exception($"adding the new innerDictionary to cODR keyed by {k1} failed"); } }; }
public void ConcurrentObservableDictionaryTest() { ConcurrentObservableDictionary <int, string> dict = new ConcurrentObservableDictionary <int, string>(); var times = 0; dict.CollectionChanged += delegate { times++; }; dict.Add(1, "foo"); dict.Add(2, "moo"); dict.Add(3, "boo"); dict.AddOrReplace(1, "boo"); dict.Remove(dict.First(x => x.Value == "moo")); Assert.True(dict.Values.All(x => x == "boo")); Assert.Equal(5, times); }
public void ConcurrentObservableDictionaryTest() { ConcurrentObservableDictionary <int, string> dict = new ConcurrentObservableDictionary <int, string>(); _times = 0; dict.CollectionChanged += Dict_CollectionChanged; try { dict.Add(1, "foo"); dict.Add(2, "moo"); dict.Add(3, "boo"); dict.AddOrReplace(1, "boo"); dict.Remove(dict.First(x => x.Value == "moo")); Assert.DoesNotContain(dict.Values, x => x != "boo"); Assert.Equal(5, _times); } finally { dict.CollectionChanged -= Dict_CollectionChanged; } }
public void ConcurrentObservableDictionarySerializationTest() { var serializer = new BinaryFormatter(); var stream = new MemoryStream(); var collection = new ConcurrentObservableDictionary <string, int>(); for (int i = 0; i < 10; i++) { collection.Add("TestItem" + (i + 1).ToString(), i); } serializer.Serialize(stream, collection); stream.Position = 0; collection = serializer.Deserialize(stream) as ConcurrentObservableDictionary <string, int>; for (int i = 0; i < 10; i++) { Assert.AreEqual(i, collection["TestItem" + (i + 1).ToString()]); } }
/// <summary> /// Defines the value of a property of this class. /// This action triggers the <see cref="PropertyChanged"/> event, unless <see cref="AllowRaiseEvent"/> is set top false. /// </summary> /// <param name="key">The name of the property</param> /// <param name="value">The value of the property</param> public virtual void SetValue(string key, object value) { key = key.ToLower(); object old = null; if (!_values.ContainsKey(key)) { _values.Add(key, value); } else { old = _values[key]; _values[key] = value; } if (old != value) { OnPropertyChanged(key, old, value); } }
public void TestManyOperations() { // Create some random, but unique items // Use a fixed seed for consistency in results Random random = new Random(1); HashSet <int> baseItemsSet = new HashSet <int>(); while (baseItemsSet.Count < 1_100_000) { baseItemsSet.Add(random.Next()); } // Create 2 collections, 1 to test, and 1 to compare against var testCollection = new ConcurrentObservableDictionary <string, string>(); var list = new List <KeyValuePair <string, string> >(); // Create 1,000,000 items to add and insert var itemsToAdd = baseItemsSet .Take(1_000_000) .Select(x => Swordfish.NET.Collections.KeyValuePair.Create($"Key {x}", $"Value {x}")) .ToList(); // Create 100,000 items to insert var itemsToInsert = baseItemsSet .Skip(1_000_000) .Take(100_000) .Select(x => Swordfish.NET.Collections.KeyValuePair.Create($"Insert Key {x}", $"Insert Value {x}")) .ToList(); // Create items to remove var itemsToRemove = itemsToInsert .Take(1000) .ToList(); foreach (var item in itemsToAdd) { testCollection.Add(item.Key, item.Value); list.Add(item); } // Check items are equal count Assert.IsTrue(list.Count == testCollection.Count, "Added Items correct count"); // Check items are equal order var allEqualAfterAdd = list .Zip(testCollection, (a, b) => (a.Key == b.Key) && (a.Value == b.Value)) .All(a => a); Assert.IsTrue(allEqualAfterAdd, "Added items correct order"); // Test inserting items int insertIndex = itemsToInsert.Count + 100; foreach (var item in itemsToInsert) { // We have the function but it's there for other reasons testCollection.Insert(insertIndex, item); list.Insert(insertIndex, item); insertIndex--; } // Check items are equal count Assert.IsTrue(list.Count == testCollection.Count, "Items correct count after inserting"); // Check items are equal order var allEqualAfterInsert = list .Zip(testCollection, (a, b) => (a.Key == b.Key) && (a.Value == b.Value)) .All(a => a); Assert.IsTrue(allEqualAfterAdd, "Items correct order after insert"); // Test removing items foreach (var item in itemsToRemove) { testCollection.Remove(item.Key); list.Remove(item); } // Check items are equal count Assert.IsTrue(list.Count == testCollection.Count, "Items correct count after removing"); // Check items are equal order var allEqualAfterRemove = list .Zip(testCollection, (a, b) => (a.Key == b.Key) && (a.Value == b.Value)) .All(a => a); Assert.IsTrue(allEqualAfterRemove, "Items correct order after removing"); // Test contains var containsAll = list .All(kv => testCollection.Contains(kv)); Assert.IsTrue(containsAll, "Contains all the items is true"); var containsNone = itemsToRemove .Any(kv => testCollection.ContainsKey(kv.Key)); Assert.IsFalse(containsNone, "Contains any of the removed items is false"); // Test removing at int removeAtIndex = list.Count - 30; while (removeAtIndex >= 0 && list.Count > 0) { list.RemoveAt(removeAtIndex); testCollection.RemoveAt(removeAtIndex); removeAtIndex -= 30; } // Check items are equal count Assert.IsTrue(list.Count == testCollection.Count, "Items correct count after removing at index"); // Check items are equal order var allEqualAfterRemoveAt = list .Zip(testCollection, (a, b) => (a.Key == b.Key) && (a.Value == b.Value)) .All(a => a); Assert.IsTrue(allEqualAfterRemoveAt, "Items correct order after removing at index"); }
public void Configure(IAppHost appHost) { Log.Debug("starting RealEstateServicesPlugin.Configure"); // Populate this Plugin's Application Configuration Settings // Location of the files will depend on running as LifeCycle Production/QA/Dev as well as Debug and Release settings var pluginAppSettings = new MultiAppSettingsBuilder() // Command line flags have highest priority // next in priority are Environment variables //.AddEnvironmentalVariables() // next in priority are Configuration settings in a text file relative to the current working directory at the point in time when this method executes. .AddTextFile(pluginSettingsTextFileName) // Builtin (compiled in) have the lowest priority .AddDictionarySettings(DefaultConfiguration.Configuration()) .Build(); // Key names in the cache for Configuration settings for a Plugin consist of the namespace and the string .Config // Key names in the appSettings of a Plugin for Configuration settings may or may not have the prefix // Compare the two lists of Configuration setting keys... // create a copy of the keys from AppSettings ensuring all are prefixed with the namespace and .Config var configKeyPrefix = myNamespace + ".Config."; var lengthConfigKeyPrefix = configKeyPrefix.Length; var appSettingsConfigKeys = pluginAppSettings.GetAllKeys(); var fullAppSettingsConfigKeys = appSettingsConfigKeys.Select(x => x.IndexOf(configKeyPrefix) >= 0? x: configKeyPrefix + x); // Get this namespaces configuration settings from the cache var cacheClient = appHost.GetContainer().Resolve <ICacheClient>(); var cacheConfigKeys = cacheClient.GetKeysStartingWith(configKeyPrefix); // Compare the configuration retrieved from the cache with the configuration from the built-in defaults, the text files, and the environment variables // If the cache is missing a ConfigKey, update the cache with the ConfigKey and its value from the appSettings var excludedConfigKeys = new HashSet <string>(cacheConfigKeys); var additionalConfigKeys = fullAppSettingsConfigKeys.Where(ck => !excludedConfigKeys.Contains(ck)); foreach (var ck in additionalConfigKeys) { cacheClient.Set <string>(ck, pluginAppSettings.GetString(ck.Substring(lengthConfigKeyPrefix))); } // If both the cache and the appSettings have the same ConfigKey, and the same value, do nothing // If both the cache and the appSettings have the same ConfigKey, and the values are different, // If the cache has a ConfigKey and the appSettings does not have that ConfigKey // Set a flag indicating the need to dialog with the user to resolve the cache vs. appSettings discrepancies bool configurationsMatch = true; // (appSettingsConfigkeys.Count == cacheConfigkeys.Count) ; // Populate this Plugin's Gateways // Location of the files will depend on running as LifeCycle Production/QA/Dev as well as Debug and Release settings var pluginGateways = new MultiGatewaysBuilder() // Command line flags have highest priority // next in priority are Environment variables //.AddEnvironmentalVariables() // next in priority are Configuration settings in a text file relative to the current working directory at the point in time when this method executes. //.AddTextFile(pluginGatewaysTextFileName) // Builtin (compiled in) have the lowest priority //.AddDictionarySettings(DefaultGateways.Configuration()) .Build(); // Create a Gateways collection from the txt file ConcurrentObservableDictionary <string, IGateway> gateways = new ConcurrentObservableDictionary <string, IGateway>(); gateways.Add("GoogleMapsGeoCoding", new GatewayBuilder().Build()); // Create the Plugin's data structure. There should only be a single instance. // Every Property matching a ConfigKey gets/sets the value of the matching ConfigKey in the cache // ConfigKey Properties do not have to be set in the constructor because the cache was setup before calling the constructor RealEstateServicesData RealEstateServicesData = new RealEstateServicesData(appHost, new ConcurrentObservableDictionary <string, decimal>(), onPluginRootCollectionChanged, onPluginRootPropertyChanged); // copy the most recent configuration settings to the Data // hmm should be a way to make sure the Data has a Property for each configuration setting, and to populate the initial Data with the cache value RealEstateServicesData.GoogleAPIKeyEncrypted = cacheClient.Get <string>(configKeyPrefix + "GoogleAPIKeyEncrypted"); RealEstateServicesData.HomeAwayAPIKeyEncrypted = cacheClient.Get <string>(configKeyPrefix + "HomeAwayAPIKeyEncrypted"); RealEstateServicesData.HomeAway_API_URI = cacheClient.Get <string>(configKeyPrefix + "HomeAway_API_URI"); RealEstateServicesData.Google_API_URI = cacheClient.Get <string>(configKeyPrefix + "Google_API_URI"); RealEstateServicesData.UriHomeAway_API_URI = cacheClient.Get <Uri>(configKeyPrefix + "UriHomeAway_API_URI"); RealEstateServicesData.UriGoogle_API_URI = cacheClient.Get <Uri>(configKeyPrefix + "UriGoogle_API_URI"); // and pass the Plugin's data structure to the container so it will be available to every other module and services appHost.GetContainer() .Register <RealEstateServicesData>(x => RealEstateServicesData); // ToDo: enable the mechanisms that monitors each GUI-specific data sensor, and start them running }