diff --git a/src/Microsoft.VisualStudio.SolutionPersistence/Model/ProjectTypeTable.cs b/src/Microsoft.VisualStudio.SolutionPersistence/Model/ProjectTypeTable.cs index 782e72e..8681e20 100644 --- a/src/Microsoft.VisualStudio.SolutionPersistence/Model/ProjectTypeTable.cs +++ b/src/Microsoft.VisualStudio.SolutionPersistence/Model/ProjectTypeTable.cs @@ -41,7 +41,7 @@ private ProjectTypeTable(bool isBuiltIn, List projectTypes) !this.fromExtension.TryAdd(GetExtension(type.Extension), type)) { string projectType = type.GetDisplayName(); - throw new SolutionException(string.Format(Errors.DuplicateExtension_Args2, type.Extension, projectType)); + throw new SolutionException(string.Format(Errors.DuplicateExtension_Args2, type.Extension, projectType), SolutionErrorType.DuplicateExtension); } if (!type.Name.IsNullOrEmpty()) @@ -49,14 +49,14 @@ private ProjectTypeTable(bool isBuiltIn, List projectTypes) if (!this.fromName.TryAdd(type.Name, type)) { string projectType = type.GetDisplayName(); - throw new SolutionException(string.Format(Errors.DuplicateName_Args2, type.Name, projectType)); + throw new SolutionException(string.Format(Errors.DuplicateName_Args2, type.Name, projectType), SolutionErrorType.DuplicateName); } // If a name isn't provided, it is just to map an extension to a project type. if (type.ProjectTypeId != Guid.Empty && !this.fromProjectTypeId.TryAdd(type.ProjectTypeId, type)) { string projectType = type.GetDisplayName(); - throw new SolutionException(string.Format(Errors.DuplicateProjectTypeId_Args2, type.ProjectTypeId, projectType)); + throw new SolutionException(string.Format(Errors.DuplicateProjectTypeId_Args2, type.ProjectTypeId, projectType), SolutionErrorType.DuplicateProjectTypeId); } } @@ -64,7 +64,7 @@ private ProjectTypeTable(bool isBuiltIn, List projectTypes) { if (this.defaultRules is not null) { - throw new SolutionException(Errors.DuplicateDefaultProjectType); + throw new SolutionException(Errors.DuplicateDefaultProjectType, SolutionErrorType.DuplicateDefaultProjectType); } this.defaultRules ??= type.ConfigurationRules; @@ -77,7 +77,7 @@ private ProjectTypeTable(bool isBuiltIn, List projectTypes) { if (this.GetBasedOnType(type) is null) { - throw new SolutionException(string.Format(Errors.InvalidProjectTypeReference_Args1, type.BasedOn)); + throw new SolutionException(string.Format(Errors.InvalidProjectTypeReference_Args1, type.BasedOn), SolutionErrorType.InvalidProjectTypeReference); } // Check for loops in the BasedOn chain using Floyd's cycle-finding algorithm. @@ -88,7 +88,7 @@ private ProjectTypeTable(bool isBuiltIn, List projectTypes) if (object.ReferenceEquals(currentSlow, currentFast)) { string projectType = type.GetDisplayName(); - throw new SolutionException(string.Format(Errors.InvalidLoop_Args1, projectType)); + throw new SolutionException(string.Format(Errors.InvalidLoop_Args1, projectType), SolutionErrorType.InvalidLoop); } currentSlow = this.GetBasedOnType(currentSlow); diff --git a/src/Microsoft.VisualStudio.SolutionPersistence/Model/SolutionArgumentException.cs b/src/Microsoft.VisualStudio.SolutionPersistence/Model/SolutionArgumentException.cs new file mode 100644 index 0000000..fa8d5fb --- /dev/null +++ b/src/Microsoft.VisualStudio.SolutionPersistence/Model/SolutionArgumentException.cs @@ -0,0 +1,35 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System; + +namespace Microsoft.VisualStudio.SolutionPersistence.Model; + +public class SolutionArgumentException : ArgumentException +{ + public readonly SolutionErrorType Type; + + public SolutionArgumentException(string? message, SolutionErrorType type) + : base(message) + { + this.Type = type; + } + + public SolutionArgumentException(string? message, Exception? innerException, SolutionErrorType type) + : base(message, innerException) + { + this.Type = type; + } + + public SolutionArgumentException(string? message, string? paramName, SolutionErrorType type) + : base(message, paramName) + { + this.Type = type; + } + + public SolutionArgumentException(string? message, string? paramName, Exception? innerException, SolutionErrorType type) + : base(message, paramName, innerException) + { + this.Type = type; + } +} diff --git a/src/Microsoft.VisualStudio.SolutionPersistence/Model/SolutionErrorType.cs b/src/Microsoft.VisualStudio.SolutionPersistence/Model/SolutionErrorType.cs new file mode 100644 index 0000000..a532db0 --- /dev/null +++ b/src/Microsoft.VisualStudio.SolutionPersistence/Model/SolutionErrorType.cs @@ -0,0 +1,35 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace Microsoft.VisualStudio.SolutionPersistence.Model; + +/// +/// Reasons the SolutionArgumentException was raised. +/// +public enum SolutionErrorType +{ + Undefined, + CannotMoveFolderToChildFolder, + DuplicateDefaultProjectType, + DuplicateExtension, + DuplicateItemRef, + DuplicateName, + DuplicateProjectName, + DuplicateProjectPath, + DuplicateProjectTypeId, + InvalidConfiguration, + InvalidEncoding, + InvalidFolderPath, + InvalidFolderReference, + InvalidItemRef, + InvalidLoop, + InvalidModelItem, + InvalidName, + InvalidProjectReference, + InvalidProjectTypeReference, + InvalidVersion, + MissingProjectValue, + NotSolution, + UnsupportedVersion, + InvalidXmlDecoratorElementName +} diff --git a/src/Microsoft.VisualStudio.SolutionPersistence/Model/SolutionException.cs b/src/Microsoft.VisualStudio.SolutionPersistence/Model/SolutionException.cs index 767eb8d..e33b967 100644 --- a/src/Microsoft.VisualStudio.SolutionPersistence/Model/SolutionException.cs +++ b/src/Microsoft.VisualStudio.SolutionPersistence/Model/SolutionException.cs @@ -23,9 +23,11 @@ public SolutionException() /// Initializes a new instance of the class. /// /// The error message that explains the reason for the exception. - public SolutionException(string message) + /// The type of error associated to this exception. + public SolutionException(string message, SolutionErrorType errorType = SolutionErrorType.Undefined) : base(message) { + this.ErrorType = errorType; } /// @@ -33,9 +35,11 @@ public SolutionException(string message) /// /// The error message that explains the reason for the exception. /// The exception that is the cause of the current exception. - public SolutionException(string message, Exception inner) + /// The type of error associated to this exception. + public SolutionException(string message, Exception inner, SolutionErrorType errorType = SolutionErrorType.Undefined) : base(message, inner) { + this.ErrorType = errorType; } #if NETFRAMEWORK @@ -57,6 +61,11 @@ protected SolutionException(System.Runtime.Serialization.SerializationInfo info, } #endif + /// + /// Gets error type. + /// + public SolutionErrorType? ErrorType { get; init; } + /// /// Gets file the error occurred in if known. /// @@ -84,19 +93,19 @@ public override void GetObjectData(System.Runtime.Serialization.SerializationInf } #endif - internal static SolutionException Create(string message, XmlDecorator location) + internal static SolutionException Create(string message, XmlDecorator location, SolutionErrorType errorType = SolutionErrorType.Undefined) { return location?.XmlElement is IXmlLineInfo lineInfo && lineInfo.HasLineInfo() ? - new SolutionException(message) { Line = lineInfo.LineNumber, Column = lineInfo.LinePosition, File = location.Root.FullPath } : - new SolutionException(message) { File = location?.Root.FullPath }; + new SolutionException(message, errorType) { Line = lineInfo.LineNumber, Column = lineInfo.LinePosition, File = location.Root.FullPath } : + new SolutionException(message, errorType) { File = location?.Root.FullPath }; } - internal static SolutionException Create(Exception innerException, XmlDecorator location, string? message = null) + internal static SolutionException Create(Exception innerException, XmlDecorator location, string? message = null, SolutionErrorType errorType = SolutionErrorType.Undefined) { message ??= innerException.Message; return location?.XmlElement is IXmlLineInfo lineInfo && lineInfo.HasLineInfo() ? - new SolutionException(message, innerException) { Line = lineInfo.LineNumber, Column = lineInfo.LinePosition, File = location.Root.FullPath } : - new SolutionException(message, innerException) { File = location?.Root.FullPath }; + new SolutionException(message, innerException, errorType) { Line = lineInfo.LineNumber, Column = lineInfo.LinePosition, File = location.Root.FullPath } : + new SolutionException(message, innerException, errorType) { File = location?.Root.FullPath }; } // Checks if an exception caught during serialization should be wrapped by a SolutionException to add position information. diff --git a/src/Microsoft.VisualStudio.SolutionPersistence/Model/SolutionFolderModel.cs b/src/Microsoft.VisualStudio.SolutionPersistence/Model/SolutionFolderModel.cs index 0023dcb..541b018 100644 --- a/src/Microsoft.VisualStudio.SolutionPersistence/Model/SolutionFolderModel.cs +++ b/src/Microsoft.VisualStudio.SolutionPersistence/Model/SolutionFolderModel.cs @@ -62,7 +62,7 @@ public string Name string testName = $"{this.Parent?.ItemRef ?? "/"}{value}/"; if (this.Solution.FindFolder(testName) is not null) { - throw new ArgumentException(string.Format(Errors.DuplicateItemRef_Args2, testName, "Folder"), nameof(value)); + throw new SolutionArgumentException(string.Format(Errors.DuplicateItemRef_Args2, testName, "Folder"), nameof(value), SolutionErrorType.DuplicateItemRef); } string oldName = this.name; diff --git a/src/Microsoft.VisualStudio.SolutionPersistence/Model/SolutionItemModel.cs b/src/Microsoft.VisualStudio.SolutionPersistence/Model/SolutionItemModel.cs index c863b9c..fc78e17 100644 --- a/src/Microsoft.VisualStudio.SolutionPersistence/Model/SolutionItemModel.cs +++ b/src/Microsoft.VisualStudio.SolutionPersistence/Model/SolutionItemModel.cs @@ -62,7 +62,7 @@ public Guid Id { if (this.Solution.FindItemById(value) is not null) { - throw new ArgumentException(string.Format(Errors.DuplicateItemRef_Args2, value, this.GetType().Name), nameof(value)); + throw new SolutionArgumentException(string.Format(Errors.DuplicateItemRef_Args2, value, this.GetType().Name), nameof(value), SolutionErrorType.DuplicateItemRef); } Guid? oldId = this.id ?? this.defaultId; @@ -114,7 +114,7 @@ public void MoveToFolder(SolutionFolderModel? folder) { if (ReferenceEquals(parents, this)) { - throw new ArgumentException(Errors.CannotMoveFolderToChildFolder, nameof(folder)); + throw new SolutionArgumentException(Errors.CannotMoveFolderToChildFolder, nameof(folder), SolutionErrorType.CannotMoveFolderToChildFolder); } } diff --git a/src/Microsoft.VisualStudio.SolutionPersistence/Model/SolutionModel.cs b/src/Microsoft.VisualStudio.SolutionPersistence/Model/SolutionModel.cs index 2312e45..acaa31f 100644 --- a/src/Microsoft.VisualStudio.SolutionPersistence/Model/SolutionModel.cs +++ b/src/Microsoft.VisualStudio.SolutionPersistence/Model/SolutionModel.cs @@ -177,7 +177,7 @@ public SolutionFolderModel AddFolder(string path) Argument.ThrowIfNullOrEmpty(path, nameof(path)); if (!path.StartsWith('/') || !path.EndsWith('/')) { - throw new ArgumentException(string.Format(Errors.InvalidFolderPath_Args1, path), nameof(path)); + throw new SolutionArgumentException(string.Format(Errors.InvalidFolderPath_Args1, path), nameof(path), SolutionErrorType.InvalidFolderPath); } SolutionFolderModel? existingFolder = this.FindFolder(path); @@ -213,7 +213,7 @@ public SolutionProjectModel AddProject(string filePath, string? projectTypeName Guid projectTypeId = Guid.TryParse(projectTypeName, out Guid projectTypeGuid) ? projectTypeGuid : this.ProjectTypeTable.GetProjectTypeId(projectTypeName, Path.GetExtension(filePath.AsSpan())) ?? - throw new ArgumentException(string.Format(Errors.InvalidProjectTypeReference_Args1, projectTypeName), nameof(projectTypeName)); + throw new SolutionArgumentException(string.Format(Errors.InvalidProjectTypeReference_Args1, projectTypeName), nameof(projectTypeName), SolutionErrorType.InvalidProjectReference); return this.AddProject(filePath, projectTypeName ?? string.Empty, projectTypeId, folder); } @@ -337,7 +337,7 @@ public bool RemovePlatform(string platform) Argument.ThrowIfNullOrEmpty(path, nameof(path)); if (!path.StartsWith('/') || !path.EndsWith('/')) { - throw new ArgumentException(string.Format(Errors.InvalidFolderPath_Args1, path), nameof(path)); + throw new SolutionArgumentException(string.Format(Errors.InvalidFolderPath_Args1, path), nameof(path), SolutionErrorType.InvalidFolderPath); } return ModelHelper.FindByItemRef(this.solutionFolders, path); @@ -386,13 +386,13 @@ internal static void ValidateName(StringSpan name) { if (char.IsControl(c) || InvalidNameChars.Contains(c)) { - throw new ArgumentException(Errors.InvalidName, nameof(name)); + throw new SolutionArgumentException(Errors.InvalidName, nameof(name), SolutionErrorType.InvalidName); } } if (IsDosWord(name)) { - throw new ArgumentException(Errors.InvalidName, nameof(name)); + throw new SolutionArgumentException(Errors.InvalidName, nameof(name), SolutionErrorType.InvalidName); } static bool IsDosWord(scoped StringSpan name) @@ -491,7 +491,7 @@ internal SolutionProjectModel AddProject(string filePath, string projectTypeName // Project is already in the solution. if (this.FindProject(project.FilePath) is not null) { - throw new ArgumentException(string.Format(Errors.DuplicateProjectPath_Arg1, project.ItemRef), nameof(filePath)); + throw new SolutionArgumentException(string.Format(Errors.DuplicateProjectPath_Arg1, project.ItemRef), nameof(filePath), SolutionErrorType.DuplicateProjectPath); } this.ValidateProjectName(project); @@ -602,7 +602,7 @@ internal void ValidateProjectName(SolutionProjectModel project) if (existingProject.ActualDisplayName.Equals(displayName, StringComparison.OrdinalIgnoreCase)) { - throw new ArgumentException(string.Format(Errors.DuplicateProjectName_Arg1, displayName)); + throw new SolutionArgumentException(string.Format(Errors.DuplicateProjectName_Arg1, displayName), SolutionErrorType.DuplicateProjectName); } } } @@ -611,7 +611,7 @@ internal void ValidateInModel(SolutionItemModel? item) { if (item is not null && item.Solution != this) { - throw new ArgumentException(Errors.InvalidModelItem, nameof(item)); + throw new SolutionArgumentException(Errors.InvalidModelItem, nameof(item), SolutionErrorType.InvalidModelItem); } } diff --git a/src/Microsoft.VisualStudio.SolutionPersistence/Model/SolutionProjectModel.cs b/src/Microsoft.VisualStudio.SolutionPersistence/Model/SolutionProjectModel.cs index 9a52426..9ca0f7d 100644 --- a/src/Microsoft.VisualStudio.SolutionPersistence/Model/SolutionProjectModel.cs +++ b/src/Microsoft.VisualStudio.SolutionPersistence/Model/SolutionProjectModel.cs @@ -99,7 +99,7 @@ public string FilePath { if (this.Solution.FindProject(value) is not null) { - throw new ArgumentException(string.Format(Errors.DuplicateItemRef_Args2, value, "Project"), nameof(value)); + throw new SolutionArgumentException(string.Format(Errors.DuplicateItemRef_Args2, value, "Project"), nameof(value), SolutionErrorType.DuplicateItemRef); } string oldPath = this.filePath!; @@ -211,7 +211,7 @@ public void AddDependency(SolutionProjectModel dependency) if (ReferenceEquals(dependency, this)) { - throw new ArgumentException(string.Format(Errors.InvalidLoop_Args1, dependency.ItemRef), nameof(dependency)); + throw new SolutionArgumentException(string.Format(Errors.InvalidLoop_Args1, dependency.ItemRef), nameof(dependency), SolutionErrorType.InvalidLoop); } this.dependencies ??= []; diff --git a/src/Microsoft.VisualStudio.SolutionPersistence/PublicAPI/PublicAPI.Unshipped.txt b/src/Microsoft.VisualStudio.SolutionPersistence/PublicAPI/PublicAPI.Unshipped.txt index 815c920..21177d6 100644 --- a/src/Microsoft.VisualStudio.SolutionPersistence/PublicAPI/PublicAPI.Unshipped.txt +++ b/src/Microsoft.VisualStudio.SolutionPersistence/PublicAPI/PublicAPI.Unshipped.txt @@ -1 +1,37 @@ -#nullable enable \ No newline at end of file +#nullable enable +Microsoft.VisualStudio.SolutionPersistence.Model.SolutionArgumentException +Microsoft.VisualStudio.SolutionPersistence.Model.SolutionArgumentException.Type -> Microsoft.VisualStudio.SolutionPersistence.Model.SolutionArgumentExceptionType? +Microsoft.VisualStudio.SolutionPersistence.Model.SolutionArgumentExceptionType +Microsoft.VisualStudio.SolutionPersistence.Model.SolutionArgumentExceptionType.CannotMoveFolderToChildFolder = 0 -> Microsoft.VisualStudio.SolutionPersistence.Model.SolutionArgumentExceptionType +Microsoft.VisualStudio.SolutionPersistence.Model.SolutionArgumentExceptionType.DuplicateDefaultProjectType = 1 -> Microsoft.VisualStudio.SolutionPersistence.Model.SolutionArgumentExceptionType +Microsoft.VisualStudio.SolutionPersistence.Model.SolutionArgumentExceptionType.DuplicateExtension = 2 -> Microsoft.VisualStudio.SolutionPersistence.Model.SolutionArgumentExceptionType +Microsoft.VisualStudio.SolutionPersistence.Model.SolutionArgumentExceptionType.DuplicateItemRef = 3 -> Microsoft.VisualStudio.SolutionPersistence.Model.SolutionArgumentExceptionType +Microsoft.VisualStudio.SolutionPersistence.Model.SolutionArgumentExceptionType.DUplicateName = 4 -> Microsoft.VisualStudio.SolutionPersistence.Model.SolutionArgumentExceptionType +Microsoft.VisualStudio.SolutionPersistence.Model.SolutionArgumentExceptionType.DuplicateProjectName = 5 -> Microsoft.VisualStudio.SolutionPersistence.Model.SolutionArgumentExceptionType +Microsoft.VisualStudio.SolutionPersistence.Model.SolutionArgumentExceptionType.DuplicateProjectPath = 6 -> Microsoft.VisualStudio.SolutionPersistence.Model.SolutionArgumentExceptionType +Microsoft.VisualStudio.SolutionPersistence.Model.SolutionArgumentExceptionType.DuplicateProjectTypeId = 7 -> Microsoft.VisualStudio.SolutionPersistence.Model.SolutionArgumentExceptionType +Microsoft.VisualStudio.SolutionPersistence.Model.SolutionArgumentExceptionType.InvalidConfiguration = 8 -> Microsoft.VisualStudio.SolutionPersistence.Model.SolutionArgumentExceptionType +Microsoft.VisualStudio.SolutionPersistence.Model.SolutionArgumentExceptionType.InvalidEncoding = 9 -> Microsoft.VisualStudio.SolutionPersistence.Model.SolutionArgumentExceptionType +Microsoft.VisualStudio.SolutionPersistence.Model.SolutionArgumentExceptionType.InvalidFolderPath = 10 -> Microsoft.VisualStudio.SolutionPersistence.Model.SolutionArgumentExceptionType +Microsoft.VisualStudio.SolutionPersistence.Model.SolutionArgumentExceptionType.InvalidFolderReference = 11 -> Microsoft.VisualStudio.SolutionPersistence.Model.SolutionArgumentExceptionType +Microsoft.VisualStudio.SolutionPersistence.Model.SolutionArgumentExceptionType.InvalidItemRef = 12 -> Microsoft.VisualStudio.SolutionPersistence.Model.SolutionArgumentExceptionType +Microsoft.VisualStudio.SolutionPersistence.Model.SolutionArgumentExceptionType.InvalidLoop = 13 -> Microsoft.VisualStudio.SolutionPersistence.Model.SolutionArgumentExceptionType +Microsoft.VisualStudio.SolutionPersistence.Model.SolutionArgumentExceptionType.InvalidModelItem = 14 -> Microsoft.VisualStudio.SolutionPersistence.Model.SolutionArgumentExceptionType +Microsoft.VisualStudio.SolutionPersistence.Model.SolutionArgumentExceptionType.InvalidName = 15 -> Microsoft.VisualStudio.SolutionPersistence.Model.SolutionArgumentExceptionType +Microsoft.VisualStudio.SolutionPersistence.Model.SolutionArgumentExceptionType.InvalidProjectReference = 16 -> Microsoft.VisualStudio.SolutionPersistence.Model.SolutionArgumentExceptionType +Microsoft.VisualStudio.SolutionPersistence.Model.SolutionArgumentExceptionType.InvalidProjectType = 17 -> Microsoft.VisualStudio.SolutionPersistence.Model.SolutionArgumentExceptionType +Microsoft.VisualStudio.SolutionPersistence.Model.SolutionArgumentExceptionType.InvalidProjectTypeReference = 18 -> Microsoft.VisualStudio.SolutionPersistence.Model.SolutionArgumentExceptionType +Microsoft.VisualStudio.SolutionPersistence.Model.SolutionArgumentExceptionType.InvalidScope = 19 -> Microsoft.VisualStudio.SolutionPersistence.Model.SolutionArgumentExceptionType +Microsoft.VisualStudio.SolutionPersistence.Model.SolutionArgumentExceptionType.InvalidVersion = 20 -> Microsoft.VisualStudio.SolutionPersistence.Model.SolutionArgumentExceptionType +Microsoft.VisualStudio.SolutionPersistence.Model.SolutionArgumentExceptionType.MissingDisplayName = 21 -> Microsoft.VisualStudio.SolutionPersistence.Model.SolutionArgumentExceptionType +Microsoft.VisualStudio.SolutionPersistence.Model.SolutionArgumentExceptionType.MissingPath = 22 -> Microsoft.VisualStudio.SolutionPersistence.Model.SolutionArgumentExceptionType +Microsoft.VisualStudio.SolutionPersistence.Model.SolutionArgumentExceptionType.MissingProjectId = 23 -> Microsoft.VisualStudio.SolutionPersistence.Model.SolutionArgumentExceptionType +Microsoft.VisualStudio.SolutionPersistence.Model.SolutionArgumentExceptionType.MissingProjectValue = 24 -> Microsoft.VisualStudio.SolutionPersistence.Model.SolutionArgumentExceptionType +Microsoft.VisualStudio.SolutionPersistence.Model.SolutionArgumentExceptionType.MissingSectionName = 25 -> Microsoft.VisualStudio.SolutionPersistence.Model.SolutionArgumentExceptionType +Microsoft.VisualStudio.SolutionPersistence.Model.SolutionArgumentExceptionType.NotSolution = 26 -> Microsoft.VisualStudio.SolutionPersistence.Model.SolutionArgumentExceptionType +Microsoft.VisualStudio.SolutionPersistence.Model.SolutionArgumentExceptionType.SyntaxError = 27 -> Microsoft.VisualStudio.SolutionPersistence.Model.SolutionArgumentExceptionType +Microsoft.VisualStudio.SolutionPersistence.Model.SolutionArgumentExceptionType.UnsupportedVersion = 28 -> Microsoft.VisualStudio.SolutionPersistence.Model.SolutionArgumentExceptionType +Microsoft.VisualStudio.SolutionPersistence.Model.SolutionException.ErrorType.get -> Microsoft.VisualStudio.SolutionPersistence.Model.SolutionErrorType? +Microsoft.VisualStudio.SolutionPersistence.Model.SolutionException.ErrorType.init -> void +Microsoft.VisualStudio.SolutionPersistence.Model.SolutionException.SolutionException(string! message, Microsoft.VisualStudio.SolutionPersistence.Model.SolutionErrorType errorType = Microsoft.VisualStudio.SolutionPersistence.Model.SolutionErrorType.Undefined) -> void +Microsoft.VisualStudio.SolutionPersistence.Model.SolutionException.SolutionException(string! message, System.Exception! inner, Microsoft.VisualStudio.SolutionPersistence.Model.SolutionErrorType errorType = Microsoft.VisualStudio.SolutionPersistence.Model.SolutionErrorType.Undefined) -> void \ No newline at end of file diff --git a/src/Microsoft.VisualStudio.SolutionPersistence/Serializer/SlnV12/SlnFileV12Serializer.Reader.cs b/src/Microsoft.VisualStudio.SolutionPersistence/Serializer/SlnV12/SlnFileV12Serializer.Reader.cs index 8637112..a012755 100644 --- a/src/Microsoft.VisualStudio.SolutionPersistence/Serializer/SlnV12/SlnFileV12Serializer.Reader.cs +++ b/src/Microsoft.VisualStudio.SolutionPersistence/Serializer/SlnV12/SlnFileV12Serializer.Reader.cs @@ -63,7 +63,7 @@ internal ValueTask ParseAsync(ISolutionSerializer serializer, str this.lineNumber = 0; if (!this.TryParseFormatLine()) { - throw new SolutionException(Errors.NotSolution) { File = fullPath, Line = this.lineNumber }; + throw new SolutionException(Errors.NotSolution, SolutionErrorType.NotSolution) { File = fullPath, Line = this.lineNumber }; } // Some property bags need to be loaded after all projects have been resolved. @@ -459,7 +459,7 @@ private bool TryParseFormatLine() if (string.IsNullOrEmpty(fileVersionMaj) || !int.TryParse(fileVersionMaj, out int fileVer) || fileVer > CurrentFileVersion) { - throw new SolutionException(string.Format(Errors.UnsupportedVersion_Args1, fileVersionMaj)) { File = fullPath, Line = this.lineNumber }; + throw new SolutionException(string.Format(Errors.UnsupportedVersion_Args1, fileVersionMaj), SolutionErrorType.UnsupportedVersion) { File = fullPath, Line = this.lineNumber }; } return true; diff --git a/src/Microsoft.VisualStudio.SolutionPersistence/Serializer/SlnV12/SlnFileV12Serializer.cs b/src/Microsoft.VisualStudio.SolutionPersistence/Serializer/SlnV12/SlnFileV12Serializer.cs index ec2a49c..da24953 100644 --- a/src/Microsoft.VisualStudio.SolutionPersistence/Serializer/SlnV12/SlnFileV12Serializer.cs +++ b/src/Microsoft.VisualStudio.SolutionPersistence/Serializer/SlnV12/SlnFileV12Serializer.cs @@ -46,7 +46,7 @@ public override ISerializerModelExtension CreateModelExtension(SlnV12SerializerS encoding.CodePage != Encoding.UTF8.CodePage && encoding.CodePage != Encoding.Unicode.CodePage) { - throw new ArgumentException(Errors.InvalidEncoding, nameof(settings)); + throw new SolutionArgumentException(Errors.InvalidEncoding, nameof(settings), SolutionErrorType.InvalidEncoding); } // Make sure ASCII encoding always has exception fallback. diff --git a/src/Microsoft.VisualStudio.SolutionPersistence/Serializer/Xml/XmlDecorators/ItemRefList`1.cs b/src/Microsoft.VisualStudio.SolutionPersistence/Serializer/Xml/XmlDecorators/ItemRefList`1.cs index 6871464..36c75fe 100644 --- a/src/Microsoft.VisualStudio.SolutionPersistence/Serializer/Xml/XmlDecorators/ItemRefList`1.cs +++ b/src/Microsoft.VisualStudio.SolutionPersistence/Serializer/Xml/XmlDecorators/ItemRefList`1.cs @@ -34,14 +34,14 @@ internal readonly void Add(T item) // Missing Name attribute. if (!item.IsValid() || item.ItemRef is null) { - throw SolutionException.Create(string.Format(Errors.InvalidItemRef_Args2, item.ItemRefAttribute, item.ElementName), item); + throw SolutionException.Create(string.Format(Errors.InvalidItemRef_Args2, item.ItemRefAttribute, item.ElementName), item, SolutionErrorType.InvalidItemRef); } else { if (!this.items.TryAdd(item.ItemRef, item)) { // Duplicate Name attribute. - throw SolutionException.Create(string.Format(Errors.DuplicateItemRef_Args2, item.ItemRef, item.ElementName), item); + throw SolutionException.Create(string.Format(Errors.DuplicateItemRef_Args2, item.ItemRef, item.ElementName), item, SolutionErrorType.DuplicateItemRef); } } } diff --git a/src/Microsoft.VisualStudio.SolutionPersistence/Serializer/Xml/XmlDecorators/SlnxFile.cs b/src/Microsoft.VisualStudio.SolutionPersistence/Serializer/Xml/XmlDecorators/SlnxFile.cs index 3e36228..02a1402 100644 --- a/src/Microsoft.VisualStudio.SolutionPersistence/Serializer/Xml/XmlDecorators/SlnxFile.cs +++ b/src/Microsoft.VisualStudio.SolutionPersistence/Serializer/Xml/XmlDecorators/SlnxFile.cs @@ -38,7 +38,7 @@ internal SlnxFile( } else { - throw new SolutionException(Errors.NotSolution) { File = this.FullPath }; + throw new SolutionException(Errors.NotSolution, SolutionErrorType.NotSolution) { File = this.FullPath }; } this.SerializationSettings = this.GetDefaultSerializationSettings(serializationSettings); diff --git a/src/Microsoft.VisualStudio.SolutionPersistence/Serializer/Xml/XmlDecorators/XmlConfiguration.cs b/src/Microsoft.VisualStudio.SolutionPersistence/Serializer/Xml/XmlDecorators/XmlConfiguration.cs index c2a7bfb..8e4e571 100644 --- a/src/Microsoft.VisualStudio.SolutionPersistence/Serializer/Xml/XmlDecorators/XmlConfiguration.cs +++ b/src/Microsoft.VisualStudio.SolutionPersistence/Serializer/Xml/XmlDecorators/XmlConfiguration.cs @@ -48,13 +48,13 @@ internal string Project if (string.IsNullOrEmpty(projectValue)) { - throw SolutionException.Create(Errors.MissingProjectValue, this); + throw SolutionException.Create(Errors.MissingProjectValue, this, SolutionErrorType.MissingProjectValue); } if (!ModelHelper.TrySplitFullConfiguration(this.Root.StringTable, this.Solution, out string? solutionBuildType, out string? solutionPlatform) && !this.Solution.IsNullOrEmpty()) { - throw SolutionException.Create(string.Format(Errors.InvalidConfiguration_Args1, this.Solution), this); + throw SolutionException.Create(string.Format(Errors.InvalidConfiguration_Args1, this.Solution), this, SolutionErrorType.InvalidConfiguration); } if (solutionBuildType is BuildTypeNames.All or null) diff --git a/src/Microsoft.VisualStudio.SolutionPersistence/Serializer/Xml/XmlDecorators/XmlContainer.cs b/src/Microsoft.VisualStudio.SolutionPersistence/Serializer/Xml/XmlDecorators/XmlContainer.cs index 3e07804..6de22d8 100644 --- a/src/Microsoft.VisualStudio.SolutionPersistence/Serializer/Xml/XmlDecorators/XmlContainer.cs +++ b/src/Microsoft.VisualStudio.SolutionPersistence/Serializer/Xml/XmlDecorators/XmlContainer.cs @@ -2,6 +2,7 @@ // Licensed under the MIT license. See LICENSE file in the project root for full license information. using System.Xml; +using Microsoft.VisualStudio.SolutionPersistence.Model; namespace Microsoft.VisualStudio.SolutionPersistence.Serializer.Xml.XmlDecorators; @@ -66,7 +67,7 @@ internal override void UpdateFromXml() if (validateItemRef && !xmlDecorator.IsValid()) { - throw new ArgumentException(string.Format(Errors.InvalidItemRef_Args2, itemRef, xmlDecorator.ElementName)); + throw new SolutionArgumentException(string.Format(Errors.InvalidItemRef_Args2, itemRef, xmlDecorator.ElementName), SolutionErrorType.InvalidItemRef); } xmlDecorator.UpdateFromXml(); diff --git a/src/Microsoft.VisualStudio.SolutionPersistence/Serializer/Xml/XmlDecorators/XmlDecorator.cs b/src/Microsoft.VisualStudio.SolutionPersistence/Serializer/Xml/XmlDecorators/XmlDecorator.cs index ab2a96a..2ed5eb3 100644 --- a/src/Microsoft.VisualStudio.SolutionPersistence/Serializer/Xml/XmlDecorators/XmlDecorator.cs +++ b/src/Microsoft.VisualStudio.SolutionPersistence/Serializer/Xml/XmlDecorators/XmlDecorator.cs @@ -3,6 +3,7 @@ using System.Diagnostics; using System.Xml; +using Microsoft.VisualStudio.SolutionPersistence.Model; namespace Microsoft.VisualStudio.SolutionPersistence.Serializer.Xml.XmlDecorators; @@ -24,7 +25,7 @@ private protected XmlDecorator(SlnxFile root, XmlElement element, Keyword elemen this.ElementName = elementName; if (this.ElementName != Keywords.ToKeyword(element.Name)) { - throw new ArgumentException($"Expected element name {this.ElementName}, but got {element.Name}"); + throw new SolutionArgumentException($"Expected element name {this.ElementName}, but got {element.Name}", SolutionErrorType.InvalidXmlDecoratorElementName); } } diff --git a/src/Microsoft.VisualStudio.SolutionPersistence/Serializer/Xml/XmlDecorators/XmlProject.cs b/src/Microsoft.VisualStudio.SolutionPersistence/Serializer/Xml/XmlDecorators/XmlProject.cs index 1aeb763..abf40a7 100644 --- a/src/Microsoft.VisualStudio.SolutionPersistence/Serializer/Xml/XmlDecorators/XmlProject.cs +++ b/src/Microsoft.VisualStudio.SolutionPersistence/Serializer/Xml/XmlDecorators/XmlProject.cs @@ -101,7 +101,7 @@ internal SolutionProjectModel AddToModel(SolutionModel solution) } else { - throw SolutionException.Create(string.Format(Errors.InvalidFolderReference_Args1, this.ParentFolder.Name), this); + throw SolutionException.Create(string.Format(Errors.InvalidFolderReference_Args1, this.ParentFolder.Name), this, SolutionErrorType.InvalidFolderReference); } } @@ -152,7 +152,7 @@ internal void AddDependenciesToModel(SolutionModel solution, SolutionProjectMode } else { - throw SolutionException.Create(string.Format(Errors.InvalidProjectReference_Args1, dependencyItemRef), buildDependency); + throw SolutionException.Create(string.Format(Errors.InvalidProjectReference_Args1, dependencyItemRef), buildDependency, SolutionErrorType.InvalidProjectReference); } } } diff --git a/src/Microsoft.VisualStudio.SolutionPersistence/Serializer/Xml/XmlDecorators/XmlSolution.cs b/src/Microsoft.VisualStudio.SolutionPersistence/Serializer/Xml/XmlDecorators/XmlSolution.cs index 275a594..cb998dd 100644 --- a/src/Microsoft.VisualStudio.SolutionPersistence/Serializer/Xml/XmlDecorators/XmlSolution.cs +++ b/src/Microsoft.VisualStudio.SolutionPersistence/Serializer/Xml/XmlDecorators/XmlSolution.cs @@ -96,12 +96,12 @@ internal SolutionModel ToModel() } catch (Exception ex) when (SolutionException.ShouldWrap(ex)) { - throw SolutionException.Create(ex, this, string.Format(Errors.InvalidVersion_Args1, fileVersion)); + throw SolutionException.Create(ex, this, string.Format(Errors.InvalidVersion_Args1, fileVersion), SolutionErrorType.InvalidVersion); } if (this.Root.FileVersion.Major > SlnxFile.CurrentVersion) { - throw SolutionException.Create(string.Format(Errors.UnsupportedVersion_Args1, fileVersion), this); + throw SolutionException.Create(string.Format(Errors.UnsupportedVersion_Args1, fileVersion), this, SolutionErrorType.UnsupportedVersion); } } diff --git a/test/Microsoft.VisualStudio.SolutionPersistence.Tests/Serialization/Folders.cs b/test/Microsoft.VisualStudio.SolutionPersistence.Tests/Serialization/Folders.cs index 9d540a4..810af52 100644 --- a/test/Microsoft.VisualStudio.SolutionPersistence.Tests/Serialization/Folders.cs +++ b/test/Microsoft.VisualStudio.SolutionPersistence.Tests/Serialization/Folders.cs @@ -137,7 +137,7 @@ public void MoveProjectToFolder() Assert.Equal("/This/Is/A/Nested/Folder/", wanderingProject.Parent.ItemRef); // Try moving project to folder with existing project - ArgumentException ex = Assert.Throws(() => wanderingProject.MoveToFolder(folderA)); + ArgumentException ex = Assert.Throws(() => wanderingProject.MoveToFolder(folderA)); Assert.Equal(string.Format(Errors.DuplicateProjectName_Arg1, wanderingProject.ActualDisplayName), ex.Message); Assert.Equal("/This/Is/A/Nested/Folder/", wanderingProject.Parent.ItemRef); @@ -172,7 +172,7 @@ public void MoveFolder() Assert.Equal("/This/Is/A/", folderFolder.Parent.ItemRef); // Try to move folder under itself. - ArgumentException ex = Assert.Throws(() => folderThis.MoveToFolder(folderNested)); + ArgumentException ex = Assert.Throws(() => folderThis.MoveToFolder(folderNested)); Assert.StartsWith(Errors.CannotMoveFolderToChildFolder, ex.Message); } @@ -192,7 +192,7 @@ public void ChangeFolderName() // Try case exact { - ArgumentException ex = Assert.Throws(() => folderB.Name = "A"); + ArgumentException ex = Assert.Throws(() => folderB.Name = "A"); Assert.StartsWith(string.Format(Errors.DuplicateItemRef_Args2, "/A/", "Folder"), ex.Message); Assert.Equal("/B/Nested/Deep/", folderNestedB.Path); @@ -200,7 +200,7 @@ public void ChangeFolderName() // Try case insensitive { - ArgumentException ex = Assert.Throws(() => folderB.Name = "a"); + ArgumentException ex = Assert.Throws(() => folderB.Name = "a"); Assert.StartsWith(string.Format(Errors.DuplicateItemRef_Args2, "/a/", "Folder"), ex.Message); Assert.Equal("/B/Nested/Deep/", folderNestedB.Path); diff --git a/test/Microsoft.VisualStudio.SolutionPersistence.Tests/Serialization/Project.cs b/test/Microsoft.VisualStudio.SolutionPersistence.Tests/Serialization/Project.cs index 4b38af6..d63dc4e 100644 --- a/test/Microsoft.VisualStudio.SolutionPersistence.Tests/Serialization/Project.cs +++ b/test/Microsoft.VisualStudio.SolutionPersistence.Tests/Serialization/Project.cs @@ -28,26 +28,26 @@ public void AddProject() // Verify error if same project is added again. { - Exception ex = Assert.Throws(() => solution.AddProject(projectPath, projectTypeName: null)); + Exception ex = Assert.Throws(() => solution.AddProject(projectPath, projectTypeName: null)); Assert.StartsWith(string.Format(Errors.DuplicateItemRef_Args2, projectPath, "Project"), ex.Message); } // Verify error if same project is added to folder. { - Exception ex = Assert.Throws(() => solution.AddProject(projectPath, projectTypeName: null, folder: folder)); + Exception ex = Assert.Throws(() => solution.AddProject(projectPath, projectTypeName: null, folder: folder)); Assert.StartsWith(string.Format(Errors.DuplicateItemRef_Args2, projectPath, "Project"), ex.Message); } // Verify error if same project is added with different case.. { string projectPathUpper = projectPath.ToUpperInvariant(); - Exception ex = Assert.Throws(() => solution.AddProject(projectPathUpper, projectTypeName: null)); + Exception ex = Assert.Throws(() => solution.AddProject(projectPathUpper, projectTypeName: null)); Assert.StartsWith(string.Format(Errors.DuplicateItemRef_Args2, projectPathUpper, "Project"), ex.Message); } // Try chaging a path to an existing project. { - Exception ex = Assert.Throws(() => anotherProject.FilePath = project.FilePath); + Exception ex = Assert.Throws(() => anotherProject.FilePath = project.FilePath); Assert.StartsWith(string.Format(Errors.DuplicateItemRef_Args2, projectPath, "Project"), ex.Message); } }