diff --git a/src/DotVVM.Framework/Storage/FileSize.cs b/src/DotVVM.Core/Storage/FileSize.cs similarity index 78% rename from src/DotVVM.Framework/Storage/FileSize.cs rename to src/DotVVM.Core/Storage/FileSize.cs index 33eb6f0d95..8f545e1a57 100644 --- a/src/DotVVM.Framework/Storage/FileSize.cs +++ b/src/DotVVM.Core/Storage/FileSize.cs @@ -1,6 +1,6 @@ -using DotVVM.Framework.Utils; +using DotVVM.Core.Utils; -namespace DotVVM.Framework.Storage +namespace DotVVM.Core.Storage { public class FileSize { @@ -13,4 +13,4 @@ public override string ToString() return FormattedText; } } -} \ No newline at end of file +} diff --git a/src/DotVVM.Framework/Storage/IReturnedFileStorage.cs b/src/DotVVM.Core/Storage/IReturnedFileStorage.cs similarity index 51% rename from src/DotVVM.Framework/Storage/IReturnedFileStorage.cs rename to src/DotVVM.Core/Storage/IReturnedFileStorage.cs index 8936d63aff..aab2d168e4 100644 --- a/src/DotVVM.Framework/Storage/IReturnedFileStorage.cs +++ b/src/DotVVM.Core/Storage/IReturnedFileStorage.cs @@ -2,28 +2,24 @@ using System.IO; using System.Threading.Tasks; -namespace DotVVM.Framework.Storage +namespace DotVVM.Core.Storage { public interface IReturnedFileStorage { /// /// Stores the file and returns its unique ID. /// - Task StoreFile(Stream stream, ReturnedFileMetadata metadata); + Task StoreFileAsync(Stream stream, ReturnedFileMetadata metadata); /// /// Gets the file from the storage. /// - Stream GetFile(Guid fileId, out ReturnedFileMetadata metadata); + Task GetFileAsync(Guid fileId); /// /// Deletes the file with the specified ID. /// - void DeleteFile(Guid fileId); + Task DeleteFileAsync(Guid fileId); - /// - /// Deletes all files older than the specified date. - /// - void DeleteOldFiles(DateTime maxCreatedDate); } -} \ No newline at end of file +} diff --git a/src/DotVVM.Core/Storage/IUploadedFileStorage.cs b/src/DotVVM.Core/Storage/IUploadedFileStorage.cs new file mode 100644 index 0000000000..8c4e4b83f7 --- /dev/null +++ b/src/DotVVM.Core/Storage/IUploadedFileStorage.cs @@ -0,0 +1,25 @@ +using System; +using System.IO; +using System.Threading.Tasks; + +namespace DotVVM.Core.Storage +{ + public interface IUploadedFileStorage + { + /// + /// Stores uploaded file and returns its unique ID. + /// + Task StoreFileAsync(Stream stream); + + /// + /// Deletes the uploaded file with the specified ID. + /// + Task DeleteFileAsync(Guid fileId); + + /// + /// Gets the stream of the file with the specified ID. + /// + Task GetFileAsync(Guid fileId); + + } +} diff --git a/src/DotVVM.Core/Storage/ReturnedFile.cs b/src/DotVVM.Core/Storage/ReturnedFile.cs new file mode 100644 index 0000000000..f3e509f5e3 --- /dev/null +++ b/src/DotVVM.Core/Storage/ReturnedFile.cs @@ -0,0 +1,23 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace DotVVM.Core.Storage +{ + public class ReturnedFile + { + + public Stream Stream { get; } + public ReturnedFileMetadata Metadata { get; } + + public ReturnedFile(Stream stream, ReturnedFileMetadata metadata) + { + Stream = stream; + Metadata = metadata; + } + + } +} diff --git a/src/DotVVM.Core/Storage/ReturnedFileMetadata.cs b/src/DotVVM.Core/Storage/ReturnedFileMetadata.cs new file mode 100644 index 0000000000..70a7788c77 --- /dev/null +++ b/src/DotVVM.Core/Storage/ReturnedFileMetadata.cs @@ -0,0 +1,12 @@ +using System.Collections.Generic; + +namespace DotVVM.Core.Storage +{ + public class ReturnedFileMetadata + { + public string? FileName { get; set; } + public string? MimeType { get; set; } + public Dictionary AdditionalHeaders { get; set; } = new Dictionary(); + public string? AttachmentDispositionType { get; set; } + } +} diff --git a/src/DotVVM.Framework/Storage/UploadedFile.cs b/src/DotVVM.Core/Storage/UploadedFile.cs similarity index 82% rename from src/DotVVM.Framework/Storage/UploadedFile.cs rename to src/DotVVM.Core/Storage/UploadedFile.cs index d958382143..962dfc4e40 100644 --- a/src/DotVVM.Framework/Storage/UploadedFile.cs +++ b/src/DotVVM.Core/Storage/UploadedFile.cs @@ -1,12 +1,12 @@ using System; -namespace DotVVM.Framework.Storage +namespace DotVVM.Core.Storage { public class UploadedFile { public Guid FileId { get; set; } - public string FileName { get; set; } + public string? FileName { get; set; } public FileSize FileSize { get; set; } = new FileSize(); @@ -17,4 +17,4 @@ public class UploadedFile public bool IsAllowed => IsFileTypeAllowed && !IsMaxSizeExceeded; } -} \ No newline at end of file +} diff --git a/src/DotVVM.Framework/Storage/UploadedFileStorageExtensions.cs b/src/DotVVM.Core/Storage/UploadedFileStorageExtensions.cs similarity index 58% rename from src/DotVVM.Framework/Storage/UploadedFileStorageExtensions.cs rename to src/DotVVM.Core/Storage/UploadedFileStorageExtensions.cs index edbe1cba13..e4ebaf41eb 100644 --- a/src/DotVVM.Framework/Storage/UploadedFileStorageExtensions.cs +++ b/src/DotVVM.Core/Storage/UploadedFileStorageExtensions.cs @@ -1,22 +1,23 @@ using System; using System.IO; +using System.Threading.Tasks; -namespace DotVVM.Framework.Storage +namespace DotVVM.Core.Storage { public static class UploadedFileStorageExtensions { /// /// Saves an uploaded file with the specified ID to the given location. /// - public static void SaveAs(this IUploadedFileStorage storage, Guid fileId, string path) + public static async Task SaveAsAsync(this IUploadedFileStorage storage, Guid fileId, string path) { - using (var stream = storage.GetFile(fileId)) + using (var stream = await storage.GetFileAsync(fileId)) { using (var fs = new FileStream(path, FileMode.OpenOrCreate, FileAccess.Write)) { - stream.CopyTo(fs); + await stream.CopyToAsync(fs); } } } } -} \ No newline at end of file +} diff --git a/src/DotVVM.Framework/Utils/TextUtils.cs b/src/DotVVM.Core/Utils/TextUtils.cs similarity index 93% rename from src/DotVVM.Framework/Utils/TextUtils.cs rename to src/DotVVM.Core/Utils/TextUtils.cs index f54b1fe77e..ad461b8091 100644 --- a/src/DotVVM.Framework/Utils/TextUtils.cs +++ b/src/DotVVM.Core/Utils/TextUtils.cs @@ -1,5 +1,7 @@ #nullable enable -namespace DotVVM.Framework.Utils +using DotVVM; + +namespace DotVVM.Core.Utils { public static class TextUtils { diff --git a/src/DotVVM.Framework/Controls/UploadedFilesCollection.cs b/src/DotVVM.Framework/Controls/UploadedFilesCollection.cs index 3509ac2ce3..dbac76afb0 100644 --- a/src/DotVVM.Framework/Controls/UploadedFilesCollection.cs +++ b/src/DotVVM.Framework/Controls/UploadedFilesCollection.cs @@ -1,6 +1,6 @@ #nullable enable using System.Collections.Generic; -using DotVVM.Framework.Storage; +using DotVVM.Core.Storage; namespace DotVVM.Framework.Controls { diff --git a/src/DotVVM.Framework/DependencyInjection/DotvvmBuilderExtensions.cs b/src/DotVVM.Framework/DependencyInjection/DotvvmBuilderExtensions.cs index 5771ee660b..0fb2b743d2 100644 --- a/src/DotVVM.Framework/DependencyInjection/DotvvmBuilderExtensions.cs +++ b/src/DotVVM.Framework/DependencyInjection/DotvvmBuilderExtensions.cs @@ -1,6 +1,7 @@ #nullable enable using System; using System.IO; +using DotVVM.Core.Storage; using DotVVM.Framework.Configuration; using DotVVM.Framework.Diagnostics; using DotVVM.Framework.Runtime; diff --git a/src/DotVVM.Framework/Hosting/DotvvmRequestContextExtensions.cs b/src/DotVVM.Framework/Hosting/DotvvmRequestContextExtensions.cs index ba2f899f6d..68f622e540 100644 --- a/src/DotVVM.Framework/Hosting/DotvvmRequestContextExtensions.cs +++ b/src/DotVVM.Framework/Hosting/DotvvmRequestContextExtensions.cs @@ -17,6 +17,7 @@ using System.Threading.Tasks; using DotVVM.Framework.Routing; using DotVVM.Framework.Hosting; +using DotVVM.Core.Storage; public static class DotvvmRequestContextExtensions { @@ -232,7 +233,7 @@ public static void ReturnFile(this IDotvvmRequestContext context, Stream stream, AttachmentDispositionType = attachmentDispositionType ?? "attachment" }; - var generatedFileId = returnedFileStorage.StoreFile(stream, metadata).Result; + var generatedFileId = returnedFileStorage.StoreFileAsync(stream, metadata).Result; context.SetRedirectResponse(context.TranslateVirtualPath("~/dotvvmReturnedFile?id=" + generatedFileId)); throw new DotvvmInterruptRequestExecutionException(InterruptReason.ReturnFile, fileName); } diff --git a/src/DotVVM.Framework/Hosting/Middlewares/DotvvmFileUploadMiddleware.cs b/src/DotVVM.Framework/Hosting/Middlewares/DotvvmFileUploadMiddleware.cs index 8d9f654ba6..8091f18be8 100644 --- a/src/DotVVM.Framework/Hosting/Middlewares/DotvvmFileUploadMiddleware.cs +++ b/src/DotVVM.Framework/Hosting/Middlewares/DotvvmFileUploadMiddleware.cs @@ -6,10 +6,10 @@ using System.Net; using System.Text.RegularExpressions; using System.Threading.Tasks; +using DotVVM.Core.Storage; using DotVVM.Framework.Configuration; using DotVVM.Framework.Controls; using DotVVM.Framework.Runtime; -using DotVVM.Framework.Storage; using DotVVM.Framework.ViewModel.Serialization; using Microsoft.AspNet.WebUtilities; using Microsoft.Extensions.DependencyInjection; @@ -176,7 +176,7 @@ private async Task SaveFiles(IHttpContext context, Group boundary, List private async Task StoreFile(IHttpContext context, MultipartSection section, IUploadedFileStorage fileStore) { - var fileId = await fileStore.StoreFile(section.Body); + var fileId = await fileStore.StoreFileAsync(section.Body); var fileNameGroup = Regex.Match(section.ContentDisposition, @"filename=""?(?[^\""]*)", RegexOptions.IgnoreCase).Groups["fileName"]; var fileName = fileNameGroup.Success ? fileNameGroup.Value : string.Empty; var mimeType = section.ContentType ?? string.Empty; diff --git a/src/DotVVM.Framework/Hosting/Middlewares/DotvvmReturnedFileMiddleware.cs b/src/DotVVM.Framework/Hosting/Middlewares/DotvvmReturnedFileMiddleware.cs index 4495a4c08a..b3c8c5c069 100644 --- a/src/DotVVM.Framework/Hosting/Middlewares/DotvvmReturnedFileMiddleware.cs +++ b/src/DotVVM.Framework/Hosting/Middlewares/DotvvmReturnedFileMiddleware.cs @@ -3,9 +3,9 @@ using System.Linq; using System.Net; using System.Threading.Tasks; -using DotVVM.Framework.Storage; using System.Collections.Generic; using Microsoft.Extensions.DependencyInjection; +using DotVVM.Core.Storage; #if DotNetCore using Microsoft.Net.Http.Headers; #else @@ -30,27 +30,27 @@ public async Task Handle(IDotvvmRequestContext request) private async Task RenderReturnedFile(IHttpContext context, IReturnedFileStorage returnedFileStorage) { - ReturnedFileMetadata metadata; - var id = Guid.Parse(context.Request.Query["id"]); - using (var stream = returnedFileStorage.GetFile(id, out metadata)) + + var returnedFile = await returnedFileStorage.GetFileAsync(id); + using (var stream = returnedFile.Stream) { #if DotNetCore - var contentDispositionValue = new ContentDispositionHeaderValue(metadata.AttachmentDispositionType); - contentDispositionValue.SetHttpFileName(metadata.FileName); + var contentDispositionValue = new ContentDispositionHeaderValue(returnedFile.Metadata.AttachmentDispositionType); + contentDispositionValue.SetHttpFileName(returnedFile.Metadata.FileName); context.Response.Headers[HeaderNames.ContentDisposition] = contentDispositionValue.ToString(); #else - var contentDispositionValue = new ContentDispositionHeaderValue(metadata.AttachmentDispositionType) + var contentDispositionValue = new ContentDispositionHeaderValue(returnedFile.Metadata.AttachmentDispositionType) { - FileName = metadata.FileName, - FileNameStar = metadata.FileName + FileName = returnedFile.Metadata.FileName, + FileNameStar = returnedFile.Metadata.FileName }; context.Response.Headers["Content-Disposition"] = contentDispositionValue.ToString(); #endif - context.Response.ContentType = metadata.MimeType; - if (metadata.AdditionalHeaders != null) + context.Response.ContentType = returnedFile.Metadata.MimeType; + if (returnedFile.Metadata.AdditionalHeaders != null) { - foreach (var header in metadata.AdditionalHeaders) + foreach (var header in returnedFile.Metadata.AdditionalHeaders) { context.Response.Headers.Add(new KeyValuePair(header.Key, header.Value)); } diff --git a/src/DotVVM.Framework/Storage/FileSystemReturnedFileStorage.cs b/src/DotVVM.Framework/Storage/FileSystemReturnedFileStorage.cs index 994295087c..4eaa81d2f7 100644 --- a/src/DotVVM.Framework/Storage/FileSystemReturnedFileStorage.cs +++ b/src/DotVVM.Framework/Storage/FileSystemReturnedFileStorage.cs @@ -7,6 +7,7 @@ using System.Text; using System.Threading; using System.Threading.Tasks; +using DotVVM.Core.Storage; using DotVVM.Framework.Configuration; using DotVVM.Framework.Utils; using Newtonsoft.Json; @@ -69,7 +70,7 @@ private Guid GenerateFileId() return SecureGuidGenerator.GenerateGuid(); } - public async Task StoreFile(Stream stream, ReturnedFileMetadata metadata) + public async Task StoreFileAsync(Stream stream, ReturnedFileMetadata metadata) { var id = GenerateFileId(); var dataFilePath = GetDataFilePath(id); @@ -99,16 +100,18 @@ private string GetMetadataFilePath(Guid id) return Path.Combine(TempDirectory, id + ".metadata"); } - public Stream GetFile(Guid id, out ReturnedFileMetadata metadata) + public Task GetFileAsync(Guid id) { var metadataJson = File.ReadAllText(GetMetadataFilePath(id), Encoding.UTF8); var settings = DefaultSerializerSettingsProvider.Instance.Settings; - metadata = JsonConvert.DeserializeObject(metadataJson, settings); - return new FileStream(GetDataFilePath(id), FileMode.Open); + var stream = new FileStream(GetDataFilePath(id), FileMode.Open); + var metadata = JsonConvert.DeserializeObject(metadataJson, settings); + + return Task.FromResult(new ReturnedFile(stream, metadata)); } - public void DeleteFile(Guid id) + public Task DeleteFileAsync(Guid id) { try { @@ -125,6 +128,8 @@ public void DeleteFile(Guid id) catch (IOException) { } + + return TaskUtils.GetCompletedTask(); } public void DeleteOldFiles(DateTime maxCreatedDate) diff --git a/src/DotVVM.Framework/Storage/FileSystemUploadedFileStorage.cs b/src/DotVVM.Framework/Storage/FileSystemUploadedFileStorage.cs index cedd80e4a0..5ed934153a 100644 --- a/src/DotVVM.Framework/Storage/FileSystemUploadedFileStorage.cs +++ b/src/DotVVM.Framework/Storage/FileSystemUploadedFileStorage.cs @@ -3,6 +3,7 @@ using System.Linq; using System.Threading; using System.Threading.Tasks; +using DotVVM.Core.Storage; using DotVVM.Framework.Utils; namespace DotVVM.Framework.Storage @@ -37,7 +38,7 @@ public FileSystemUploadedFileStorage(string tempDirectory, TimeSpan autoDeleteIn /// /// Stores uploaded file and returns its unique id. /// - public async Task StoreFile(Stream stream) + public async Task StoreFileAsync(Stream stream) { var id = SecureGuidGenerator.GenerateGuid(); using (var fs = new FileStream(GetFileName(id), FileMode.OpenOrCreate, FileAccess.Write)) @@ -50,7 +51,7 @@ public async Task StoreFile(Stream stream) /// /// Deletes the uploaded file. /// - public void DeleteFile(Guid fileId) + public Task DeleteFileAsync(Guid fileId) { try { @@ -59,14 +60,16 @@ public void DeleteFile(Guid fileId) catch (IOException) { } + return TaskUtils.GetCompletedTask(); } /// /// Gets the file with the specified id. /// - public Stream GetFile(Guid fileId) + public Task GetFileAsync(Guid fileId) { - return new FileStream(GetFileName(fileId), FileMode.Open, FileAccess.Read); + var stream = new FileStream(GetFileName(fileId), FileMode.Open, FileAccess.Read); + return Task.FromResult(stream); } /// @@ -107,4 +110,4 @@ public void Dispose() } } } -} \ No newline at end of file +} diff --git a/src/DotVVM.Framework/Storage/IUploadedFileStorage.cs b/src/DotVVM.Framework/Storage/IUploadedFileStorage.cs deleted file mode 100644 index 426cd7057c..0000000000 --- a/src/DotVVM.Framework/Storage/IUploadedFileStorage.cs +++ /dev/null @@ -1,29 +0,0 @@ -using System; -using System.IO; -using System.Threading.Tasks; - -namespace DotVVM.Framework.Storage -{ - public interface IUploadedFileStorage - { - /// - /// Stores uploaded file and returns its unique ID. - /// - Task StoreFile(Stream stream); - - /// - /// Deletes the uploaded file. - /// - void DeleteFile(Guid fileId); - - /// - /// Gets the file with the specified ID. - /// - Stream GetFile(Guid fileId); - - /// - /// Deletes files older than the specified date. - /// - void DeleteOldFiles(DateTime maxCreatedDate); - } -} \ No newline at end of file diff --git a/src/DotVVM.Framework/Storage/ReturnedFileMetadata.cs b/src/DotVVM.Framework/Storage/ReturnedFileMetadata.cs deleted file mode 100644 index 5285816a52..0000000000 --- a/src/DotVVM.Framework/Storage/ReturnedFileMetadata.cs +++ /dev/null @@ -1,13 +0,0 @@ -using System.Collections.Generic; -using Microsoft.Extensions.Primitives; - -namespace DotVVM.Framework.Storage -{ - public class ReturnedFileMetadata - { - public string FileName { get; set; } - public string MimeType { get; set; } - public Dictionary AdditionalHeaders { get; set; } - public string AttachmentDispositionType { get; set; } - } -} diff --git a/src/DotVVM.Samples.Common/ViewModels/ControlSamples/FileUpload/FileUploadViewModel.cs b/src/DotVVM.Samples.Common/ViewModels/ControlSamples/FileUpload/FileUploadViewModel.cs index f94def3289..b48c57b4c6 100644 --- a/src/DotVVM.Samples.Common/ViewModels/ControlSamples/FileUpload/FileUploadViewModel.cs +++ b/src/DotVVM.Samples.Common/ViewModels/ControlSamples/FileUpload/FileUploadViewModel.cs @@ -3,8 +3,8 @@ using System.IO; using System.Linq; using System.Threading.Tasks; +using DotVVM.Core.Storage; using DotVVM.Framework.Controls; -using DotVVM.Framework.Storage; using DotVVM.Framework.ViewModel; namespace DotVVM.Samples.BasicSamples.ViewModels.ControlSamples.FileUpload @@ -48,14 +48,14 @@ public void CheckFile() FileSize = file.FileSize; } - public void Process() + public async Task Process() { var uploadPath = GetUploadPath(); foreach (var file in Files.Files) { - fileStorage.SaveAs(file.FileId, Path.Combine(uploadPath, file.FileId + ".bin")); - fileStorage.DeleteFile(file.FileId); + await fileStorage.SaveAsAsync(file.FileId, Path.Combine(uploadPath, file.FileId + ".bin")); + await fileStorage.DeleteFileAsync(file.FileId); } Files.Clear(); }