what transaction read pricing microsoft kind from common are c# .net azure encoding azure-storage

c# - read - table storage transaction



¿Cómo puedo codificar las claves de fila de la tabla de almacenamiento de Azure y las claves de partición? (6)

Estoy usando tablas de almacenamiento de Azure y tengo datos que van a la RowKey que tiene barras. De acuerdo con esta página de MSDN , los siguientes caracteres no están permitidos en PartitionKey y RowKey:

  • El carácter de barra diagonal (/)

  • El carácter de barra invertida ()

  • El caracter del signo numérico (#)

  • El carácter de interrogación (?)

  • Controle los caracteres de U + 0000 a U + 001F, que incluyen:

  • El carácter de tabulación horizontal (/ t)

  • El carácter de salto de línea (/ n)

  • El carácter de retorno de carro (/ r)

  • Controle los caracteres de U + 007F a U + 009F

He visto a algunas personas usar codificación URL para evitar esto. Desafortunadamente, hay algunas fallas técnicas que pueden surgir de esto, como poder insertar pero no eliminar ciertas entidades. También he visto que algunas personas usan codificación base64, sin embargo, esto también puede contener caracteres no permitidos.

¿Cómo puedo codificar RowKey de manera eficiente sin tener que ejecutar los caracteres no permitidos o transferir mi propia codificación?


Si solo son las barras, simplemente puede reemplazarlas al escribir en la tabla con otro personaje, por ejemplo, ''|'' y volver a reemplazarlos en la lectura.


Cuando una URL está codificada en Base64, el único carácter que no es válido en una columna de clave de Azure Table Storage es la barra inclinada (''/''). Para solucionar esto, simplemente reemplace el carácter de barra inclinada con otro carácter que sea (1) válido en una columna de clave de Almacenamiento de tabla de Azure y (2) no un carácter de Base64. El ejemplo más común que he encontrado (que se cita en otras respuestas) es reemplazar la barra inclinada (''/'') con el guión bajo (''_'').

private static String EncodeUrlInKey(String url) { var keyBytes = System.Text.Encoding.UTF8.GetBytes(url); var base64 = System.Convert.ToBase64String(keyBytes); return base64.Replace(''/'',''_''); }

Al decodificar, simplemente deshaga el carácter reemplazado (¡primero!) Y luego Base64 decodifique la cadena resultante. Eso es todo al respecto.

private static String DecodeUrlInKey(String encodedKey) { var base64 = encodedKey.Replace(''_'', ''/''); byte[] bytes = System.Convert.FromBase64String(base64); return System.Text.Encoding.UTF8.GetString(bytes); }

Algunas personas han sugerido que otros personajes de Base64 también necesitan codificación. Según los documentos de Azure Table Storage, este no es el caso.


Me encontré con la misma necesidad.

No estaba satisfecho con la codificación Base64 porque convierte una cadena legible por humanos en una cadena irreconocible e inflará el tamaño de las cadenas independientemente de si siguen las reglas (una pérdida cuando la gran mayoría de los caracteres no son caracteres ilegales que necesitan escaparse).

Aquí hay un codificador / decodificador que usa ''!'' como un personaje de escape de la misma manera que uno tradicionalmente usaría el carácter de barra diagonal inversa.

public static class TableKeyEncoding { // https://msdn.microsoft.com/library/azure/dd179338.aspx // // The following characters are not allowed in values for the PartitionKey and RowKey properties: // The forward slash(/) character // The backslash(/) character // The number sign(#) character // The question mark (?) character // Control characters from U+0000 to U+001F, including: // The horizontal tab(/t) character // The linefeed(/n) character // The carriage return (/r) character // Control characters from U+007F to U+009F public static string Encode(string unsafeForUseAsAKey) { StringBuilder safe = new StringBuilder(); foreach (char c in unsafeForUseAsAKey) { switch (c) { case ''/'': safe.Append("!f"); break; case ''//': safe.Append("!b"); break; case ''#'': safe.Append("!p"); break; case ''?'': safe.Append("!q"); break; case ''/t'': safe.Append("!t"); break; case ''/n'': safe.Append("!n"); break; case ''/r'': safe.Append("!r"); break; case ''!'': safe.Append("!!"); break; default: if (c <= 0x1f || (c >= 0x7f && c <= 0x9f)) { int charCode = c; safe.Append("!x" + charCode.ToString("x2")); } else { safe.Append(c); } break; } } return safe.ToString(); } public static string Decode(string key) { StringBuilder decoded = new StringBuilder(); int i = 0; while (i < key.Length) { char c = key[i++]; if (c != ''!'' || i == key.Length) { // There''s no escape character (''!''), or the escape should be ignored because it''s the end of the array decoded.Append(c); } else { char escapeCode = key[i++]; switch (escapeCode) { case ''f'': decoded.Append(''/''); break; case ''b'': decoded.Append(''//'); break; case ''p'': decoded.Append(''#''); break; case ''q'': decoded.Append(''?''); break; case ''t'': decoded.Append(''/t''); break; case ''n'': decoded.Append("/n"); break; case ''r'': decoded.Append("/r"); break; case ''!'': decoded.Append(''!''); break; case ''x'': if (i + 2 <= key.Length) { string charCodeString = key.Substring(i, 2); int charCode; if (int.TryParse(charCodeString, NumberStyles.HexNumber, NumberFormatInfo.InvariantInfo, out charCode)) { decoded.Append((char)charCode); } i += 2; } break; default: decoded.Append(''!''); break; } } } return decoded.ToString(); } }

Ya que uno debe tener extrema precaución al escribir su propio codificador, he escrito algunas pruebas de unidad también.

using Xunit; namespace xUnit_Tests { public class TableKeyEncodingTests { const char Unicode0X1A = (char) 0x1a; public void RoundTripTest(string unencoded, string encoded) { Assert.Equal(encoded, TableKeyEncoding.Encode(unencoded)); Assert.Equal(unencoded, TableKeyEncoding.Decode(encoded)); } [Fact] public void RoundTrips() { RoundTripTest("!/n", "!!!n"); RoundTripTest("left" + Unicode0X1A + "right", "left!x1aright"); } // The following characters are not allowed in values for the PartitionKey and RowKey properties: // The forward slash(/) character // The backslash(/) character // The number sign(#) character // The question mark (?) character // Control characters from U+0000 to U+001F, including: // The horizontal tab(/t) character // The linefeed(/n) character // The carriage return (/r) character // Control characters from U+007F to U+009F [Fact] void EncodesAllForbiddenCharacters() { List<char> forbiddenCharacters = "///#?/t/n/r".ToCharArray().ToList(); forbiddenCharacters.AddRange(Enumerable.Range(0x00, 1+(0x1f-0x00)).Select(i => (char)i)); forbiddenCharacters.AddRange(Enumerable.Range(0x7f, 1+(0x9f-0x7f)).Select(i => (char)i)); string allForbiddenCharacters = String.Join("", forbiddenCharacters); string allForbiddenCharactersEncoded = TableKeyEncoding.Encode(allForbiddenCharacters); // Make sure decoding is same as encoding Assert.Equal(allForbiddenCharacters, TableKeyEncoding.Decode(allForbiddenCharactersEncoded)); // Ensure encoding does not contain any forbidden characters Assert.Equal(0, allForbiddenCharacters.Count( c => allForbiddenCharactersEncoded.Contains(c) )); } } }


¿Qué hay de las funciones de codificación / decodificación URL? Se ocupa de ''/'' , ''?'' y ''#'' personajes.

string url = "http://www.google.com/search?q=Example"; string key = HttpUtility.UrlEncode(url); string urlBack = HttpUtility.UrlDecode(key);


Lo que he visto es que, aunque técnicamente se permiten muchos caracteres no alfanuméricos, en realidad no funciona muy bien como partición y clave de fila.

Miré las answears ya dadas aquí y en otros lugares y escribí esto: https://github.com/JohanNorberg/AlphaNumeric

Dos codificadores alfanuméricos.

Si necesita escapar una cadena que es principalmente alfanumérica, puede usar esto:

AlphaNumeric.English.Encode(str);

Si necesita escapar de una cadena que no es alfanumérica, puede usar esto:

AlphaNumeric.Data.EncodeString(str);

Codificación de datos:

var base64 = Convert.ToBase64String(bytes); var alphaNumericEncodedString = base64 .Replace("0", "01") .Replace("+", "02") .Replace("/", "03") .Replace("=", "04");

Pero, si desea utilizar, por ejemplo, una dirección de correo electrónico como una hilera de teclas, solo querría escapar de ''@'' y ''.''. Este código hará eso:

char[] validChars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ3456789".ToCharArray(); char[] allChars = rawString.ToCharArray(); StringBuilder builder = new StringBuilder(rawString.Length * 2); for(int i = 0; i < allChars.Length; i++) { int c = allChars[i]; if((c >= 51 && c <= 57) || (c >= 65 && c <= 90) || (c >= 97 && c <= 122)) { builder.Append(allChars[i]); } else { int index = builder.Length; int count = 0; do { builder.Append(validChars[c % 59]); c /= 59; count++; } while (c > 0); if (count == 1) builder.Insert(index, ''0''); else if (count == 2) builder.Insert(index, ''1''); else if (count == 3) builder.Insert(index, ''2''); else throw new Exception("Base59 has invalid count, method must be wrong Count is: " + count); } } return builder.ToString();


vea estos enlaces http://tools.ietf.org/html/rfc4648#page-7 Código para decodificar / codificar una URL base64 modificada (vea también la segunda respuesta: https://.com/a/1789179/1094268 )

Yo tuve el problema yo mismo. Estas son mis propias funciones que uso para esto ahora. Utilizo el truco en la segunda respuesta que mencioné, así como cambiar los + y / que son incompatibles con las teclas azules que aún pueden aparecer.

private static String EncodeSafeBase64(String toEncode) { if (toEncode == null) throw new ArgumentNullException("toEncode"); String base64String = Convert.ToBase64String(Encoding.UTF8.GetBytes(toEncode)); StringBuilder safe = new StringBuilder(); foreach (Char c in base64String) { switch (c) { case ''+'': safe.Append(''-''); break; case ''/'': safe.Append(''_''); break; default: safe.Append(c); break; } } return safe.ToString(); } private static String DecodeSafeBase64(String toDecode) { if (toDecode == null) throw new ArgumentNullException("toDecode"); StringBuilder deSafe = new StringBuilder(); foreach (Char c in toDecode) { switch (c) { case ''-'': deSafe.Append(''+''); break; case ''_'': deSafe.Append(''/''); break; default: deSafe.Append(c); break; } } return Encoding.UTF8.GetString(Convert.FromBase64String(deSafe.ToString())); }