/// <summary> /// Loads the configuration. /// </summary> /// <param name="path">Path to the directory containing configuration information.</param> /// <param name="sections">Collection of keyed ConfigurationSections.</param> /// <remarks>Loads the configuration with the same name as the service type (e.g. [ServiceTypeName].XML. This /// method was constructed this way to enable some level of unit testing. ConfigurationSection cannot be created or mocked.</remarks> internal void LoadConfiguration(string path, KeyedCollection <string, ConfigurationSection> sections) { Guard.ArgumentNotNullOrWhitespace(path, nameof(path)); Guard.ArgumentNotNull(sections, nameof(sections)); _eventSource?.ServicePartitionConfigurationChanged(_serviceName, _partitionId, _replicaOrInstanceId); try { // Create an MD5 to hash the values to determine if they have changed. using (MD5 md5 = MD5.Create()) { // First load the configuration section for this service type. if (sections.Contains(_serviceNameUri.AbsoluteUri)) { // Get the section and calculate the hash. ConfigurationSection section = sections[_serviceNameUri.AbsoluteUri]; string sectionContent = string.Join("|", section.Parameters.Select(p => $"{p.Name}~{p.Value}")); byte[] hash = md5.ComputeHash(Encoding.UTF8.GetBytes(sectionContent)); if (false == CompareHashes(hash, _configSectionHash)) { // Set the provider values. _configSection = section; _configSectionHash = hash; // If necessary, call the property changed event. OnConfigurationPropertyChangedEvent?.Invoke(this, EventArgs.Empty); } } // Second, attempt to load a file of the format <service name>.json. Use the last segment of the service name Uri for the file name. string filepath = Path.Combine(path, $"{_serviceName}.json"); // Stream the file while calculating the MD5 hash of the contents. using (FileStream fs = new FileStream(filepath, FileMode.Open, FileAccess.Read)) using (CryptoStream cs = new CryptoStream(fs, md5, CryptoStreamMode.Read)) using (StreamReader reader = new StreamReader(cs)) { string json = reader.ReadToEnd(); JsonSerializerSettings settings = new JsonSerializerSettings(); settings.Converters.Add(new IsoDateTimeConverter()); TConfiguration result = JsonConvert.DeserializeObject <TConfiguration>(json, settings); byte[] fileHash = md5.Hash; if (false == CompareHashes(fileHash, _configFileHash)) { // If necessary, call the class changed event. OnConfigurationClassChangedEvent?.Invoke(this, new ConfigurationClassChangedEventArgs <TConfiguration>(_serviceName, _configFile, result)); // Set the provider values. _configFileHash = fileHash; _configFile = result; } } } } catch (FileNotFoundException) { } }
/// <summary> /// QueueService constructor. /// </summary> /// <param name="context">StatefulServiceContext instance.</param> /// <param name="eventSource">IStatefulServiceEventSource instance for diagnostic logging.</param> public GenericInt64PartitionService(StatefulServiceContext context, IServiceEventSource eventSource) : base(context) { // Check passed parameters. Guard.ArgumentNotNull(context, nameof(context)); Guard.ArgumentNotNull(eventSource, nameof(eventSource)); _eventSource = eventSource; TokenSource = new CancellationTokenSource(); // Parse the service name into an application name. string appName = (Context.ServiceName.Segments.Length > 2) ? Context.ServiceName.Segments[1].Replace("/", "") : ""; Application = new Uri($"fabric:/{appName}"); ConfigurationProvider = new ConfigurationProvider <TConfiguration>(context.ServiceName, context.CodePackageActivationContext, eventSource, Context.PartitionId, Context.ReplicaOrInstanceId); _eventSource?.ServicePartitionConfigurationChanged(Context.ServiceTypeName, Context.PartitionId, Context.ReplicaOrInstanceId); }