/// <summary> /// Find all files that are to be considered SDK Resolvers. Pattern will match /// Root\SdkResolver\(ResolverName)\(ResolverName).dll. /// </summary> /// <param name="rootFolder"></param> /// <param name="location"></param> /// <returns></returns> internal virtual IList <string> FindPotentialSdkResolvers(string rootFolder, ElementLocation location) { var assembliesList = new List <string>(); if ((string.IsNullOrEmpty(rootFolder) || !FileUtilities.DirectoryExistsNoThrow(rootFolder)) && AdditionalResolversFolder == null) { return(assembliesList); } DirectoryInfo[] subfolders = GetSubfolders(rootFolder, AdditionalResolversFolder); foreach (var subfolder in subfolders) { var assembly = Path.Combine(subfolder.FullName, $"{subfolder.Name}.dll"); var manifest = Path.Combine(subfolder.FullName, $"{subfolder.Name}.xml"); var assemblyAdded = TryAddAssembly(assembly, assembliesList); if (!assemblyAdded) { assemblyAdded = TryAddAssemblyFromManifest(manifest, subfolder.FullName, assembliesList, location); } if (!assemblyAdded) { ProjectFileErrorUtilities.ThrowInvalidProjectFile(new BuildEventFileInfo(location), "SdkResolverNoDllOrManifest", subfolder.FullName); } } return(assembliesList); }
protected virtual void LoadResolvers(string resolverPath, LoggingContext loggingContext, ElementLocation location, List <SdkResolver> resolvers) { Assembly assembly; try { assembly = LoadResolverAssembly(resolverPath, loggingContext, location); } catch (Exception e) { ProjectFileErrorUtilities.ThrowInvalidProjectFile(new BuildEventFileInfo(location), e, "CouldNotLoadSdkResolverAssembly", resolverPath, e.Message); return; } foreach (Type type in GetResolverTypes(assembly)) { try { resolvers.Add((SdkResolver)Activator.CreateInstance(type)); } catch (TargetInvocationException e) { // .NET wraps the original exception inside of a TargetInvocationException which masks the original message // Attempt to get the inner exception in this case, but fall back to the top exception message string message = e.InnerException?.Message ?? e.Message; ProjectFileErrorUtilities.ThrowInvalidProjectFile(new BuildEventFileInfo(location), e.InnerException ?? e, "CouldNotLoadSdkResolver", type.Name, message); } catch (Exception e) { ProjectFileErrorUtilities.ThrowInvalidProjectFile(new BuildEventFileInfo(location), e, "CouldNotLoadSdkResolver", type.Name, e.Message); } } }
public RemoveOperation(RemoveOperationBuilder builder, LazyItemEvaluator <P, I, M, D> lazyEvaluator) : base(builder, lazyEvaluator) { _matchOnMetadata = builder.MatchOnMetadata.ToImmutable(); ProjectFileErrorUtilities.VerifyThrowInvalidProjectFile( _matchOnMetadata.IsEmpty || _itemSpec.Fragments.All(f => f is ItemSpec <P, I> .ItemExpressionFragment), new BuildEventFileInfo(string.Empty), "OM_MatchOnMetadataIsRestrictedToReferencedItems"); if (!_matchOnMetadata.IsEmpty) { _metadataSet = new MetadataTrie <P, I>(builder.MatchOnMetadataOptions, _matchOnMetadata, _itemSpec); } }
/// <summary> /// Determines what the real tools version is. /// </summary> private string ResolveToolsVersion(BuildRequestData data, string defaultToolsVersion, Internal.Utilities.GetToolset getToolset) { if (data.ExplicitToolsVersionSpecified) { return(data.ExplicitlySpecifiedToolsVersion); } // None was specified by the call, fall back to the project's ToolsVersion attribute if (data.ProjectInstance != null) { return(data.ProjectInstance.Toolset.ToolsVersion); } else if (FileUtilities.IsVCProjFilename(data.ProjectFullPath)) { ProjectFileErrorUtilities.ThrowInvalidProjectFile(new BuildEventFileInfo(data.ProjectFullPath), "ProjectUpgradeNeededToVcxProj", data.ProjectFullPath); } else if (!FileUtilities.IsSolutionFilename(data.ProjectFullPath)) { // If the file does not exist, it's a failure of the host, possibly msbuild.exe; so it's an ArgumentException here ErrorUtilities.VerifyThrowArgument(File.Exists(data.ProjectFullPath), "ProjectFileNotFound", data.ProjectFullPath); string toolsVersionFromFile = null; // We use an XmlTextReader to sniff, rather than simply loading a ProjectRootElement into the cache, because // quite likely this won't be the node on which the request will be built, so we'd be loading the ProjectRootElement // on this node unnecessarily. toolsVersionFromFile = XmlUtilities.SniffAttributeValueFromXmlFile(ProjectFullPath, XMakeAttributes.project, XMakeAttributes.toolsVersion); // Instead of just using the ToolsVersion from the file, though, ask our "source of truth" what the ToolsVersion // we should use is. This takes into account the various environment variables that can affect ToolsVersion, etc., // to make it more likely that the ToolsVersion we come up with is going to be the one actually being used by the // project at build time. string toolsVersionToUse = Utilities.GenerateToolsVersionToUse ( data.ExplicitlySpecifiedToolsVersion, toolsVersionFromFile, getToolset, defaultToolsVersion ); return(toolsVersionToUse); } // Couldn't find out the right ToolsVersion any other way, so just return the default. return(defaultToolsVersion); }
private List <ProjectItemInstance> FindItemsMatchingMetadataSpecification( ICollection <ProjectItemInstance> group, ProjectItemGroupTaskItemInstance child, Expander <ProjectPropertyInstance, ProjectItemInstance> expander, HashSet <string> matchOnMetadata, MatchOnMetadataOptions matchingOptions) { ItemSpec <ProjectPropertyInstance, ProjectItemInstance> itemSpec = new ItemSpec <ProjectPropertyInstance, ProjectItemInstance>(child.Remove, expander, child.RemoveLocation, Project.Directory, true); ProjectFileErrorUtilities.VerifyThrowInvalidProjectFile( itemSpec.Fragments.All(f => f is ItemSpec <ProjectPropertyInstance, ProjectItemInstance> .ItemExpressionFragment), BuildEventFileInfo.Empty, "OM_MatchOnMetadataIsRestrictedToReferencedItems", child.RemoveLocation, child.Remove); MetadataTrie <ProjectPropertyInstance, ProjectItemInstance> metadataSet = new MetadataTrie <ProjectPropertyInstance, ProjectItemInstance>(matchingOptions, matchOnMetadata, itemSpec); return(group.Where(item => metadataSet.Contains(matchOnMetadata.Select(m => item.GetMetadataValue(m)))).ToList()); }
private bool TryAddAssemblyFromManifest(string pathToManifest, string manifestFolder, List <string> assembliesList, ElementLocation location) { if (!string.IsNullOrEmpty(pathToManifest) && !FileUtilities.FileExistsNoThrow(pathToManifest)) { return(false); } string path = null; try { // <SdkResolver> // <Path>...</Path> // </SdkResolver> var manifest = SdkResolverManifest.Load(pathToManifest); if (manifest == null || string.IsNullOrEmpty(manifest.Path)) { ProjectFileErrorUtilities.ThrowInvalidProjectFile(new BuildEventFileInfo(location), "SdkResolverDllInManifestMissing", pathToManifest, string.Empty); } path = FileUtilities.FixFilePath(manifest.Path); } catch (XmlException e) { // Note: Not logging e.ToString() as most of the information is not useful, the Message will contain what is wrong with the XML file. ProjectFileErrorUtilities.ThrowInvalidProjectFile(new BuildEventFileInfo(location), e, "SdkResolverManifestInvalid", pathToManifest, e.Message); } if (!Path.IsPathRooted(path)) { path = Path.Combine(manifestFolder, path); path = Path.GetFullPath(path); } if (!TryAddAssembly(path, assembliesList)) { ProjectFileErrorUtilities.ThrowInvalidProjectFile(new BuildEventFileInfo(location), "SdkResolverDllInManifestMissing", pathToManifest, path); } return(true); }
/// <summary> /// Apply the Remove operation. /// </summary> /// <remarks> /// This operation is mostly implemented in terms of the default <see cref="LazyItemOperation.ApplyImpl(ImmutableList{ItemData}.Builder, ImmutableHashSet{string})"/>. /// This override exists to apply the removing-everything short-circuit. /// </remarks> protected override void ApplyImpl(ImmutableList <ItemData> .Builder listBuilder, ImmutableHashSet <string> globsToIgnore) { var matchOnMetadataValid = !_matchOnMetadata.IsEmpty && _itemSpec.Fragments.Count == 1 && _itemSpec.Fragments.First() is ItemSpec <ProjectProperty, ProjectItem> .ItemExpressionFragment; ProjectFileErrorUtilities.VerifyThrowInvalidProjectFile( _matchOnMetadata.IsEmpty || (matchOnMetadataValid && _matchOnMetadata.Count == 1), new BuildEventFileInfo(string.Empty), "OM_MatchOnMetadataIsRestrictedToOnlyOneReferencedItem"); if (_matchOnMetadata.IsEmpty && ItemspecContainsASingleBareItemReference(_itemSpec, _itemElement.ItemType)) { // Perf optimization: If the Remove operation references itself (e.g. <I Remove="@(I)"/>) // then all items are removed and matching is not necessary listBuilder.Clear(); return; } base.ApplyImpl(listBuilder, globsToIgnore); }
// todo port the self referencing matching optimization (e.g. <I Remove="@(I)">) from Update to Remove as well. Ideally make one mechanism for both. https://github.com/Microsoft/msbuild/issues/2314 // todo Perf: do not match against the globs: https://github.com/Microsoft/msbuild/issues/2329 protected override ImmutableList <I> SelectItems(ImmutableList <ItemData> .Builder listBuilder, ImmutableHashSet <string> globsToIgnore) { var matchOnMetadataValid = !_matchOnMetadata.IsEmpty && _itemSpec.Fragments.Count == 1 && _itemSpec.Fragments.First() is ItemSpec <ProjectProperty, ProjectItem> .ItemExpressionFragment; ProjectFileErrorUtilities.VerifyThrowInvalidProjectFile( _matchOnMetadata.IsEmpty || matchOnMetadataValid && _matchOnMetadata.Count == 1, new BuildEventFileInfo(string.Empty), "OM_MatchOnMetadataIsRestrictedToOnlyOneReferencedItem"); var items = ImmutableHashSet.CreateBuilder <I>(); foreach (ItemData item in listBuilder) { if (_matchOnMetadata.IsEmpty ? _itemSpec.MatchesItem(item.Item) : _itemSpec.MatchesItemOnMetadata(item.Item, _matchOnMetadata, _matchOnMetadataOptions)) { items.Add(item.Item); } } return(items.ToImmutableList()); }
private List <ProjectItemInstance> FindItemsUsingMatchOnMetadata( ICollection <ProjectItemInstance> items, ProjectItemGroupTaskItemInstance child, ItemBucket bucket, HashSet <string> matchOnMetadata, MatchOnMetadataOptions options) { ErrorUtilities.VerifyThrowArgumentNull(matchOnMetadata, nameof(matchOnMetadata)); var itemSpec = new ItemSpec <ProjectPropertyInstance, ProjectItemInstance>(child.Remove, bucket.Expander, child.RemoveLocation, Project.Directory, true); ProjectFileErrorUtilities.VerifyThrowInvalidProjectFile( itemSpec.Fragments.Count == 1 && itemSpec.Fragments.First() is ItemSpec <ProjectPropertyInstance, ProjectItemInstance> .ItemExpressionFragment && matchOnMetadata.Count == 1, new BuildEventFileInfo(string.Empty), "OM_MatchOnMetadataIsRestrictedToOnlyOneReferencedItem", child.RemoveLocation, child.Remove); return(items.Where(item => itemSpec.MatchesItemOnMetadata(item, matchOnMetadata, options)).ToList()); }
/// <summary> /// Determines what the real tools version is. /// </summary> private string ResolveToolsVersion(BuildRequestData data, string defaultToolsVersion) { if (data.ExplicitToolsVersionSpecified) { return(data.ExplicitlySpecifiedToolsVersion); } // None was specified by the call, fall back to the project's ToolsVersion attribute if (data.ProjectInstance != null) { return(data.ProjectInstance.Toolset.ToolsVersion); } if (FileUtilities.IsVCProjFilename(data.ProjectFullPath)) { ProjectFileErrorUtilities.ThrowInvalidProjectFile(new BuildEventFileInfo(data.ProjectFullPath), "ProjectUpgradeNeededToVcxProj", data.ProjectFullPath); } // We used to "sniff" the tools version from the project XML by opening it and reading the attribute. // This was causing unnecessary overhead since the ToolsVersion is never really used. Instead we just // return the default tools version return(defaultToolsVersion); }
private (IReadOnlyCollection <ProjectGraphEntryPoint> NewEntryPoints, IReadOnlyDictionary <string, IReadOnlyCollection <string> > SolutionDependencies) ExpandSolutionIfPresent(IReadOnlyCollection <ProjectGraphEntryPoint> entryPoints) { if (entryPoints.Count == 0 || !entryPoints.Any(e => FileUtilities.IsSolutionFilename(e.ProjectFile))) { return(entryPoints, null); } if (entryPoints.Count != 1) { throw new ArgumentException( ResourceUtilities.FormatResourceStringIgnoreCodeAndKeyword( "StaticGraphAcceptsSingleSolutionEntryPoint", string.Join(";", entryPoints.Select(e => e.ProjectFile)))); } ErrorUtilities.VerifyThrowArgument(entryPoints.Count == 1, "StaticGraphAcceptsSingleSolutionEntryPoint"); var solutionEntryPoint = entryPoints.Single(); var solutionGlobalProperties = ImmutableDictionary.CreateRange( keyComparer: StringComparer.OrdinalIgnoreCase, valueComparer: StringComparer.OrdinalIgnoreCase, items: solutionEntryPoint.GlobalProperties ?? ImmutableDictionary <string, string> .Empty); var solution = SolutionFile.Parse(FileUtilities.NormalizePath(solutionEntryPoint.ProjectFile)); if (solution.SolutionParserWarnings.Count != 0 || solution.SolutionParserErrorCodes.Count != 0) { throw new InvalidProjectFileException( ResourceUtilities.FormatResourceStringIgnoreCodeAndKeyword( "StaticGraphSolutionLoaderEncounteredSolutionWarningsAndErrors", solutionEntryPoint.ProjectFile, string.Join(";", solution.SolutionParserWarnings), string.Join(";", solution.SolutionParserErrorCodes))); } var projectsInSolution = GetBuildableProjects(solution); var currentSolutionConfiguration = SelectSolutionConfiguration(solution, solutionGlobalProperties); var newEntryPoints = new List <ProjectGraphEntryPoint>(projectsInSolution.Count); foreach (var project in projectsInSolution) { if (project.ProjectConfigurations.Count == 0) { continue; } var projectConfiguration = SelectProjectConfiguration(currentSolutionConfiguration, project.ProjectConfigurations); if (projectConfiguration.IncludeInBuild) { newEntryPoints.Add( new ProjectGraphEntryPoint( FileUtilities.NormalizePath(project.AbsolutePath), solutionGlobalProperties .SetItem("Configuration", projectConfiguration.ConfigurationName) .SetItem("Platform", projectConfiguration.PlatformName) )); } } newEntryPoints.TrimExcess(); return(newEntryPoints, GetSolutionDependencies(solution)); IReadOnlyCollection <ProjectInSolution> GetBuildableProjects(SolutionFile solutionFile) { return(solutionFile.ProjectsInOrder.Where(p => p.ProjectType == SolutionProjectType.KnownToBeMSBuildFormat).ToImmutableArray()); } SolutionConfigurationInSolution SelectSolutionConfiguration(SolutionFile solutionFile, ImmutableDictionary <string, string> globalProperties) { var solutionConfiguration = globalProperties.ContainsKey("Configuration") ? globalProperties["Configuration"] : solutionFile.GetDefaultConfigurationName(); var solutionPlatform = globalProperties.ContainsKey("Platform") ? globalProperties["Platform"] : solutionFile.GetDefaultPlatformName(); return(new SolutionConfigurationInSolution(solutionConfiguration, solutionPlatform)); } ProjectConfigurationInSolution SelectProjectConfiguration( SolutionConfigurationInSolution solutionConfig, IReadOnlyDictionary <string, ProjectConfigurationInSolution> projectConfigs) { // implements the matching described in https://docs.microsoft.com/en-us/visualstudio/ide/understanding-build-configurations?view=vs-2019#how-visual-studio-assigns-project-configuration var solutionConfigFullName = solutionConfig.FullName; if (projectConfigs.ContainsKey(solutionConfigFullName)) { return(projectConfigs[solutionConfigFullName]); } var partiallyMarchedConfig = projectConfigs.FirstOrDefault(pc => pc.Value.ConfigurationName.Equals(solutionConfig.ConfigurationName, StringComparison.OrdinalIgnoreCase)).Value; return(partiallyMarchedConfig ?? projectConfigs.First().Value); } IReadOnlyDictionary <string, IReadOnlyCollection <string> > GetSolutionDependencies(SolutionFile solutionFile) { var solutionDependencies = new Dictionary <string, IReadOnlyCollection <string> >(); foreach (var projectWithDependencies in solutionFile.ProjectsInOrder.Where(p => p.Dependencies.Count != 0)) { solutionDependencies[FileUtilities.NormalizePath(projectWithDependencies.AbsolutePath)] = projectWithDependencies.Dependencies.Select( dependencyGuid => { // code snippet cloned from SolutionProjectGenerator.AddPropertyGroupForSolutionConfiguration if (!solutionFile.ProjectsByGuid.TryGetValue(dependencyGuid, out var dependencyProject)) { // If it's not itself part of the solution, that's an invalid solution ProjectFileErrorUtilities.VerifyThrowInvalidProjectFile( dependencyProject != null, "SubCategoryForSolutionParsingErrors", new BuildEventFileInfo(solutionFile.FullPath), "SolutionParseProjectDepNotFoundError", projectWithDependencies.ProjectGuid, dependencyGuid); } // Add it to the list of dependencies, but only if it should build in this solution configuration // (If a project is not selected for build in the solution configuration, it won't build even if it's depended on by something that IS selected for build) // .. and only if it's known to be MSBuild format, as projects can't use the information otherwise return(dependencyProject?.ProjectType == SolutionProjectType.KnownToBeMSBuildFormat ? FileUtilities.NormalizePath(dependencyProject.AbsolutePath) : null); }) .Where(p => p != null) .ToArray(); } return(solutionDependencies); } }
/// <summary> /// Used to load information about default MSBuild tasks i.e. tasks that do not need to be explicitly declared in projects /// with the <UsingTask> element. Default task information is read from special files, which are located in the same /// directory as the MSBuild binaries. /// </summary> /// <remarks> /// 1) a default tasks file needs the <Project> root tag in order to be well-formed /// 2) the XML declaration tag <?xml ...> is ignored /// 3) comment tags are always ignored regardless of their placement /// 4) the rest of the tags are expected to be <UsingTask> tags /// </remarks> private void RegisterDefaultTasks(BuildEventContext buildEventContext) { if (!defaultTasksRegistrationAttempted) { try { this.defaultTaskRegistry = new TaskRegistry(); string[] defaultTasksFiles = { }; try { defaultTasksFiles = getFiles(toolset.ToolsPath, defaultTasksFilePattern); if (defaultTasksFiles.Length == 0) { loggingServices.LogWarning(buildEventContext, new BuildEventFileInfo(/* this warning truly does not involve any file */ String.Empty), "DefaultTasksFileLoadFailureWarning", defaultTasksFilePattern, toolset.ToolsPath, String.Empty); } } // handle security problems when finding the default tasks files catch (UnauthorizedAccessException e) { loggingServices.LogWarning(buildEventContext, new BuildEventFileInfo(/* this warning truly does not involve any file */ String.Empty), "DefaultTasksFileLoadFailureWarning", defaultTasksFilePattern, toolset.ToolsPath, e.Message); } // handle problems when reading the default tasks files catch (Exception e) // Catching Exception, but rethrowing unless it's an IO related exception. { if (ExceptionHandling.NotExpectedException(e)) { throw; } loggingServices.LogWarning(buildEventContext, new BuildEventFileInfo(/* this warning truly does not involve any file */ String.Empty), "DefaultTasksFileLoadFailureWarning", defaultTasksFilePattern, toolset.ToolsPath, e.Message); } BuildPropertyGroup propertyBag = null; foreach (string defaultTasksFile in defaultTasksFiles) { try { XmlDocument defaultTasks = loadXmlFromPath(defaultTasksFile); // look for the first root tag that is not a comment or an XML declaration -- this should be the <Project> tag // NOTE: the XML parser will guarantee there is only one real root element in the file // but we need to find it amongst the other types of XmlNode at the root. foreach (XmlNode topLevelNode in defaultTasks.ChildNodes) { if (XmlUtilities.IsXmlRootElement(topLevelNode)) { ProjectErrorUtilities.VerifyThrowInvalidProject(topLevelNode.LocalName == XMakeElements.project, topLevelNode, "UnrecognizedElement", topLevelNode.Name); ProjectErrorUtilities.VerifyThrowInvalidProject((topLevelNode.Prefix.Length == 0) && (String.Equals(topLevelNode.NamespaceURI, XMakeAttributes.defaultXmlNamespace, StringComparison.OrdinalIgnoreCase)), topLevelNode, "ProjectMustBeInMSBuildXmlNamespace", XMakeAttributes.defaultXmlNamespace); // the <Project> tag can only the XML namespace -- no other attributes foreach (XmlAttribute projectAttribute in topLevelNode.Attributes) { ProjectXmlUtilities.VerifyThrowProjectInvalidAttribute(projectAttribute.Name == XMakeAttributes.xmlns, projectAttribute); } // look at all the child tags of the <Project> root tag we found foreach (XmlNode usingTaskNode in topLevelNode.ChildNodes) { if (usingTaskNode.NodeType != XmlNodeType.Comment) { ProjectErrorUtilities.VerifyThrowInvalidProject(usingTaskNode.Name == XMakeElements.usingTask, usingTaskNode, "UnrecognizedElement", usingTaskNode.Name); // Initialize the property bag if it hasn't been already. if (propertyBag == null) { // Set the value of the MSBuildBinPath/ToolsPath properties. BuildPropertyGroup reservedPropertyBag = new BuildPropertyGroup(); reservedPropertyBag.SetProperty( new BuildProperty(ReservedPropertyNames.binPath, EscapingUtilities.Escape(toolset.ToolsPath), PropertyType.ReservedProperty)); reservedPropertyBag.SetProperty( new BuildProperty(ReservedPropertyNames.toolsPath, EscapingUtilities.Escape(toolset.ToolsPath), PropertyType.ReservedProperty)); // Also set MSBuildAssemblyVersion so that the tasks file can tell between v4 and v12 MSBuild reservedPropertyBag.SetProperty( new BuildProperty(ReservedPropertyNames.assemblyVersion, Constants.AssemblyVersion, PropertyType.ReservedProperty)); propertyBag = new BuildPropertyGroup(); propertyBag.ImportInitialProperties(parentEngine.EnvironmentProperties, reservedPropertyBag, BuildProperties, parentEngine.GlobalProperties); } defaultTaskRegistry.RegisterTask(new UsingTask((XmlElement)usingTaskNode, true), new Expander(propertyBag), loggingServices, buildEventContext); } } break; } } } // handle security problems when loading the default tasks file catch (UnauthorizedAccessException e) { loggingServices.LogError(buildEventContext, new BuildEventFileInfo(defaultTasksFile), "DefaultTasksFileFailure", e.Message); break; } // handle problems when loading the default tasks file catch (IOException e) { loggingServices.LogError(buildEventContext, new BuildEventFileInfo(defaultTasksFile), "DefaultTasksFileFailure", e.Message); break; } // handle XML errors in the default tasks file catch (XmlException e) { ProjectFileErrorUtilities.VerifyThrowInvalidProjectFile(false, new BuildEventFileInfo(e), "DefaultTasksFileFailure", e.Message); } } } finally { defaultTasksRegistrationAttempted = true; } } }
/// <summary> /// Validates a project against the given schema -- if no schema is provided, uses the default schema. /// </summary> /// <owner>JomoF</owner> /// <param name="contentReader"></param> /// <param name="schemaFile">Can be null.</param> /// <param name="projectFile"></param> private void VerifyProjectSchema ( TextReader contentReader, string schemaFile, string projectFile ) { // Options for XmlReader object can be set only in constructor. After the object is created, they // become read-only. Because of that we need to create // XmlSettings structure, fill it in with correct parameters and pass into XmlReader constructor. XmlReaderSettings validatorSettings = new XmlReaderSettings(); validatorSettings.ValidationType = ValidationType.Schema; validatorSettings.XmlResolver = null; validatorSettings.ValidationEventHandler += this.OnSchemaValidationError; if (string.IsNullOrEmpty(schemaFile)) { schemaFile = Path.Combine(binPath, "Microsoft.Build.xsd"); } // Log the schema file we're using, particularly since it can vary // according to the toolset being used engineLoggingServices.LogComment(buildEventContext, "SchemaFileLocation", schemaFile); XmlTextReader schemaReader = new XmlTextReader(schemaFile); schemaReader.DtdProcessing = DtdProcessing.Ignore; using (schemaReader) { try { validatorSettings.Schemas.Add(XMakeAttributes.defaultXmlNamespace, schemaReader); // We need full path to the project file to be able handle it as URI in ValidationEventHandler. // Uri class cannot instantiate with relative paths. if (projectFile.Length != 0) { projectFile = Path.GetFullPath(projectFile); } using (XmlReader validator = XmlReader.Create(contentReader, validatorSettings, projectFile)) // May also throw XmlSchemaException { this.syntaxError = false; bool couldRead = true; while (couldRead) { try { couldRead = validator.Read(); } catch (XmlException) { // We swallow exception here because XmlValidator fires the validation event to report the error // And we handle the event. Also XmlValidator can continue parsing Xml text after throwing an exception. // Thus we don't need any special recover here. } } ProjectFileErrorUtilities.VerifyThrowInvalidProjectFile(!this.syntaxError, "SubCategoryForSchemaValidationErrors", new BuildEventFileInfo(projectFile), "ProjectSchemaErrorHalt"); } } // handle errors in the schema itself catch (XmlException e) { ProjectFileErrorUtilities.VerifyThrowInvalidProjectFile(false, "SubCategoryForSchemaValidationErrors", new BuildEventFileInfo(e), "InvalidSchemaFile", schemaFile, e.Message); } // handle errors in the schema itself catch (XmlSchemaException e) { ProjectFileErrorUtilities.VerifyThrowInvalidProjectFile(false, "SubCategoryForSchemaValidationErrors", new BuildEventFileInfo(e), "InvalidSchemaFile", schemaFile, e.Message); } } }