//===================================================================== /// <summary> /// This helper method can be called to find all target files and load them into the dictionary /// </summary> /// <param name="maxDegreeOfParallelism">This can be used to override the maximum degree of parallelism. /// By default, it is -1 to allow as many threads as possible.</param> /// <remarks>This method assumes that the dictionary is thread-safe and supports parallel loading of /// target data. If not, override this method to load the data synchronously.</remarks> protected virtual void LoadTargetDictionary(int maxDegreeOfParallelism = -1) { Parallel.ForEach(Directory.EnumerateFiles(this.DirectoryPath, this.FilePattern, this.Recurse ? SearchOption.AllDirectories : SearchOption.TopDirectoryOnly), new ParallelOptions { MaxDegreeOfParallelism = maxDegreeOfParallelism }, file => { // Skip the file if not in a defined filter or if it's already in the dictionary if ((namespaceFileFilter.Count != 0 && !namespaceFileFilter.Contains(Path.GetFileName(file))) || this.ContainsKey("N:" + Path.GetFileNameWithoutExtension(file))) { return; } this.BuildComponent.WriteMessage(MessageLevel.Info, "Indexing targets in {0}", file); try { using (var reader = XmlReader.Create(file, new XmlReaderSettings { CloseInput = true })) { XPathDocument document = new XPathDocument(reader); // We use the Target.Add() method so that any of its dependencies are added too foreach (var t in XmlTargetDictionaryUtilities.EnumerateTargets(document.CreateNavigator())) { t.Add(this); } } } catch (XmlSchemaException e) { throw new InvalidOperationException(String.Format(CultureInfo.InvariantCulture, "The reference targets file '{0}' is not valid. The error message is: {1}", file, e.GetExceptionMessage())); } catch (XmlException e) { throw new InvalidOperationException(String.Format(CultureInfo.InvariantCulture, "The reference targets file '{0}' is not well-formed XML. The error message is: {1}", file, e.GetExceptionMessage())); } catch (IOException e) { throw new InvalidOperationException(String.Format(CultureInfo.InvariantCulture, "An access error occurred while opening the reference targets file '{0}'. The error " + "message is: {1}", file, e.GetExceptionMessage())); } }); }
/// <summary> /// This is overridden to load the SQL dictionary in a thread-safe manner /// </summary> /// <param name="maxDegreeOfParallelism">This can be used to override the maximum degree of parallelism. /// By default, it is -1 to allow as many threads as possible.</param> protected override void LoadTargetDictionary(int maxDegreeOfParallelism = -1) { var namespaceFileFilter = this.NamespaceFileFilter; Parallel.ForEach(Directory.EnumerateFiles(this.DirectoryPath, this.FilePattern, this.Recurse ? SearchOption.AllDirectories : SearchOption.TopDirectoryOnly), new ParallelOptions { MaxDegreeOfParallelism = maxDegreeOfParallelism }, file => { using (SqlConnection cn = new SqlConnection(connectionString)) using (SqlCommand cmd = new SqlCommand()) { cn.Open(); cmd.Connection = cn; cmd.Parameters.Add(new SqlParameter("@key", SqlDbType.VarChar, 768)); cmd.CommandText = String.Format(CultureInfo.InvariantCulture, "Select TargetKey From Targets Where GroupId = '{0}' And TargetKey = @key", base.DictionaryId); cmd.Parameters[0].Value = "N:" + Path.GetFileNameWithoutExtension(file); // Skip the file if not in a defined filter or if it's already in the dictionary if ((namespaceFileFilter.Count != 0 && !namespaceFileFilter.Contains(Path.GetFileName(file))) || cmd.ExecuteScalar() != null) { return; } this.BuildComponent.WriteMessage(MessageLevel.Info, "Indexing targets in {0}", file); cmd.CommandText = String.Format(CultureInfo.InvariantCulture, "IF NOT EXISTS(Select * From Targets Where GroupId = '{0}' And TargetKey = @key) " + "Insert Targets (GroupId, TargetKey, TargetValue) Values ('{0}', @key, @value) " + "ELSE Update Targets Set TargetValue = @value Where GroupId = '{0}' " + "And TargetKey = @key", base.DictionaryId); cmd.Parameters.Add(new SqlParameter("@value", SqlDbType.VarBinary)); BinaryFormatter bf = new BinaryFormatter { Context = new StreamingContext(StreamingContextStates.Persistence) }; try { using (var reader = XmlReader.Create(file, new XmlReaderSettings { CloseInput = true })) { XPathDocument document = new XPathDocument(reader); foreach (var t in XmlTargetDictionaryUtilities.EnumerateTargets(document.CreateNavigator())) { cmd.Parameters[0].Value = t.Id; using (MemoryStream ms = new MemoryStream()) { bf.Serialize(ms, t); cmd.Parameters[1].Value = ms.GetBuffer(); cmd.ExecuteNonQuery(); } // Enumeration targets have members we need to add too. We can't use the // Target.Add() method here so we must do it manually. if (t is EnumerationTarget et) { foreach (var el in et.Elements) { cmd.Parameters[0].Value = el.Id; using (MemoryStream ms = new MemoryStream()) { bf.Serialize(ms, el); cmd.Parameters[1].Value = ms.GetBuffer(); cmd.ExecuteNonQuery(); } } } } } } catch (XmlSchemaException e) { throw new InvalidOperationException(String.Format(CultureInfo.InvariantCulture, "The reference targets file '{0}' is not valid. The error message is: {1}", file, e.GetExceptionMessage())); } catch (XmlException e) { throw new InvalidOperationException(String.Format(CultureInfo.InvariantCulture, "The reference targets file '{0}' is not well-formed XML. The error message is: {1}", file, e.GetExceptionMessage())); } catch (IOException e) { throw new InvalidOperationException(String.Format(CultureInfo.InvariantCulture, "An access error occurred while opening the reference targets file '{0}'. The error " + "message is: {1}", file, e.GetExceptionMessage())); } } }); }