public async Task <string> WriteFileAsync(string path, string fileName, Stream messageStream, bool overwriteIfExists = false, bool createDirectory = false)
        {
            var tempFileName        = $".{Guid.NewGuid()}.tmp";
            var destinationFilePath = Path.Combine(path, FileNameHelper.PopulateFileNameMacros(fileName)).Replace('\\', '/');
            var tempFilePath        = Path.Combine(path, tempFileName).Replace('\\', '/');

            path = path.Replace('\\', '/');

            using (var sftpClient = new Sftp())
            {
                sftpClient.TransferType = _transferType;

                // Connect & authenticate:
                await sftpClient.ConnectAsync(_serverAddress, _port);

                await sftpClient.LoginAsync(_userName, _password);

                // If the directory does not exist, create it if allowed:
                if (!await sftpClient.DirectoryExistsAsync(path))
                {
                    if (createDirectory)
                    {
                        // Examine the path step by step and create directories:
                        StringBuilder directory = null;
                        foreach (var directoryPart in path.Split('/'))
                        {
                            // First directory should not be preceded by '/':
                            if (directory == null)
                            {
                                directory = new StringBuilder();
                                directory.Append(directoryPart);
                            }
                            else
                            {
                                directory.AppendFormat("/{0}", directoryPart);
                            }

                            // If this directory does not exist, create it and move to the next part:
                            var dirString = directory.ToString();
                            if (!string.IsNullOrWhiteSpace(dirString) && !await sftpClient.DirectoryExistsAsync(dirString))
                            {
                                await sftpClient.CreateDirectoryAsync(dirString);
                            }
                        }
                    }
                    else
                    {
                        throw new Exception($"Directory '{path}' was not found.");
                    }
                }

                // Overwrite existing files if allowed:
                if (await sftpClient.FileExistsAsync(destinationFilePath))
                {
                    if (overwriteIfExists)
                    {
                        await sftpClient.DeleteFileAsync(destinationFilePath);
                    }
                    else
                    {
                        throw new Exception($"File '{destinationFilePath}' already exists.");
                    }
                }

                // Upload the file with a temporary file name:
                await sftpClient.PutFileAsync(messageStream, tempFilePath);

                await sftpClient.RenameAsync(tempFilePath, destinationFilePath);

                await sftpClient.DisconnectAsync();
            }

            return(tempFileName);
        }
        public async Task <string> AddAsync <T>(T obj, string fileName)
        {
            // TODO: Implement retry

            var blobName = FileNameHelper.PopulateFileNameMacros(!string.IsNullOrWhiteSpace(fileName) ? fileName : FileNameFormat);

            try
            {
                var container = _blobClient.GetContainerReference(_path);
                await container.CreateIfNotExistsAsync();

                var blob = container.GetBlockBlobReference(blobName);

                var message = obj as Message;
                if (message != null)
                {
                    // Save the message contents:
                    if (message.ContentStream != null)
                    {
                        var position = message.ContentStream.Position;

                        message.ContentStream.Position = 0;
                        await blob.UploadFromStreamAsync(message.ContentStream);

                        // Restore the position:
                        message.ContentStream.Position = position;
                    }
                    else
                    {
                        await blob.UploadTextAsync(string.Empty);
                    }

                    // Save the properties as blob metadata:
                    if (message.Metadata?.Any() ?? false)
                    {
                        foreach (var property in message.Metadata)
                        {
                            blob.Metadata[property.Key] = property.Value;
                        }
                        await blob.SetMetadataAsync();
                    }
                }
                else
                {
                    // Serialize the object to the blob stream:
                    using (var stream = await blob.OpenWriteAsync())
                    {
                        var serializer = new XmlSerializer(typeof(T));
                        serializer.Serialize(stream, obj);
                    }

                    // Save the type:
                    blob.Metadata["Type"] = typeof(T).ToString();
                    await blob.SetMetadataAsync();
                }
            }
            catch (Exception ex)
            {
                _log.Error($"Adding object to the message log store failed (path '{_path}', filename '{blobName}')", ex);
            }

            return(blobName);
        }