| File: Classification\DataClassificationTypeConverter.cs | Web Access |
| Project: src\src\Libraries\Microsoft.Extensions.Compliance.Abstractions\Microsoft.Extensions.Compliance.Abstractions.csproj (Microsoft.Extensions.Compliance.Abstractions) |
// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. using System; using System.ComponentModel; using System.Diagnostics.CodeAnalysis; using System.Globalization; using Microsoft.Shared.DiagnosticIds; namespace Microsoft.Extensions.Compliance.Classification; /// <summary> /// Provides a way to convert a <see cref="DataClassification"/> to and from a string. /// </summary> [Experimental(DiagnosticIds.Experiments.Compliance, UrlFormat = DiagnosticIds.UrlFormat)] public class DataClassificationTypeConverter : TypeConverter { private const char Delimiter = ':'; /// <inheritdoc/> public override bool CanConvertFrom(ITypeDescriptorContext? context, Type sourceType) { return sourceType == typeof(string); } /// <inheritdoc/> public override bool CanConvertTo(ITypeDescriptorContext? context, Type? destinationType) { return destinationType == typeof(DataClassification); } /// <inheritdoc/> [SuppressMessage("Performance", "LA0001:Use the 'Microsoft.Shared.Diagnostics.Throws' class instead of explicitly throwing exception for improved performance", Justification = "Using the Throws class causes static analysis to incorrectly assume that code after the throw is reachable.")] public override object? ConvertFrom(ITypeDescriptorContext? context, CultureInfo? culture, object value) { if (value is not string stringValue) { throw new ArgumentException("Value must be a string.", nameof(value)); } if (stringValue == nameof(DataClassification.None)) { return DataClassification.None; } if (stringValue == nameof(DataClassification.Unknown)) { return DataClassification.Unknown; } if (TryParse(stringValue, out var taxonomyName, out var taxonomyValue)) { return new DataClassification(taxonomyName, taxonomyValue); } throw new FormatException($"Invalid data classification format: '{stringValue}'."); } /// <inheritdoc/> public override bool IsValid(ITypeDescriptorContext? context, object? value) { if (value is not string stringValue) { return false; } if (stringValue == nameof(DataClassification.None) || stringValue == nameof(DataClassification.Unknown)) { return true; } return TryParse(stringValue, out var taxonomyName, out var taxonomyValue); } /// <summary> /// Attempts to parse a string in the format "TaxonomyName:Value". /// </summary> /// <param name="value">The input string to parse.</param> /// <param name="taxonomyName">When this method returns, contains the parsed taxonomy name if the parsing succeeded, or an empty string if it failed.</param> /// <param name="taxonomyValue">When this method returns, contains the parsed taxonomy value if the parsing succeeded, or the original input string if it failed.</param> /// <returns><see langword="true"/> if the string was successfully parsed; otherwise, <see langword="false"/>.</returns> private static bool TryParse(string value, out string taxonomyName, out string taxonomyValue) { taxonomyName = string.Empty; taxonomyValue = value; if (value.Length <= 1) { return false; } ReadOnlySpan<char> valueSpan = value.AsSpan(); int index = valueSpan.IndexOf(Delimiter); if (index <= 0 || index >= (value.Length - 1)) { return false; } taxonomyName = valueSpan.Slice(0, index).ToString(); taxonomyValue = valueSpan.Slice(index + 1).ToString(); return true; } }