Bond_009 преди 5 години
родител
ревизия
016be02cd6

+ 2 - 2
Emby.Server.Implementations/ApplicationHost.cs

@@ -362,7 +362,7 @@ namespace Emby.Server.Implementations
         {
             _configuration = configuration;
 
-            XmlSerializer = new MyXmlSerializer(fileSystem, loggerFactory);
+            XmlSerializer = new MyXmlSerializer();
 
             NetworkManager = networkManager;
             networkManager.LocalSubnetsFn = GetConfiguredLocalSubnets;
@@ -906,7 +906,7 @@ namespace Emby.Server.Implementations
 
             _displayPreferencesRepository.Initialize();
 
-            var userDataRepo = new SqliteUserDataRepository(LoggerFactory, ApplicationPaths);
+            var userDataRepo = new SqliteUserDataRepository(LoggerFactory.CreateLogger<SqliteUserDataRepository>(), ApplicationPaths);
 
             SetStaticProperties();
 

+ 5 - 5
Emby.Server.Implementations/Data/SqliteDisplayPreferencesRepository.cs

@@ -110,8 +110,8 @@ namespace Emby.Server.Implementations.Data
 
             using (var statement = connection.PrepareStatement("replace into userdisplaypreferences (id, userid, client, data) values (@id, @userId, @client, @data)"))
             {
-                statement.TryBind("@id", displayPreferences.Id.ToGuidBlob());
-                statement.TryBind("@userId", userId.ToGuidBlob());
+                statement.TryBind("@id", new Guid(displayPreferences.Id).ToByteArray());
+                statement.TryBind("@userId", userId.ToByteArray());
                 statement.TryBind("@client", client);
                 statement.TryBind("@data", serialized);
 
@@ -170,8 +170,8 @@ namespace Emby.Server.Implementations.Data
             {
                 using (var statement = connection.PrepareStatement("select data from userdisplaypreferences where id = @id and userId=@userId and client=@client"))
                 {
-                    statement.TryBind("@id", guidId.ToGuidBlob());
-                    statement.TryBind("@userId", userId.ToGuidBlob());
+                    statement.TryBind("@id", guidId.ToByteArray());
+                    statement.TryBind("@userId", userId.ToByteArray());
                     statement.TryBind("@client", client);
 
                     foreach (var row in statement.ExecuteQuery())
@@ -200,7 +200,7 @@ namespace Emby.Server.Implementations.Data
             using (var connection = GetConnection(true))
             using (var statement = connection.PrepareStatement("select data from userdisplaypreferences where userId=@userId"))
             {
-                statement.TryBind("@userId", userId.ToGuidBlob());
+                statement.TryBind("@userId", userId.ToByteArray());
 
                 foreach (var row in statement.ExecuteQuery())
                 {

+ 52 - 64
Emby.Server.Implementations/Data/SqliteExtensions.cs

@@ -9,6 +9,47 @@ namespace Emby.Server.Implementations.Data
 {
     public static class SqliteExtensions
     {
+        /// <summary>
+        /// An array of ISO-8601 DateTime formats that we support parsing.
+        /// </summary>
+        private static readonly string[] _datetimeFormats = new string[]
+        {
+            "THHmmssK",
+            "THHmmK",
+            "HH:mm:ss.FFFFFFFK",
+            "HH:mm:ssK",
+            "HH:mmK",
+            "yyyy-MM-dd HH:mm:ss.FFFFFFFK", /* NOTE: UTC default (5). */
+            "yyyy-MM-dd HH:mm:ssK",
+            "yyyy-MM-dd HH:mmK",
+            "yyyy-MM-ddTHH:mm:ss.FFFFFFFK",
+            "yyyy-MM-ddTHH:mmK",
+            "yyyy-MM-ddTHH:mm:ssK",
+            "yyyyMMddHHmmssK",
+            "yyyyMMddHHmmK",
+            "yyyyMMddTHHmmssFFFFFFFK",
+            "THHmmss",
+            "THHmm",
+            "HH:mm:ss.FFFFFFF",
+            "HH:mm:ss",
+            "HH:mm",
+            "yyyy-MM-dd HH:mm:ss.FFFFFFF", /* NOTE: Non-UTC default (19). */
+            "yyyy-MM-dd HH:mm:ss",
+            "yyyy-MM-dd HH:mm",
+            "yyyy-MM-ddTHH:mm:ss.FFFFFFF",
+            "yyyy-MM-ddTHH:mm",
+            "yyyy-MM-ddTHH:mm:ss",
+            "yyyyMMddHHmmss",
+            "yyyyMMddHHmm",
+            "yyyyMMddTHHmmssFFFFFFF",
+            "yyyy-MM-dd",
+            "yyyyMMdd",
+            "yy-MM-dd"
+        };
+
+        private static readonly string _datetimeFormatUtc = _datetimeFormats[5];
+        private static readonly string _datetimeFormatLocal = _datetimeFormats[19];
+
         public static void RunQueries(this SQLiteDatabaseConnection connection, string[] queries)
         {
             if (queries == null)
@@ -22,16 +63,6 @@ namespace Emby.Server.Implementations.Data
             });
         }
 
-        public static byte[] ToGuidBlob(this string str)
-        {
-            return ToGuidBlob(new Guid(str));
-        }
-
-        public static byte[] ToGuidBlob(this Guid guid)
-        {
-            return guid.ToByteArray();
-        }
-
         public static Guid ReadGuidFromBlob(this IResultSetValue result)
         {
             return new Guid(result.ToBlob());
@@ -50,58 +81,16 @@ namespace Emby.Server.Implementations.Data
                     CultureInfo.InvariantCulture);
         }
 
-        private static string GetDateTimeKindFormat(
-           DateTimeKind kind)
-        {
-            return (kind == DateTimeKind.Utc) ? _datetimeFormatUtc : _datetimeFormatLocal;
-        }
-
-        /// <summary>
-        /// An array of ISO-8601 DateTime formats that we support parsing.
-        /// </summary>
-        private static string[] _datetimeFormats = new string[] {
-      "THHmmssK",
-      "THHmmK",
-      "HH:mm:ss.FFFFFFFK",
-      "HH:mm:ssK",
-      "HH:mmK",
-      "yyyy-MM-dd HH:mm:ss.FFFFFFFK", /* NOTE: UTC default (5). */
-      "yyyy-MM-dd HH:mm:ssK",
-      "yyyy-MM-dd HH:mmK",
-      "yyyy-MM-ddTHH:mm:ss.FFFFFFFK",
-      "yyyy-MM-ddTHH:mmK",
-      "yyyy-MM-ddTHH:mm:ssK",
-      "yyyyMMddHHmmssK",
-      "yyyyMMddHHmmK",
-      "yyyyMMddTHHmmssFFFFFFFK",
-      "THHmmss",
-      "THHmm",
-      "HH:mm:ss.FFFFFFF",
-      "HH:mm:ss",
-      "HH:mm",
-      "yyyy-MM-dd HH:mm:ss.FFFFFFF", /* NOTE: Non-UTC default (19). */
-      "yyyy-MM-dd HH:mm:ss",
-      "yyyy-MM-dd HH:mm",
-      "yyyy-MM-ddTHH:mm:ss.FFFFFFF",
-      "yyyy-MM-ddTHH:mm",
-      "yyyy-MM-ddTHH:mm:ss",
-      "yyyyMMddHHmmss",
-      "yyyyMMddHHmm",
-      "yyyyMMddTHHmmssFFFFFFF",
-      "yyyy-MM-dd",
-      "yyyyMMdd",
-      "yy-MM-dd"
-    };
-
-        private static string _datetimeFormatUtc = _datetimeFormats[5];
-        private static string _datetimeFormatLocal = _datetimeFormats[19];
+        private static string GetDateTimeKindFormat(DateTimeKind kind)
+            => (kind == DateTimeKind.Utc) ? _datetimeFormatUtc : _datetimeFormatLocal;
 
         public static DateTime ReadDateTime(this IResultSetValue result)
         {
             var dateText = result.ToString();
 
             return DateTime.ParseExact(
-                dateText, _datetimeFormats,
+                dateText,
+                _datetimeFormats,
                 DateTimeFormatInfo.InvariantInfo,
                 DateTimeStyles.None).ToUniversalTime();
         }
@@ -139,7 +128,10 @@ namespace Emby.Server.Implementations.Data
 
         public static void Attach(SQLiteDatabaseConnection db, string path, string alias)
         {
-            var commandText = string.Format("attach @path as {0};", alias);
+            var commandText = string.Format(
+                CultureInfo.InvariantCulture,
+                "attach @path as {0};",
+                alias);
 
             using (var statement = db.PrepareStatement(commandText))
             {
@@ -186,10 +178,7 @@ namespace Emby.Server.Implementations.Data
         private static void CheckName(string name)
         {
 #if DEBUG
-            //if (!name.IndexOf("@", StringComparison.OrdinalIgnoreCase) != 0)
-            {
-                throw new Exception("Invalid param name: " + name);
-            }
+            throw new ArgumentException("Invalid param name: " + name, nameof(name));
 #endif
         }
 
@@ -264,7 +253,7 @@ namespace Emby.Server.Implementations.Data
         {
             if (statement.BindParameters.TryGetValue(name, out IBindParameter bindParam))
             {
-                bindParam.Bind(value.ToGuidBlob());
+                bindParam.Bind(value.ToByteArray());
             }
             else
             {
@@ -392,8 +381,7 @@ namespace Emby.Server.Implementations.Data
             }
         }
 
-        public static IEnumerable<IReadOnlyList<IResultSetValue>> ExecuteQuery(
-            this IStatement This)
+        public static IEnumerable<IReadOnlyList<IResultSetValue>> ExecuteQuery(this IStatement This)
         {
             while (This.MoveNext())
             {

+ 24 - 21
Emby.Server.Implementations/Data/SqliteItemRepository.cs

@@ -549,7 +549,7 @@ namespace Emby.Server.Implementations.Data
                 {
                     using (var saveImagesStatement = base.PrepareStatement(db, "Update TypedBaseItems set Images=@Images where guid=@Id"))
                     {
-                        saveImagesStatement.TryBind("@Id", item.Id.ToGuidBlob());
+                        saveImagesStatement.TryBind("@Id", item.Id.ToByteArray());
                         saveImagesStatement.TryBind("@Images", SerializeImages(item));
 
                         saveImagesStatement.MoveNext();
@@ -1989,7 +1989,7 @@ namespace Emby.Server.Implementations.Data
                 throw new ArgumentNullException(nameof(chapters));
             }
 
-            var idBlob = id.ToGuidBlob();
+            var idBlob = id.ToByteArray();
 
             using (var connection = GetConnection())
             {
@@ -3768,7 +3768,7 @@ namespace Emby.Server.Implementations.Data
 
                     if (statement != null)
                     {
-                        statement.TryBind(paramName, personId.ToGuidBlob());
+                        statement.TryBind(paramName, personId.ToByteArray());
                     }
                     index++;
                 }
@@ -3979,7 +3979,7 @@ namespace Emby.Server.Implementations.Data
                     clauses.Add("(guid in (select itemid from itemvalues where CleanValue = (select CleanName from TypedBaseItems where guid=" + paramName + ") and Type<=1))");
                     if (statement != null)
                     {
-                        statement.TryBind(paramName, artistId.ToGuidBlob());
+                        statement.TryBind(paramName, artistId.ToByteArray());
                     }
                     index++;
                 }
@@ -3998,7 +3998,7 @@ namespace Emby.Server.Implementations.Data
                     clauses.Add("(guid in (select itemid from itemvalues where CleanValue = (select CleanName from TypedBaseItems where guid=" + paramName + ") and Type=1))");
                     if (statement != null)
                     {
-                        statement.TryBind(paramName, artistId.ToGuidBlob());
+                        statement.TryBind(paramName, artistId.ToByteArray());
                     }
                     index++;
                 }
@@ -4017,7 +4017,7 @@ namespace Emby.Server.Implementations.Data
                     clauses.Add("((select CleanName from TypedBaseItems where guid=" + paramName + ") in (select CleanValue from itemvalues where ItemId=Guid and Type=0) AND (select CleanName from TypedBaseItems where guid=" + paramName + ") not in (select CleanValue from itemvalues where ItemId=Guid and Type=1))");
                     if (statement != null)
                     {
-                        statement.TryBind(paramName, artistId.ToGuidBlob());
+                        statement.TryBind(paramName, artistId.ToByteArray());
                     }
                     index++;
                 }
@@ -4036,7 +4036,7 @@ namespace Emby.Server.Implementations.Data
                     clauses.Add("Album in (select Name from typedbaseitems where guid=" + paramName + ")");
                     if (statement != null)
                     {
-                        statement.TryBind(paramName, albumId.ToGuidBlob());
+                        statement.TryBind(paramName, albumId.ToByteArray());
                     }
                     index++;
                 }
@@ -4055,7 +4055,7 @@ namespace Emby.Server.Implementations.Data
                     clauses.Add("(guid not in (select itemid from itemvalues where CleanValue = (select CleanName from TypedBaseItems where guid=" + paramName + ") and Type<=1))");
                     if (statement != null)
                     {
-                        statement.TryBind(paramName, artistId.ToGuidBlob());
+                        statement.TryBind(paramName, artistId.ToByteArray());
                     }
                     index++;
                 }
@@ -4074,7 +4074,7 @@ namespace Emby.Server.Implementations.Data
                     clauses.Add("(guid in (select itemid from itemvalues where CleanValue = (select CleanName from TypedBaseItems where guid=" + paramName + ") and Type=2))");
                     if (statement != null)
                     {
-                        statement.TryBind(paramName, genreId.ToGuidBlob());
+                        statement.TryBind(paramName, genreId.ToByteArray());
                     }
                     index++;
                 }
@@ -4145,7 +4145,7 @@ namespace Emby.Server.Implementations.Data
 
                     if (statement != null)
                     {
-                        statement.TryBind(paramName, studioId.ToGuidBlob());
+                        statement.TryBind(paramName, studioId.ToByteArray());
                     }
                     index++;
                 }
@@ -4921,7 +4921,7 @@ where AncestorIdText not null and ItemValues.Value not null and ItemValues.Type
             {
                 connection.RunInTransaction(db =>
                 {
-                    var idBlob = id.ToGuidBlob();
+                    var idBlob = id.ToByteArray();
 
                     // Delete people
                     ExecuteWithSingleParam(db, "delete from People where ItemId=@Id", idBlob);
@@ -5040,7 +5040,7 @@ where AncestorIdText not null and ItemValues.Value not null and ItemValues.Type
                 whereClauses.Add("ItemId=@ItemId");
                 if (statement != null)
                 {
-                    statement.TryBind("@ItemId", query.ItemId.ToGuidBlob());
+                    statement.TryBind("@ItemId", query.ItemId.ToByteArray());
                 }
             }
             if (!query.AppearsInItemId.Equals(Guid.Empty))
@@ -5048,7 +5048,7 @@ where AncestorIdText not null and ItemValues.Value not null and ItemValues.Type
                 whereClauses.Add("Name in (Select Name from People where ItemId=@AppearsInItemId)");
                 if (statement != null)
                 {
-                    statement.TryBind("@AppearsInItemId", query.AppearsInItemId.ToGuidBlob());
+                    statement.TryBind("@AppearsInItemId", query.AppearsInItemId.ToByteArray());
                 }
             }
             var queryPersonTypes = query.PersonTypes.Where(IsValidPersonType).ToList();
@@ -5117,7 +5117,7 @@ where AncestorIdText not null and ItemValues.Value not null and ItemValues.Type
 
             CheckDisposed();
 
-            var itemIdBlob = itemId.ToGuidBlob();
+            var itemIdBlob = itemId.ToByteArray();
 
             // First delete
             deleteAncestorsStatement.Reset();
@@ -5151,7 +5151,7 @@ where AncestorIdText not null and ItemValues.Value not null and ItemValues.Type
 
                     var ancestorId = ancestorIds[i];
 
-                    statement.TryBind("@AncestorId" + index, ancestorId.ToGuidBlob());
+                    statement.TryBind("@AncestorId" + index, ancestorId.ToByteArray());
                     statement.TryBind("@AncestorIdText" + index, ancestorId.ToString("N", CultureInfo.InvariantCulture));
                 }
 
@@ -5616,7 +5616,7 @@ where AncestorIdText not null and ItemValues.Value not null and ItemValues.Type
 
             CheckDisposed();
 
-            var guidBlob = itemId.ToGuidBlob();
+            var guidBlob = itemId.ToByteArray();
 
             // First delete
             db.Execute("delete from ItemValues where ItemId=@Id", guidBlob);
@@ -5640,10 +5640,13 @@ where AncestorIdText not null and ItemValues.Value not null and ItemValues.Type
                 {
                     if (isSubsequentRow)
                     {
-                        insertText.Append(",");
+                        insertText.Append(',');
                     }
 
-                    insertText.AppendFormat("(@ItemId, @Type{0}, @Value{0}, @CleanValue{0})", i.ToString(CultureInfo.InvariantCulture));
+                    insertText.AppendFormat(
+                        CultureInfo.InvariantCulture,
+                        "(@ItemId, @Type{0}, @Value{0}, @CleanValue{0})",
+                        i);
                     isSubsequentRow = true;
                 }
 
@@ -5696,7 +5699,7 @@ where AncestorIdText not null and ItemValues.Value not null and ItemValues.Type
             {
                 connection.RunInTransaction(db =>
                 {
-                    var itemIdBlob = itemId.ToGuidBlob();
+                    var itemIdBlob = itemId.ToByteArray();
 
                     // First delete chapters
                     db.Execute("delete from People where ItemId=@ItemId", itemIdBlob);
@@ -5815,7 +5818,7 @@ where AncestorIdText not null and ItemValues.Value not null and ItemValues.Type
 
                 using (var statement = PrepareStatement(connection, cmdText))
                 {
-                    statement.TryBind("@ItemId", query.ItemId.ToGuidBlob());
+                    statement.TryBind("@ItemId", query.ItemId.ToByteArray());
 
                     if (query.Type.HasValue)
                     {
@@ -5857,7 +5860,7 @@ where AncestorIdText not null and ItemValues.Value not null and ItemValues.Type
             {
                 connection.RunInTransaction(db =>
                 {
-                    var itemIdBlob = id.ToGuidBlob();
+                    var itemIdBlob = id.ToByteArray();
 
                     // First delete chapters
                     db.Execute("delete from mediastreams where ItemId=@ItemId", itemIdBlob);

+ 5 - 10
Emby.Server.Implementations/Data/SqliteUserDataRepository.cs

@@ -1,7 +1,6 @@
 using System;
 using System.Collections.Generic;
 using System.IO;
-using System.Linq;
 using System.Threading;
 using MediaBrowser.Common.Configuration;
 using MediaBrowser.Controller.Entities;
@@ -15,23 +14,19 @@ namespace Emby.Server.Implementations.Data
     public class SqliteUserDataRepository : BaseSqliteRepository, IUserDataRepository
     {
         public SqliteUserDataRepository(
-            ILoggerFactory loggerFactory,
+            ILogger<SqliteUserDataRepository> logger,
             IApplicationPaths appPaths)
-            : base(loggerFactory.CreateLogger(nameof(SqliteUserDataRepository)))
+            : base(logger)
         {
             DbFilePath = Path.Combine(appPaths.DataPath, "library.db");
         }
 
-        /// <summary>
-        /// Gets the name of the repository
-        /// </summary>
-        /// <value>The name.</value>
+        /// <inheritdoc />
         public string Name => "SQLite";
 
         /// <summary>
-        /// Opens the connection to the database
+        /// Opens the connection to the database.
         /// </summary>
-        /// <returns>Task.</returns>
         public void Initialize(IUserManager userManager, SemaphoreSlim dbLock, SQLiteDatabaseConnection dbConnection)
         {
             WriteLock.Dispose();
@@ -97,7 +92,7 @@ namespace Emby.Server.Implementations.Data
                         continue;
                     }
 
-                    statement.TryBind("@UserId", user.Id.ToGuidBlob());
+                    statement.TryBind("@UserId", user.Id.ToByteArray());
                     statement.TryBind("@InternalUserId", user.InternalId);
 
                     statement.MoveNext();

+ 1 - 1
Emby.Server.Implementations/Data/SqliteUserRepository.cs

@@ -116,7 +116,7 @@ namespace Emby.Server.Implementations.Data
                 {
                     using (var statement = db.PrepareStatement("insert into LocalUsersv2 (guid, data) values (@guid, @data)"))
                     {
-                        statement.TryBind("@guid", user.Id.ToGuidBlob());
+                        statement.TryBind("@guid", user.Id.ToByteArray());
                         statement.TryBind("@data", serialized);
 
                         statement.MoveNext();

+ 0 - 1
Emby.Server.Implementations/Library/InvalidAuthProvider.cs

@@ -1,7 +1,6 @@
 using System.Threading.Tasks;
 using MediaBrowser.Controller.Authentication;
 using MediaBrowser.Controller.Entities;
-using MediaBrowser.Controller.Net;
 
 namespace Emby.Server.Implementations.Library
 {

+ 5 - 31
Emby.Server.Implementations/Serialization/XmlSerializer.cs → Emby.Server.Implementations/Serialization/MyXmlSerializer.cs

@@ -1,11 +1,9 @@
 using System;
-using System.Collections.Generic;
+using System.Collections.Concurrent;
 using System.IO;
 using System.Xml;
 using System.Xml.Serialization;
-using MediaBrowser.Model.IO;
 using MediaBrowser.Model.Serialization;
-using Microsoft.Extensions.Logging;
 
 namespace Emby.Server.Implementations.Serialization
 {
@@ -14,35 +12,13 @@ namespace Emby.Server.Implementations.Serialization
     /// </summary>
     public class MyXmlSerializer : IXmlSerializer
     {
-        private readonly IFileSystem _fileSystem;
-        private readonly ILogger _logger;
-
-        public MyXmlSerializer(
-            IFileSystem fileSystem,
-            ILoggerFactory loggerFactory)
-        {
-            _fileSystem = fileSystem;
-            _logger = loggerFactory.CreateLogger("XmlSerializer");
-        }
-
         // Need to cache these
         // http://dotnetcodebox.blogspot.com/2013/01/xmlserializer-class-may-result-in.html
-        private readonly Dictionary<string, XmlSerializer> _serializers =
-            new Dictionary<string, XmlSerializer>();
+        private static readonly ConcurrentDictionary<string, XmlSerializer> _serializers =
+            new ConcurrentDictionary<string, XmlSerializer>();
 
-        private XmlSerializer GetSerializer(Type type)
-        {
-            var key = type.FullName;
-            lock (_serializers)
-            {
-                if (!_serializers.TryGetValue(key, out var serializer))
-                {
-                    serializer = new XmlSerializer(type);
-                    _serializers[key] = serializer;
-                }
-                return serializer;
-            }
-        }
+        private static XmlSerializer GetSerializer(Type type)
+            => _serializers.GetOrAdd(type.FullName, _ => new XmlSerializer(type));
 
         /// <summary>
         /// Serializes to writer.
@@ -91,7 +67,6 @@ namespace Emby.Server.Implementations.Serialization
         /// <param name="file">The file.</param>
         public void SerializeToFile(object obj, string file)
         {
-            _logger.LogDebug("Serializing to file {0}", file);
             using (var stream = new FileStream(file, FileMode.Create))
             {
                 SerializeToStream(obj, stream);
@@ -106,7 +81,6 @@ namespace Emby.Server.Implementations.Serialization
         /// <returns>System.Object.</returns>
         public object DeserializeFromFile(Type type, string file)
         {
-            _logger.LogDebug("Deserializing file {0}", file);
             using (var stream = File.OpenRead(file))
             {
                 return DeserializeFromStream(type, stream);

+ 11 - 13
MediaBrowser.Common/Cryptography/PasswordHash.cs

@@ -124,10 +124,10 @@ namespace MediaBrowser.Common.Cryptography
             stringBuilder.Append('$');
             foreach (var pair in _parameters)
             {
-                stringBuilder.Append(pair.Key);
-                stringBuilder.Append('=');
-                stringBuilder.Append(pair.Value);
-                stringBuilder.Append(',');
+                stringBuilder.Append(pair.Key)
+                    .Append('=')
+                    .Append(pair.Value)
+                    .Append(',');
             }
 
             // Remove last ','
@@ -137,21 +137,19 @@ namespace MediaBrowser.Common.Cryptography
         /// <inheritdoc />
         public override string ToString()
         {
-            var str = new StringBuilder();
-            str.Append('$');
-            str.Append(Id);
+            var str = new StringBuilder()
+                .Append('$')
+                .Append(Id);
             SerializeParameters(str);
 
             if (Salt.Length != 0)
             {
-                str.Append('$');
-                str.Append(ToHexString(Salt));
+                str.Append('$')
+                    .Append(ToHexString(Salt));
             }
 
-            str.Append('$');
-            str.Append(ToHexString(Hash));
-
-            return str.ToString();
+            return str.Append('$')
+                .Append(ToHexString(Hash)).ToString();
         }
     }
 }