# Azure Storage Queues Name Sanitization Queue name sanitization is not done by default for NServiceBus.Azure.Transports.WindowsAzureStorageQueues version 8.0 or NServiceBus.Azure.Transports.AzureStorageQueues versions 9 and up. ## Azure Storage Queues naming rules Sanitization is necessary if queue names do not adhere to the following rules: 1. A queue name can only contain letters, numbers, and the dash (`-`) character. 1. The first and last letters in the queue name must be alphanumeric. 1. Consecutive dash characters are not permitted in the queue name. 1. All letters in a queue name must be lowercase. 1. A queue name must be between 3 and 63 characters long. ## Queue name sanitization To sanitize queue names, a sanitization function containing the required logic can be registered. ```cs var transport = new AzureStorageQueueTransport("connection string") { QueueNameSanitizer = queueName => queueName.Replace('.', '-') }; endpointConfiguration.UseTransport(transport); ``` When an endpoint is started, the sanitizer function will be invoked for each queue the transport creates. ## Backward compatibility with versions 7 and below To remain compatible with queues created by versions 7 and below of the transport, be sure to configure queues created by versions 8 and above with the same rules. The following custom code will ensure queues are sanitized in a backward-compatible manner. ```cs var transport = new AzureStorageQueueTransport("connection string") { QueueNameSanitizer = BackwardsCompatibleQueueNameSanitizer.WithMd5Shortener }; endpointConfiguration.UseTransport(transport); ``` Sanitization code for MD5 and SHA1: ```cs public static class BackwardsCompatibleQueueNameSanitizer { public static string WithMd5Shortener(string queueName) { return Sanitize(queueName, useMd5Hashing: true); } public static string WithSha1Shortener(string queueName) { return Sanitize(queueName, useMd5Hashing: false); } static string Sanitize(string queueName, bool useMd5Hashing = true) { var queueNameInLowerCase = queueName.ToLowerInvariant(); return ShortenQueueNameIfNecessary(SanitizeQueueName(queueNameInLowerCase), useMd5Hashing); } static string ShortenQueueNameIfNecessary(string sanitizedQueueName, bool useMd5Hashing) { if (sanitizedQueueName.Length <= 63) { return sanitizedQueueName; } var shortenedName = useMd5Hashing ? ShortenWithMd5(sanitizedQueueName) : ShortenWithSha1(sanitizedQueueName); return $"{sanitizedQueueName.Substring(0, 63 - shortenedName.Length - 1).Trim('-')}-{shortenedName}"; } static string SanitizeQueueName(string queueName) { // this can lead to multiple '-' occurrences in a row var sanitized = invalidCharacters.Replace(queueName, "-"); return multipleDashes.Replace(sanitized, "-"); } static string ShortenWithMd5(string test) { //use MD5 hash to get a 16-byte hash of the string using (var provider = MD5.Create()) { var inputBytes = Encoding.Default.GetBytes(test); var hashBytes = provider.ComputeHash(inputBytes); //generate a GUID from the hash: return new Guid(hashBytes).ToString(); } } static string ShortenWithSha1(string queueName) { using (var provider = SHA1.Create()) { var inputBytes = Encoding.Default.GetBytes(queueName); var hashBytes = provider.ComputeHash(inputBytes); return ToChars(hashBytes); } } static string ToChars(byte[] hashBytes) { var chars = new char[hashBytes.Length * 2]; for (var i = 0; i < chars.Length; i += 2) { var byteIndex = i / 2; chars[i] = HexToChar((byte)(hashBytes[byteIndex] >> 4)); chars[i + 1] = HexToChar(hashBytes[byteIndex]); } return new string(chars); } static char HexToChar(byte a) { a &= 15; return a > 9 ? (char)(a - 10 + 97) : (char)(a + 48); } static Regex invalidCharacters = new Regex(@"[^a-z0-9\-]", RegexOptions.Compiled); static Regex multipleDashes = new Regex(@"\-+", RegexOptions.Compiled); } ``` ## Future consideration prior to using sanitization When implementing custom sanitization, consider factors such as readability and discover-ability. Things to consider: * Truncated long queue names could conflict. * Hashed queue names could lead to difficult names to use during production troubleshooting or debugging. * Sanitized queue names stay in the system and cannot be replaced until no longer used. Possible way to avoid sanitization is to define endpoint name short and meaningful.